{"id":13651586,"url":"https://github.com/mrasu/echoed","last_synced_at":"2025-04-12T03:31:25.702Z","repository":{"id":211910087,"uuid":"728035376","full_name":"mrasu/echoed","owner":"mrasu","description":"Observable Integration Testing using OpenTelemetry on top of Jest/Playwright/Cypress.","archived":false,"fork":false,"pushed_at":"2024-04-16T15:18:31.000Z","size":12563,"stargazers_count":12,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-04-21T17:21:22.192Z","etag":null,"topics":["api","api-testing","cypress","integration-testing","jest","opentelemetry","playwright","test","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mrasu.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-12-06T04:55:09.000Z","updated_at":"2024-04-27T04:27:25.789Z","dependencies_parsed_at":"2024-03-15T04:30:09.736Z","dependency_job_id":"4fc50584-6ec6-4a9f-b4a7-05459bdc58d5","html_url":"https://github.com/mrasu/echoed","commit_stats":null,"previous_names":["mrasu/tobikura"],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrasu%2Fechoed","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrasu%2Fechoed/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrasu%2Fechoed/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrasu%2Fechoed/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mrasu","download_url":"https://codeload.github.com/mrasu/echoed/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248512621,"owners_count":21116645,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","api-testing","cypress","integration-testing","jest","opentelemetry","playwright","test","typescript"],"created_at":"2024-08-02T02:00:50.709Z","updated_at":"2025-04-12T03:31:25.694Z","avatar_url":"https://github.com/mrasu.png","language":"TypeScript","readme":"\u003cdiv align=\"center\"\u003e\n\n\u003cimg src=\"https://github.com/mrasu/echoed/raw/main/docs/img/logo.svg\" alt=\"echoed logo\" height=\"300\"/\u003e\n\n# Echoed\n\n#### Observable Integration Testing using OpenTelemetry on top of Jest/Playwright/Cypress.\n\n\u003c/div\u003e\n\n# Table of Contents\n\n* [Features](#Features)\n* [How Echoed Works](#How-Echoed-Works)\n* [Screenshots](#Screenshots)\n* [Installation](#Installation)\n* [How to Use](#How-to-Use)\n  * [Jest](#Jest)\n  * [Playwright](#Playwright)\n  * [Cypress](#Cypress)\n  * [Analyze Coverage](#Analyze-Coverage)\n* [Using Echoed without OpenTelemetry](#Using-Echoed-without-OpenTelemetry)\n* [Configuration](#Configuration)\n\n# Features\nEchoed enhances Integration testing, aka API testing with the following features:\n\n* **Effortless Test Troubleshooting**: Quickly identify issues in failed tests by visualizing OpenTelemetry's traces and logs.\n* **YAML Supported**: Write tests effortlessly using YAML and easily expand functionality through your plugins.\n* **Coverage Analysis**: Gain insights into the coverage of your API endpoints based on OpenAPI or Protocol Buffers specifications.\n* **Detect Propagation Leaks**: Uncover spans that don't propagate OpenTelemetry's context to their children.\n* **Validate Spans**: Validate span's fields, such as SQL or requests going outside.\n* **CI-Friendly**: Integrates with CI without relying on external services.\n* **IDE Debugging**: Debug your tests in your preferred IDE, leveraging TypeScript/JavaScript's built-in debugging capabilities.\n* **Code Compatibility**: No need to modify your existing tests.\n* **Parallel Execution**: Boost by executing tests in parallel.\n\n# How Echoed Works\n\nEchoed starts a local server to gather data through OpenTelemetry when test is started.  \nThroughout the testing process, Echoed captures OpenTelemetry's traces and logs.  \nOnce tests finish, Echoed generates an HTML report for the test.\n\n![How Echoed Works](https://github.com/mrasu/echoed/raw/main/docs/img/howEchoedWorks.png)\n\n# Screenshots\n\nEchoed generates HTML that visualizes OpenTelemetry traces for each request in tests.  \nExplore the screenshots below to see how it looks:\n\n* Trace and logs of the Test  \n    ![Screenshot of Echoed's log detail](https://github.com/mrasu/echoed/raw/main/docs/img/readmeTraceDetailTrace.png)\n    ![Screenshot of Echoed's log detail](https://github.com/mrasu/echoed/raw/main/docs/img/readmeTraceDetailLog.png)\n* Coverage per service  \n    ![Screenshot of Echoed's coverage](https://github.com/mrasu/echoed/raw/main/docs/img/readmeCoverage.png)\n\n# Installation\n\nEchoed offers several installation methods depending on your needs:\n\n## Option 1. Create From Template (Jest)\n\n1. Initialize a new directory using our template:\n    ```bash\n    mkdir my_test_directory \u0026\u0026 cd my_test_directory\n    npm create echoed@latest\n    ```\n2. Install dependencies:\n    ```bash\n    npm install\n    ```\n3. Start server in the `example` directory:\n    ```bash\n    cd example\n    make start\n    ```\n4. Run test from project root directory after compiling YAML tests:\n    ```bash\n    cd ../\n    npm run compile \u0026\u0026 npm run test\n    ```\n5. After test, you can view the HTML report in `report/result.html` (specified in `.echoed.yml`):\n    ```bash\n    open report/result.html\n    ```\n\n## Other Options\n\nRefer to the following documents for other installation methods:\n* [Jest](./docs/installation.md#jest)\n* [Playwright](./docs/installation.md#playwright)\n* [Cypress](./docs/installation.md#cypress)\n\n# How to Use\n\n## Jest\n\n### YAML\n\nYou can write tests using YAML, and Echoed will convert them into Jest tests.  \n![Compilation flow](https://github.com/mrasu/echoed/raw/main/docs/img/scenarioYamlCompile.jpg)\n\nThe YAML below makes a request to `http://localhost:8080/api/cart` and validates the response.\n\n```yaml\nvariable:\n  productId: OLJCESPC7Z\nscenarios:\n  - name: Get product detail\n    steps:\n      - description: fetch /products/{id}\n        act:\n          runner: fetch\n          argument:\n            endpoint: /products/${productId}\n        assert:\n          - expect(_.jsonBody.id).toBe(productId)\n```\n\nFor more details, refer to the [documentation](./docs/yamlJestScenario.md) or [examples](create-echoed/template/jest/example/scenario).  \n\n### Make Tests Observable\n\nYou can write Jest tests in TypeScript too.\n\nTo generate an HTML report visualizing API traces, no additional code is needed.  \nSimply write your Jest tests as usual.\n\n```ts\ndescribe(\"Awesome test\", () =\u003e {\n  it(\"should pass\", async () =\u003e {\n    const response = await fetch(`http://localhost:8080/api/cart`);\n    expect(response.status).toBe(200);\n\n    const body = await response.json();\n    expect(body.items.length).toBe(0);\n  });\n});\n```\nThe code above produces an HTML report illustrating a trace for the requested endpoint (`http://localhost:8080/api/cart`).\n\n### Test OpenTelemetry's Spans\n\nIn addition to the HTML output, Echoed offers a method for testing OpenTelemetry spans.  \nUse the `waitForSpan` function to obtain a span that matches your needs.\n\n```ts\ndescribe(\"Awesome test\", () =\u003e {\n  it(\"should create an OpenTelemetry gRPC span\", async () =\u003e {\n    const response = await fetch(`http://localhost:8080/api/products`);\n    expect(response.status).toBe(200);\n\n    const span = await waitForSpan(response, {\n      name: \"oteldemo.ProductCatalogService/ListProducts\",\n    });\n    \n    const productsCount = span.attributes.find(attr =\u003e attr.key === \"app.products.count\");\n    expect(productsCount?.value?.intValue).toBe(10);\n  });\n});\n```\nThe code above waits for a span and compares it using the `expect` statement\n\n### Other Examples\n\nFor more examples, refer to [documentation](./docs/howToUse.md#jest).\n\n## Playwright\n\nYou can write Playwright tests in TypeScript too.\n\n### YAML\n\nYou can write tests using YAML, and Echoed will convert them into Playwright tests.  \n\n![Compilation flow](https://github.com/mrasu/echoed/raw/main/docs/img/scenarioYamlToPlaywright.png)\n\nThe YAML below opens `http://localhost:8080` and validates DOM elements.\n\n```yaml\nscenarios:\n  - name: Validate Homepage\n    fixtures:\n      - page\n    steps:\n      - description: Check product list is shown\n        act:\n          raw: await page.goto(\"http://localhost:8080\")\n        assert:\n          - expectToBeVisible: \"[data-cy=home-page]\"\n          - expectToHaveCount:\n              selector: \"[data-cy=product-list] [data-cy=product-card]\"\n              count: 10\n```\n\nFor more details, refer to the [documentation](./docs/yamlPlaywrightScenario.md) or [examples](create-echoed/template/playwright/example/test/scenario). \n\n### Make Tests Observable\n\nYou can write Playwright tests in TypeScript too.\n\nTo generate an HTML report visualizing API traces, replace `test` of Playwright to Echoed's to intercept requests.\n\n```ts\n// import { test } from \"@playwright/test\"; \u003c- Replace this line\nimport { test } from \"echoed/playwright/test\";\n\ntest(\"opens home page\", async ({ page }) =\u003e {\n  await page.goto(\"http://localhost:8080/\");\n  await expect(page).toHaveTitle(\"OTel demo\");\n\n  const productList = page.locator(\"[data-cy=product-card]\");\n  await expect(productList).toHaveCount(10);\n});\n```\n\nThe code above produces an HTML report illustrating traces when opening the home page(`http://localhost:8080`).\n\n### Test OpenTelemetry's Spans\n\nIn addition to the HTML output, Echoed offers a method for testing OpenTelemetry spans.  \nUse the `waitForSpanCreatedIn` function to obtain a span that matches your needs.\n\n```ts\ntest(\"creates an OpenTelemetry gRPC span\", async ({ page }) =\u003e {\n  await page.goto(\"http://localhost:8080/\");\n  await expect(page).toHaveTitle(\"OTel demo\");\n\n  const span = await waitForSpanCreatedIn(\n    page.context(),\n    \"http://localhost:8080/api/products\",\n    { name: \"oteldemo.ProductCatalogService/ListProducts\" },\n  );\n  \n  const rpcSystem = span.attributes.find(\n    (attr) =\u003e attr.key === \"app.products.count\",\n  );\n  expect(rpcSystem?.value?.intValue).toBe(10);\n});\n```\nThe code above waits for a span that links to the request to `http://localhost:8080/api/products` and compares it using the `expect` statement\n\n### Other Examples\n\nFor more examples, refer to [documentation](./docs/howToUse.md#playwright).\n\n## Cypress\n\nYou can write Cypress tests in TypeScript too.\n\n### Make Tests Observable\n\nTo generate an HTML report visualizing API traces, no additional code is needed.  \nSimply write your Cypress tests as usual.\n\n```ts\nit(\"opens home page\", () =\u003e {\n  cy.visit(\"http://localhost:8080\");\n  cy.title().should(\"eq\", \"OTel demo\");\n  \n  cy.get(\"[data-cy=product-card]\").should(\"have.length\", 10);\n});\n```\n\nThe code above produces an HTML report illustrating traces when opening the home page(`http://localhost:8080`).\n\n### Test OpenTelemetry's Spans\n\nIn addition to the HTML output, Echoed offers a method for testing OpenTelemetry spans.  \nUse the `waitForSpan` command to obtain a span that matches your needs.\n\n```ts\nit(\"creates an OpenTelemetry gRPC span\", () =\u003e {\n  cy.visit(\"http://localhost:8080\");\n  cy.title().should(\"eq\", \"OTel demo\");\n\n  cy.waitForSpan(\n    \"http://localhost:8080/api/products\",\n    { name: \"oteldemo.ProductCatalogService/ListProducts\" },\n  ).then((span) =\u003e {\n    const rpcSystem = span.attributes.find(\n      (attr) =\u003e attr.key === \"app.products.count\",\n    );\n    expect(rpcSystem?.value?.intValue).to.eq(10);\n  });\n});\n```\nThe code above waits for a span that links to the request to `http://localhost:8080/api/products` and compares it using the `expect` statement\n\n### Other Examples\n\nFor more examples, refer to [documentation](./docs/howToUse.md#cypress).\n\n## Analyze Coverage\n\nYou can get coverage of your HTTP and gRPC endpoints based on OpenAPI or Protocol Buffers specifications.  \nBy configuring the `openapi` or `proto` option in your `.echoed.yml` file, Echoed analyzes the coverage of your tests and generates a report.  \nFor more option, refer to the [Configuration](#Configuration) section.  \n\n```yaml\nservices:\n  - name: frontend\n    namespace: opentelemetry-demo\n    openapi: \"./example/echoed-opentelemetry-demo/src/frontend/schema.yaml\"\n  - name: cartservice\n    namespace: opentelemetry-demo\n    proto:\n      filePath: \"./example/echoed-opentelemetry-demo/pb/demo.proto\"\n      services:\n        - oteldemo.CartService\n```\n\n# Using Echoed without OpenTelemetry\n\nWhile Echoed's primary feature is to troubleshoot or analyze tests by visualizing OpenTelemetry data, it can also be used to write tests in YAML.  \nTo add YAML tests into existing tests, simply create a `.echoed.yml` file for configuration and run `npx echoed compile`.  \n\nAlternatively, if you wish to create example tests without OpenTelemetry, you can do so using the following commands:\n```bash\n# Create example tests\nnpm create echoed@latest -- --template jest-no-otel\n\n# Compile YAML to TypeScript and run tests\nnpx echoed compile\nnpx jest\n```\n\nOr for Playwright:\n```bash\n# Create example tests\nnpm create echoed@latest -- --template playwright-no-otel\n\n# Compile YAML to TypeScript and run tests\nnpx echoed compile\nnpx playwright test\n```\n\n# Configuration\n\nEchoed can be configured at `.echoed.yml` in the root of your project.  \nExplore available options [here](./src/schema/configSchema.ts).\n","funding_links":[],"categories":["Packages","Reporters"],"sub_categories":["Reporters"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrasu%2Fechoed","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmrasu%2Fechoed","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrasu%2Fechoed/lists"}