{"id":44508609,"url":"https://github.com/jagreehal/executable-stories","last_synced_at":"2026-06-11T08:00:53.586Z","repository":{"id":336332648,"uuid":"1148355016","full_name":"jagreehal/executable-stories","owner":"jagreehal","description":"Tests that document. Reports that convince. Write BDD stories inside your test framework. Generate living documentation your whole team can read.","archived":false,"fork":false,"pushed_at":"2026-06-09T22:01:53.000Z","size":28697,"stargazers_count":2,"open_issues_count":10,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-10T00:04:35.656Z","etag":null,"topics":["bdd","cypress","dotnet","executable","golang","java","javascript","jest","kotlin","living-documentation","otel","playwright","python","ruby","rust","typescript","vitest"],"latest_commit_sha":null,"homepage":"https://executablestories.com","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/jagreehal.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-02-02T21:43:53.000Z","updated_at":"2026-06-09T22:02:08.000Z","dependencies_parsed_at":null,"dependency_job_id":"16913a22-0fe2-4e96-b853-f08eac8237b6","html_url":"https://github.com/jagreehal/executable-stories","commit_stats":null,"previous_names":["jagreehal/executable-stories"],"tags_count":205,"template":false,"template_full_name":null,"purl":"pkg:github/jagreehal/executable-stories","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jagreehal%2Fexecutable-stories","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jagreehal%2Fexecutable-stories/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jagreehal%2Fexecutable-stories/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jagreehal%2Fexecutable-stories/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jagreehal","download_url":"https://codeload.github.com/jagreehal/executable-stories/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jagreehal%2Fexecutable-stories/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34188272,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-11T02:00:06.485Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["bdd","cypress","dotnet","executable","golang","java","javascript","jest","kotlin","living-documentation","otel","playwright","python","ruby","rust","typescript","vitest"],"created_at":"2026-02-13T12:37:11.315Z","updated_at":"2026-06-11T08:00:53.577Z","avatar_url":"https://github.com/jagreehal.png","language":"TypeScript","funding_links":[],"categories":["Packages"],"sub_categories":["Utilities"],"readme":"# executable-stories\n\nExecutable stories without Cucumber across JavaScript/TypeScript and non-JS test frameworks, with generated documentation and report outputs.\n\n## Why not Cucumber?\n\n| This project                  | Cucumber                        |\n| ----------------------------- | ------------------------------- |\n| Write TypeScript              | Write Gherkin feature files     |\n| Steps are inline functions    | Steps matched by regex          |\n| Normal variables and closures | World object and shared state   |\n| Docs generated from test runs | Separate documentation pipeline |\n\nOne source of truth. Code that executes. Docs that do not lie.\n\n## What you get\n\n- Scenario API built on your test runner's native primitives\n- `given()`, `when()`, `then()`, `and()`, `but()` helpers that register real tests\n- Reporters/formatters that generate Markdown, HTML, JUnit XML, and Cucumber outputs from test metadata\n- Output readable by developers and stakeholders\n\nIf a test is skipped, failed, or todo, the docs reflect that.\n\n## Packages\n\n| Package                                                                   | Ecosystem                    | Install / Usage                          |\n| ------------------------------------------------------------------------- | ---------------------------- | ---------------------------------------- |\n| [executable-stories-jest](./packages/executable-stories-jest)             | Jest 30+                     | `npm i -D executable-stories-jest`       |\n| [executable-stories-vitest](./packages/executable-stories-vitest)         | Vitest 4+                    | `npm i -D executable-stories-vitest`     |\n| [executable-stories-playwright](./packages/executable-stories-playwright) | Playwright 1.58+             | `npm i -D executable-stories-playwright` |\n| [executable-stories-cypress](./packages/executable-stories-cypress)       | Cypress 13+                  | `npm i -D executable-stories-cypress`    |\n| [executable-stories-ruby](./packages/executable-stories-ruby)             | Ruby / Minitest              | Ruby gem/package in repo                 |\n| [executable-stories-go](./packages/executable-stories-go)                 | Go `testing`                 | Go module in repo                        |\n| [executable-stories-rust](./packages/executable-stories-rust)             | Rust                          | Rust crate in repo                       |\n| [executable-stories-pytest](./packages/executable-stories-pytest)         | Python / pytest              | Python package in repo                   |\n| [executable-stories-junit5](./packages/executable-stories-junit5)         | Kotlin / JUnit 5             | JVM module in repo                       |\n| [executable-stories-xunit](./packages/executable-stories-xunit)           | C# / xUnit                   | .NET package in repo                     |\n| [executable-stories-formatters](./packages/executable-stories-formatters) | Cross-runner formatter CLI   | `npm i -D executable-stories-formatters` |\n| [executable-stories-react](./packages/executable-stories-react)           | React StoryReport renderer   | `npm i executable-stories-react`         |\n| [executable-stories-mcp](./packages/executable-stories-mcp)               | Read-only MCP behavior tools | `npm i -D executable-stories-mcp`        |\n| [executable-stories-init](./packages/executable-stories-init)             | JS/TS onboarding CLI         | `npm i -D executable-stories-init`       |\n| [executable-stories-demo](./packages/executable-stories-demo)             | Demo site/report tooling     | workspace package                        |\n| [eslint-plugin-executable-stories-vitest](./packages/eslint-plugin-executable-stories-vitest) | ESLint plugin (Vitest) | `npm i -D eslint-plugin-executable-stories-vitest` |\n| [eslint-plugin-executable-stories-jest](./packages/eslint-plugin-executable-stories-jest) | ESLint plugin (Jest)   | `npm i -D eslint-plugin-executable-stories-jest` |\n| [eslint-plugin-executable-stories-playwright](./packages/eslint-plugin-executable-stories-playwright) | ESLint plugin (Playwright) | `npm i -D eslint-plugin-executable-stories-playwright` |\n| [eslint-config](./packages/eslint-config)                                 | Shared ESLint config         | workspace package                        |\n\nExample apps: [apps/jest-example](./apps/jest-example), [apps/vitest-example](./apps/vitest-example), [apps/playwright-example](./apps/playwright-example), [apps/cypress-example](./apps/cypress-example), [apps/vite-plus-example](./apps/vite-plus-example), [apps/junit5-example](./apps/junit5-example) (Java 21, Maven; verification: `pnpm run verify:junit5`), [apps/pytest-example](./apps/pytest-example) (Python 3.12+, pytest; verification: `pnpm run verify:pytest`), [apps/go-example](./apps/go-example) (Go 1.22+; verification: `pnpm run verify:go`), [apps/rust-example](./apps/rust-example) (Rust 1.75+; verification: `pnpm run verify:rust`), [apps/xunit-example](./apps/xunit-example) (.NET 8, xUnit; verification: `pnpm run verify:xunit`).\n\n### Features matrix\n\n| Feature                           | Jest                                                                          | Vitest                                                       | Playwright                                           | Cypress                                              |\n| --------------------------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------ | ---------------------------------------------------- | ---------------------------------------------------- |\n| **API**                           | `story.init()` + `story.given` / `story.when` / `story.then`; top-level step helpers also exported | `story.init(task)` + `story.given` / `story.when` / `story.then`; no top-level `then` export | `story.init(testInfo)` + `story.given` / `story.when` / `story.then`; top-level step helpers also exported | `story.init()` + `story.given` / `story.when` / `story.then`; top-level step helpers also exported |\n| **Step modifiers**                | `.skip` `.only` `.todo` `.fails` `.concurrent`                                | `.skip` `.only` `.todo` `.fails` `.concurrent`               | `.skip` `.only` `.fixme` `.todo` `.fail` `.slow`     | `.skip` `.only` `.todo` `.fails` `.concurrent`       |\n| **Scenario modifiers**            | `story.skip` `story.only`                                                     | `story.skip` `story.only`                                    | `story.skip` `story.only` `story.fixme` `story.slow` | `story.skip` `story.only`                            |\n| **Output modes**                  | Colocated, aggregated, mixed                                                  | Colocated, aggregated, mixed                                 | Colocated, aggregated, mixed                         | Colocated, aggregated, mixed                         |\n| **Rich step docs**                | ✅ note, kv, code, table, link, section, mermaid, screenshot, video, runtime, custom | ✅ same                                                      | ✅ same                                              | ✅ same                                              |\n| **Embedded HTML** (`story.html`)  | ✅ path / url / content → sandboxed iframe                                     | ✅ path / url / content → sandboxed iframe                   | ✅ same (local files inlined at capture time)        | ✅ path / url / content → sandboxed iframe            |\n| **Scenario options**              | `tags`, `meta`, `ticket`, `traceUrlTemplate`                                  | `tags`, `meta`, `ticket`, `traceUrlTemplate`                 | `tags`, `meta`, `ticket`, `traceUrlTemplate`         | `tags`, `meta`, `ticket`, `traceUrlTemplate`         |\n| **OTel trace link**               | ✅ auto-detect via `@opentelemetry/api`                                       | ✅ same                                                      | ✅ same                                              | — (browser env)                                      |\n| **OTel trace waterfall**          | —                                                                             | ✅ via [autotel](https://github.com/jagreehal/autotel) `task.meta.otelSpans` | ✅ via autotel `otel-spans` annotation               | —                                                    |\n| **Attach story to plain it/test** | `story.init()` inside `test()`                                                | `story.init(task)` with `it(..., ({ task }) =\u003e ...)`         | `story.init(testInfo)` inside `test()`               | `story.init()` or `doc.story(\"Title\")` inside `it()` |\n| **Step callbacks**                | `story.given('text', () =\u003e ...)` on all steps                                 | ✅ same                                                      | ✅ same                                              | ✅ same                                              |\n| **AAA aliases**                   | arrange/act/assert, setup/context, etc.                                       | arrange/act/assert, setup/context, etc.                      | arrange/act/assert, setup/context, etc.              | arrange/act/assert, setup/context, etc.              |\n| **CLI collate**                   | ✅                                                                            | ✅                                                           | ✅                                                   | ✅                                                   |\n| **CI detection (formatter CLI)**  | ✅ (report meta: branch, commit, build URL)                                  | ✅                                                           | ✅                                                   | ✅                                                   |\n| **Notifications (formatter CLI)**| Slack, Teams, webhook; `--notify`                                            | same                                                         | same                                                | same                                                |\n| **Run history (formatter CLI)**   | `--history-file` → flakiness, stability, perf in HTML                       | same                                                         | same                                                | same                                                |\n| **GitHub Actions summary**        | ✅                                                                            | ✅                                                           | ✅                                                   | ✅                                                   |\n| **Custom doc renderers**          | ✅                                                                            | ✅                                                           | ✅                                                   | ✅                                                   |\n\nFor per-framework behaviour and guarantees (entry point, mental model, modifiers, framework-native attach), see: [Jest — Developer experience](./packages/executable-stories-jest/README.md#developer-experience), [Vitest — Developer experience](./packages/executable-stories-vitest/README.md#developer-experience), [Playwright — Developer experience](./packages/executable-stories-playwright/README.md#developer-experience), [Cypress](./packages/executable-stories-cypress/README.md).\n\nDetails and reporter options: see each package's README.\n\n**OTel trace link** is also supported in the non-JS adapters: Go (`WithTraceUrlTemplate`), Python (`trace_url_template`), Kotlin/JUnit5 (`traceUrlTemplate` parameter or env var), Rust (`with_trace_url_template`, requires `otel` feature), and C#/xUnit (`Story.WithTraceUrlTemplate()` or env var). All adapters auto-detect an active span and inject trace ID docs bidirectionally. Set `OTEL_TRACE_URL_TEMPLATE` (with `{traceId}` placeholder) to generate clickable trace links in reports.\n\n**Step timing** (`startTimer`/`endTimer`) is supported in all non-JS adapters: Go (`s.StartTimer()`/`s.EndTimer(token)`), Python (`story.start_timer()`/`story.end_timer(token)`), Kotlin/JUnit5 (`Story.startTimer()`/`Story.endTimer(token)`), Rust (`story.start_timer()`/`story.end_timer(token)`), and C#/xUnit (`Story.StartTimer()`/`Story.EndTimer(token)`). The JS adapters record step timing automatically via `story.fn()` / `story.expect()` wrappers and step callbacks.\n\n## Quick example\n\n**Jest** (`story.init()` plus step markers):\n\n```ts\nimport { expect, it } from '@jest/globals';\nimport { story } from 'executable-stories-jest';\n\nit('User logs in', () =\u003e {\n  story.init();\n  story.given('user is on login page');\n  story.when('user submits valid credentials');\n  story.then('user sees the dashboard', () =\u003e {\n    expect(true).toBe(true); // or real assertion\n  });\n});\n```\n\nPlaywright uses the same `story.given` / `story.when` / `story.then` style, but pass `testInfo` to `story.init(testInfo)`.\n\n**Cypress** (call `story.init()` at the start of each `it`, then use step markers; see [Cypress README](./packages/executable-stories-cypress/README.md)).\n\n**Vitest** (`story.init(task)`; no top-level `then`):\n\n```ts\nimport { expect, it } from 'vitest';\nimport { story } from 'executable-stories-vitest';\n\nit('User logs in', ({ task }) =\u003e {\n  story.init(task);\n  story.given('user is on login page');\n  story.when('user submits valid credentials');\n  story.then('user sees the dashboard', () =\u003e {\n    expect(true).toBe(true);\n  });\n});\n```\n\nPlaywright step callbacks can use fixtures: `given(\"...\", async ({ page }) =\u003e { await page.goto(\"/login\"); });`\n\n**Generated Markdown:**\n\n```markdown\n### User logs in\n\n- **Given** user is on login page\n- **When** user submits valid credentials\n- **Then** user sees the dashboard\n```\n\n## Getting started\n\n1. Install the package for your test runner\n2. Add the reporter to your config\n3. Run your tests\n4. Open the generated Markdown\n\nSee each package's README for detailed setup instructions.\n\n**Agent workflows:** Publish StoryReport JSON and a scenario index from CI — see the [agent artifact contract](https://executablestories.com/guides/agent-artifact-contract/) and [MCP server guide](https://executablestories.com/guides/mcp-server/). Package roles: [package map](https://executablestories.com/reference/package-map/). Cross-language parity policy: [parity matrix](https://executablestories.com/reference/cross-language-parity/).\n\n## Development\n\nFrom the repo root: `pnpm quality` runs build, lint, type-check, and test for all packages.\n\nFor contributor and AI agent guidance (conventions, framework APIs, ESLint plugins, verification), see [AGENTS.md](./AGENTS.md). [CLAUDE.md](./CLAUDE.md) is a symlink to the same file. Example apps in `apps/` use the workspace packages. JUnit 5, pytest, Go, Rust, Ruby, and xUnit example apps are not part of `pnpm quality`. When Java 21 and Maven are available (e.g. in the devcontainer), run `pnpm run verify:junit5` to run [junit5-example](./apps/junit5-example). When Python 3.12+ is available, run `pnpm run verify:pytest` to run [pytest-example](./apps/pytest-example). When Go 1.22+ is available, run `pnpm run verify:go` to run [go-example](./apps/go-example). When Rust is available, run `pnpm run verify:rust` to run [rust-example](./apps/rust-example). When Ruby and Bundler are available, run `pnpm run verify:ruby` for [executable-stories-ruby](./packages/executable-stories-ruby). When .NET 8 is available, run `pnpm run verify:xunit` to run [xunit-example](./apps/xunit-example).\n\n### Formatters standalone binary\n\nThe `executable-stories-formatters` package (CLI for generating reports from test results JSON) supports filtering by source file (`--include` / `--exclude`), **CI auto-detection** (GitHub Actions, GitLab, CircleCI, Azure DevOps, Buildkite, Jenkins, Travis) so reports include branch, commit, and build links, **notifications** (Slack, Teams, or generic webhook with optional HMAC signing; `--notify always|on-failure|never`), and **run history** (`--history-file`) for flakiness, stability, and performance trends in the HTML report. See [formatters README](./packages/executable-stories-formatters/README.md#filtering-by-source-file). The HTML report highlights step parameters (quoted strings and numbers) for readability. The package can be built as a single standalone binary with [Bun](https://bun.sh):\n\n```bash\ncd packages/executable-stories-formatters \u0026\u0026 bun run compile\n```\n\nThis produces an `executable-stories` binary in that package directory. CI builds the binary for the runner platform and uploads it as an artifact (`executable-stories-linux-x64`). The Release workflow builds multi-platform binaries (linux-x64, linux-arm64, darwin-x64, darwin-arm64, windows-x64) and uploads them as the `formatters-binaries` artifact.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjagreehal%2Fexecutable-stories","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjagreehal%2Fexecutable-stories","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjagreehal%2Fexecutable-stories/lists"}