@crvouga/atlas 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/LICENSE +21 -0
- package/README.md +649 -2
- package/dist/bun/src/driver.d.ts +67 -0
- package/dist/bun/src/driver.js +90 -0
- package/dist/bun/src/index.d.ts +2 -0
- package/dist/bun/src/index.js +2 -0
- package/dist/core/src/cli.d.ts +1 -0
- package/dist/core/src/cli.js +177 -0
- package/dist/core/src/config.d.ts +477 -0
- package/dist/core/src/config.js +100 -0
- package/dist/core/src/events/cloudevents.d.ts +56 -0
- package/dist/core/src/events/cloudevents.js +152 -0
- package/dist/core/src/graph.d.ts +113 -0
- package/dist/core/src/graph.js +221 -0
- package/dist/core/src/index.d.ts +17 -0
- package/dist/core/src/index.js +17 -0
- package/dist/core/src/lint.d.ts +53 -0
- package/dist/core/src/lint.js +138 -0
- package/dist/core/src/plan.d.ts +109 -0
- package/dist/core/src/plan.js +324 -0
- package/dist/core/src/privacy.d.ts +8 -0
- package/dist/core/src/privacy.js +42 -0
- package/dist/core/src/report/formats.d.ts +69 -0
- package/dist/core/src/report/formats.js +109 -0
- package/dist/core/src/report/markdown.d.ts +8 -0
- package/dist/core/src/report/markdown.js +140 -0
- package/dist/core/src/run/clients.d.ts +42 -0
- package/dist/core/src/run/clients.js +250 -0
- package/dist/core/src/run/execute.d.ts +854 -0
- package/dist/core/src/run/execute.js +877 -0
- package/dist/core/src/run/frames.d.ts +16 -0
- package/dist/core/src/run/frames.js +52 -0
- package/dist/core/src/run/http.d.ts +41 -0
- package/dist/core/src/run/http.js +71 -0
- package/dist/core/src/run/types.d.ts +248 -0
- package/dist/core/src/run/types.js +39 -0
- package/dist/core/src/signals.d.ts +110 -0
- package/dist/core/src/signals.js +121 -0
- package/dist/core/src/spec/compose.d.ts +28 -0
- package/dist/core/src/spec/compose.js +71 -0
- package/dist/core/src/spec/index.d.ts +5 -0
- package/dist/core/src/spec/index.js +5 -0
- package/dist/core/src/spec/load.d.ts +8 -0
- package/dist/core/src/spec/load.js +46 -0
- package/dist/core/src/spec/parse.d.ts +5 -0
- package/dist/core/src/spec/parse.js +32 -0
- package/dist/core/src/spec/scxml.d.ts +19 -0
- package/dist/core/src/spec/scxml.js +239 -0
- package/dist/core/src/spec/types.d.ts +96 -0
- package/dist/core/src/spec/types.js +25 -0
- package/dist/detox/src/index.d.ts +75 -0
- package/dist/detox/src/index.js +110 -0
- package/dist/playwright/src/driver.d.ts +44 -0
- package/dist/playwright/src/driver.js +82 -0
- package/dist/playwright/src/index.d.ts +3 -0
- package/dist/playwright/src/index.js +3 -0
- package/dist/playwright/src/media.d.ts +68 -0
- package/dist/playwright/src/media.js +283 -0
- package/dist/playwright/src/signals.d.ts +34 -0
- package/dist/playwright/src/signals.js +56 -0
- package/dist/reports/src/browser-navigation.d.ts +2 -0
- package/dist/reports/src/browser-navigation.js +28 -0
- package/dist/reports/src/bundle.d.ts +24 -0
- package/dist/reports/src/bundle.js +114 -0
- package/dist/reports/src/catalog.d.ts +37 -0
- package/dist/reports/src/catalog.js +127 -0
- package/dist/reports/src/clock.d.ts +14 -0
- package/dist/reports/src/clock.js +4 -0
- package/dist/reports/src/completion-order.d.ts +10 -0
- package/dist/reports/src/completion-order.js +76 -0
- package/dist/reports/src/evidence-live.d.ts +40 -0
- package/dist/reports/src/evidence-live.js +118 -0
- package/dist/reports/src/evidence-types.d.ts +90 -0
- package/dist/reports/src/evidence-types.js +15 -0
- package/dist/reports/src/evidence-view.d.ts +68 -0
- package/dist/reports/src/evidence-view.js +113 -0
- package/dist/reports/src/explorer-types.d.ts +56 -0
- package/dist/reports/src/explorer-types.js +0 -0
- package/dist/reports/src/explorer-versions.d.ts +4 -0
- package/dist/reports/src/explorer-versions.js +21 -0
- package/dist/reports/src/export-evidence.d.ts +11 -0
- package/dist/reports/src/export-evidence.js +94 -0
- package/dist/reports/src/fetcher.d.ts +50 -0
- package/dist/reports/src/fetcher.js +205 -0
- package/dist/reports/src/format-date.d.ts +1 -0
- package/dist/reports/src/format-date.js +10 -0
- package/dist/reports/src/format.d.ts +16 -0
- package/dist/reports/src/format.js +71 -0
- package/dist/reports/src/frames.d.ts +46 -0
- package/dist/reports/src/frames.js +245 -0
- package/dist/reports/src/hash.d.ts +17 -0
- package/dist/reports/src/hash.js +43 -0
- package/dist/reports/src/html-frame.d.ts +13 -0
- package/dist/reports/src/html-frame.js +63 -0
- package/dist/reports/src/http.d.ts +3 -0
- package/dist/reports/src/http.js +0 -0
- package/dist/reports/src/junit.d.ts +23 -0
- package/dist/reports/src/junit.js +119 -0
- package/dist/reports/src/keyboard.d.ts +16 -0
- package/dist/reports/src/keyboard.js +135 -0
- package/dist/reports/src/keys.d.ts +53 -0
- package/dist/reports/src/keys.js +122 -0
- package/dist/reports/src/layer-catalog.d.ts +5 -0
- package/dist/reports/src/layer-catalog.js +39 -0
- package/dist/reports/src/layer-merge.d.ts +43 -0
- package/dist/reports/src/layer-merge.js +154 -0
- package/dist/reports/src/layer-source.d.ts +6 -0
- package/dist/reports/src/layer-source.js +32 -0
- package/dist/reports/src/layer-store.d.ts +10 -0
- package/dist/reports/src/layer-store.js +36 -0
- package/dist/reports/src/layer-types.d.ts +32 -0
- package/dist/reports/src/layer-types.js +0 -0
- package/dist/reports/src/layers-route.d.ts +20 -0
- package/dist/reports/src/layers-route.js +259 -0
- package/dist/reports/src/namespace-guard.d.ts +11 -0
- package/dist/reports/src/namespace-guard.js +40 -0
- package/dist/reports/src/navigation.d.ts +8 -0
- package/dist/reports/src/navigation.js +0 -0
- package/dist/reports/src/object-io.d.ts +9 -0
- package/dist/reports/src/object-io.js +41 -0
- package/dist/reports/src/object-store.d.ts +67 -0
- package/dist/reports/src/object-store.js +32 -0
- package/dist/reports/src/performance-part.d.ts +9 -0
- package/dist/reports/src/performance-part.js +42 -0
- package/dist/reports/src/performance.d.ts +13 -0
- package/dist/reports/src/performance.js +45 -0
- package/dist/reports/src/persist.d.ts +10 -0
- package/dist/reports/src/persist.js +38 -0
- package/dist/reports/src/phone.d.ts +5 -0
- package/dist/reports/src/phone.js +18 -0
- package/dist/reports/src/protocol.d.ts +78 -0
- package/dist/reports/src/protocol.js +36 -0
- package/dist/reports/src/publication.d.ts +4 -0
- package/dist/reports/src/publication.js +35 -0
- package/dist/reports/src/publish.d.ts +52 -0
- package/dist/reports/src/publish.js +189 -0
- package/dist/reports/src/read.d.ts +62 -0
- package/dist/reports/src/read.js +214 -0
- package/dist/reports/src/recording-bundle.d.ts +22 -0
- package/dist/reports/src/recording-bundle.js +4 -0
- package/dist/reports/src/recording-keys.d.ts +9 -0
- package/dist/reports/src/recording-keys.js +50 -0
- package/dist/reports/src/remote-report.d.ts +39 -0
- package/dist/reports/src/remote-report.js +304 -0
- package/dist/reports/src/report-loader.d.ts +22 -0
- package/dist/reports/src/report-loader.js +0 -0
- package/dist/reports/src/report-parts.d.ts +10 -0
- package/dist/reports/src/report-parts.js +112 -0
- package/dist/reports/src/report-types.d.ts +194 -0
- package/dist/reports/src/report-types.js +29 -0
- package/dist/reports/src/reports-explorer-route.d.ts +90 -0
- package/dist/reports/src/reports-explorer-route.js +65 -0
- package/dist/reports/src/reports-list-route.d.ts +23 -0
- package/dist/reports/src/reports-list-route.js +55 -0
- package/dist/reports/src/reports-route.d.ts +267 -0
- package/dist/reports/src/reports-route.js +204 -0
- package/dist/reports/src/reports-store.d.ts +11 -0
- package/dist/reports/src/reports-store.js +28 -0
- package/dist/reports/src/resilient-cache.d.ts +3 -0
- package/dist/reports/src/resilient-cache.js +33 -0
- package/dist/reports/src/retention.d.ts +9 -0
- package/dist/reports/src/retention.js +16 -0
- package/dist/reports/src/scenario.d.ts +15 -0
- package/dist/reports/src/scenario.js +35 -0
- package/dist/reports/src/snapshot-bundle.d.ts +18 -0
- package/dist/reports/src/snapshot-bundle.js +94 -0
- package/dist/reports/src/snapshot-surface.d.ts +29 -0
- package/dist/reports/src/snapshot-surface.js +339 -0
- package/dist/reports/src/source-content.d.ts +30 -0
- package/dist/reports/src/source-content.js +63 -0
- package/dist/reports/src/source-entries.d.ts +4 -0
- package/dist/reports/src/source-entries.js +34 -0
- package/dist/reports/src/source-part.d.ts +4 -0
- package/dist/reports/src/source-part.js +66 -0
- package/dist/reports/src/source-reader.d.ts +6 -0
- package/dist/reports/src/source-reader.js +17 -0
- package/dist/reports/src/spec-evidence.d.ts +6 -0
- package/dist/reports/src/spec-evidence.js +20 -0
- package/dist/reports/src/spec-inventory.d.ts +14 -0
- package/dist/reports/src/spec-inventory.js +75 -0
- package/dist/reports/src/status.d.ts +4 -0
- package/dist/reports/src/status.js +8 -0
- package/dist/reports/src/store-prefix.d.ts +21 -0
- package/dist/reports/src/store-prefix.js +53 -0
- package/dist/reports/src/test-catalog-entity.d.ts +3 -0
- package/dist/reports/src/test-catalog-entity.js +34 -0
- package/dist/reports/src/types.d.ts +5 -0
- package/dist/reports/src/types.js +0 -0
- package/dist/reports/src/use-report-nav.d.ts +25 -0
- package/dist/reports/src/use-report-nav.js +181 -0
- package/dist/schema/src/common.d.ts +57 -0
- package/dist/schema/src/common.js +32 -0
- package/dist/schema/src/index.d.ts +5 -0
- package/dist/schema/src/index.js +5 -0
- package/dist/schema/src/manifest.d.ts +457 -0
- package/dist/schema/src/manifest.js +247 -0
- package/dist/schema/src/report-sources.d.ts +68 -0
- package/dist/schema/src/report-sources.js +53 -0
- package/dist/schema/src/runs-index.d.ts +52 -0
- package/dist/schema/src/runs-index.js +24 -0
- package/dist/schema/src/spec.d.ts +245 -0
- package/dist/schema/src/spec.js +133 -0
- package/dist/vitest/src/index.d.ts +22 -0
- package/dist/vitest/src/index.js +33 -0
- package/dist/webdriver/src/driver.d.ts +69 -0
- package/dist/webdriver/src/driver.js +230 -0
- package/dist/webdriver/src/index.d.ts +11 -0
- package/dist/webdriver/src/index.js +10 -0
- package/dist/webdriver/src/protocol.d.ts +60 -0
- package/dist/webdriver/src/protocol.js +146 -0
- package/package.json +181 -4
- package/packages/bun/README.md +69 -0
- package/packages/core/README.md +78 -0
- package/packages/core/bin/atlas.mjs +8 -0
- package/packages/detox/README.md +73 -0
- package/packages/playwright/README.md +77 -0
- package/packages/reports/README.md +47 -0
- package/packages/reports/STORAGE.md +73 -0
- package/packages/schema/README.md +23 -0
- package/packages/schema/schemas/atlas-change.schema.json +34 -0
- package/packages/schema/schemas/atlas.schema.json +32 -0
- package/packages/schema/schemas/cloud-event.schema.json +40 -0
- package/packages/schema/schemas/journeys.schema.json +17 -0
- package/packages/schema/schemas/manifest.schema.json +160 -0
- package/packages/schema/schemas/path-record.schema.json +151 -0
- package/packages/schema/schemas/report-sources.schema.json +95 -0
- package/packages/schema/schemas/run-info.schema.json +176 -0
- package/packages/schema/schemas/run-summary.schema.json +206 -0
- package/packages/schema/schemas/runs-index.schema.json +23 -0
- package/packages/schema/schemas/state-node.schema.json +238 -0
- package/packages/schema/schemas/state-record.schema.json +354 -0
- package/packages/schema/schemas/timeline-entry.schema.json +124 -0
- package/packages/schema/schemas/transition-record.schema.json +125 -0
- package/packages/visualizer/README.md +154 -0
- package/packages/visualizer/bin/atlas-visualizer.mjs +176 -0
- package/packages/visualizer/example/specs/coffee/ordering/checkout.scxml +82 -0
- package/packages/visualizer/example/specs/coffee/ordering/journeys.yaml +129 -0
- package/packages/visualizer/example/specs/coffee/ordering/known-issues.md +14 -0
- package/packages/visualizer/example/specs/coffee/ordering/machine.yaml +158 -0
- package/packages/visualizer/example/specs/coffee/ordering/open-questions.md +25 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/chart.mmd +67 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/ctrf.json +245 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/junit.xml +12 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/manifest.json +2003 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/001.vtt +9 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/002.vtt +9 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/003.vtt +9 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/004.vtt +9 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/005.vtt +17 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/006.vtt +9 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/007.vtt +17 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/008.vtt +17 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/009.vtt +13 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/010.vtt +9 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/011.vtt +9 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/012.vtt +9 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/013.vtt +9 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/01.mp4 +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/01.poster.webp +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/02.mp4 +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/02.poster.webp +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/03.mp4 +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/03.poster.webp +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/04.mp4 +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/04.poster.webp +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/01.png +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/01.webp +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/02.png +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/02.webp +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/03.png +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/03.webp +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/04.png +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/04.webp +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/05.png +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/05.webp +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-2/01.png +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-2/01.webp +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-3/failed-01.png +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-3/failed-01.webp +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-4/01.png +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-4/01.webp +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-5/01.png +0 -0
- package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-5/01.webp +0 -0
- package/packages/visualizer/fixtures/failures/specs/coffee/ordering/checkout.scxml +82 -0
- package/packages/visualizer/fixtures/failures/specs/coffee/ordering/journeys.yaml +129 -0
- package/packages/visualizer/fixtures/failures/specs/coffee/ordering/known-issues.md +14 -0
- package/packages/visualizer/fixtures/failures/specs/coffee/ordering/machine.yaml +158 -0
- package/packages/visualizer/fixtures/failures/specs/coffee/ordering/open-questions.md +25 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-02T09-10-00-000Z-fast/chart.mmd +67 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-02T09-10-00-000Z-fast/ctrf.json +247 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-02T09-10-00-000Z-fast/junit.xml +12 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-02T09-10-00-000Z-fast/manifest.json +1875 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/chart.mmd +67 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/ctrf.json +244 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/junit.xml +12 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/manifest.json +1977 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/captions/001.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/captions/002.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/captions/003.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/captions/004.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/captions/005.vtt +17 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/captions/006.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/clips/journey-1/01.mp4 +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/clips/journey-1/01.poster.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/clips/journey-1/02.mp4 +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/clips/journey-1/02.poster.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/paths/journey-1/01.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/paths/journey-1/01.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/paths/journey-1/02.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/paths/journey-1/02.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/paths/journey-1/03.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/paths/journey-1/03.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/paths/journey-2/01.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/paths/journey-2/01.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/chart.mmd +67 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/ctrf.json +472 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/junit.xml +16 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/manifest.json +3701 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/001.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/002.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/003.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/004.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/005.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/006.vtt +13 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/007.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/008.vtt +13 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/009.vtt +17 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/010.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/011.vtt +13 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/012.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/013.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/014.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/015.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/016.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/017.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/018.vtt +17 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/019.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/020.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/021.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/022.vtt +17 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/023.vtt +17 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/024.vtt +13 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/025.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/026.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/027.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/028.vtt +9 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/01.mp4 +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/01.poster.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/02.mp4 +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/02.poster.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/03.mp4 +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/03.poster.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/04.mp4 +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/04.poster.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/01.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/01.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/02.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/02.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/03.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/03.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/04.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/04.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/05.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/05.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/06.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/06.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/07.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/07.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/08.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/08.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/09.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/09.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/10.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/10.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/11.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/11.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/12.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/12.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/13.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/13.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/14.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/14.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-2/01.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-2/01.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-3/01.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-3/01.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-4/01.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-4/01.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-5/01.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-5/01.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-6/01.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-6/01.webp +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-7/01.png +0 -0
- package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-7/01.webp +0 -0
- package/packages/visualizer/fixtures/full/specs/coffee/ordering/checkout.scxml +82 -0
- package/packages/visualizer/fixtures/full/specs/coffee/ordering/journeys.yaml +129 -0
- package/packages/visualizer/fixtures/full/specs/coffee/ordering/known-issues.md +14 -0
- package/packages/visualizer/fixtures/full/specs/coffee/ordering/machine.yaml +158 -0
- package/packages/visualizer/fixtures/full/specs/coffee/ordering/open-questions.md +25 -0
- package/packages/visualizer/fixtures/large/runs/2026-10-06T14-40-00-000Z-fast/ctrf.json +1280 -0
- package/packages/visualizer/fixtures/large/runs/2026-10-06T14-40-00-000Z-fast/junit.xml +26 -0
- package/packages/visualizer/fixtures/large/runs/2026-10-06T14-40-00-000Z-fast/manifest.json +28393 -0
- package/packages/visualizer/fixtures/large/specs/accounts/sign-up/identity-check.machine.yaml +397 -0
- package/packages/visualizer/fixtures/large/specs/accounts/sign-up/journeys.yaml +129 -0
- package/packages/visualizer/fixtures/large/specs/accounts/sign-up/machine.yaml +830 -0
- package/packages/visualizer/fixtures/large/specs/atlas.yaml +65 -0
- package/packages/visualizer/fixtures/large/specs/billing/invoices/journeys.yaml +132 -0
- package/packages/visualizer/fixtures/large/specs/billing/invoices/machine.yaml +830 -0
- package/packages/visualizer/fixtures/large/specs/billing/invoices/refund-handling.scxml +288 -0
- package/packages/visualizer/fixtures/large/specs/catalog/browsing/journeys.yaml +126 -0
- package/packages/visualizer/fixtures/large/specs/catalog/browsing/machine.yaml +831 -0
- package/packages/visualizer/fixtures/large/specs/catalog/browsing/product-comparison.machine.yaml +395 -0
- package/packages/visualizer/fixtures/large/specs/orders/checkout/journeys.yaml +120 -0
- package/packages/visualizer/fixtures/large/specs/orders/checkout/machine.yaml +724 -0
- package/packages/visualizer/fixtures/large/specs/orders/checkout/open-questions.md +16 -0
- package/packages/visualizer/fixtures/large/specs/orders/checkout/payment.scxml +288 -0
- package/packages/visualizer/fixtures/large/specs/shipping/deliveries/delivery-scheduling.machine.yaml +397 -0
- package/packages/visualizer/fixtures/large/specs/shipping/deliveries/journeys.yaml +132 -0
- package/packages/visualizer/fixtures/large/specs/shipping/deliveries/known-issues.md +13 -0
- package/packages/visualizer/fixtures/large/specs/shipping/deliveries/machine.yaml +830 -0
- package/packages/visualizer/fixtures/large/specs/support/tickets/escalation.machine.yaml +395 -0
- package/packages/visualizer/fixtures/large/specs/support/tickets/journeys.yaml +123 -0
- package/packages/visualizer/fixtures/large/specs/support/tickets/machine.yaml +720 -0
- package/packages/visualizer/fixtures/malformed/runs/2026-10-06T10-00-00-000Z-showcase/manifest.json +68 -0
- package/packages/visualizer/fixtures/malformed/runs/2026-10-06T11-00-00-000Z-showcase/ctrf.json +50 -0
- package/packages/visualizer/fixtures/malformed/runs/2026-10-06T11-00-00-000Z-showcase/junit.xml +6 -0
- package/packages/visualizer/fixtures/malformed/runs/2026-10-06T11-00-00-000Z-showcase/manifest.json +1281 -0
- package/packages/visualizer/fixtures/malformed/runs/2026-10-06T12-00-00-000Z-showcase/ctrf.json +50 -0
- package/packages/visualizer/fixtures/malformed/runs/2026-10-06T12-00-00-000Z-showcase/junit.xml +6 -0
- package/packages/visualizer/fixtures/malformed/runs/2026-10-06T12-00-00-000Z-showcase/manifest.json +1232 -0
- package/packages/visualizer/fixtures/malformed/runs/2026-10-06T13-00-00-000Z-showcase/manifest.json +1244 -0
- package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/checkout.scxml +82 -0
- package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/journeys.yaml +134 -0
- package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/known-issues.md +14 -0
- package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/loyalty.scxml +4 -0
- package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/machine.yaml +156 -0
- package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/open-questions.md +25 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/chart.mmd +67 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/ctrf.json +149 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/junit.xml +9 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/manifest.json +1718 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/001.vtt +9 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/002.vtt +17 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/003.vtt +17 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/004.vtt +9 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/005.vtt +9 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/01.mp4 +0 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/01.poster.webp +0 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/02.mp4 +0 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/02.poster.webp +0 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/03.mp4 +0 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/03.poster.webp +0 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/01.png +0 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/01.webp +0 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/02.png +0 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/02.webp +0 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/03.png +0 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/03.webp +0 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/05.png +0 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/05.webp +0 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-3/01.png +0 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-3/01.webp +0 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T15-05-00-000Z-showcase/media/paths/journey-1/00-start-01.png +0 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T15-05-00-000Z-showcase/media/paths/journey-1/00-start-01.webp +0 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T15-05-00-000Z-showcase/media/paths/journey-1/02.png +0 -0
- package/packages/visualizer/fixtures/partial/runs/2026-10-06T15-05-00-000Z-showcase/media/paths/journey-1/02.webp +0 -0
- package/packages/visualizer/fixtures/partial/specs/coffee/ordering/checkout.scxml +82 -0
- package/packages/visualizer/fixtures/partial/specs/coffee/ordering/journeys.yaml +129 -0
- package/packages/visualizer/fixtures/partial/specs/coffee/ordering/known-issues.md +14 -0
- package/packages/visualizer/fixtures/partial/specs/coffee/ordering/machine.yaml +158 -0
- package/packages/visualizer/fixtures/partial/specs/coffee/ordering/open-questions.md +25 -0
- package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/ctrf.json +79 -0
- package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/junit.xml +7 -0
- package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/manifest.json +1504 -0
- package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/001.vtt +9 -0
- package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/002.vtt +9 -0
- package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/003.vtt +9 -0
- package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/004.vtt +17 -0
- package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/01.mp4 +0 -0
- package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/01.poster.webp +0 -0
- package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/02.mp4 +0 -0
- package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/02.poster.webp +0 -0
- package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/01.png +0 -0
- package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/01.webp +0 -0
- package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/02.png +0 -0
- package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/02.webp +0 -0
- package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/03.png +0 -0
- package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/03.webp +0 -0
- package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/04.png +0 -0
- package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/04.webp +0 -0
- package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-2/01.png +0 -0
- package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-2/01.webp +0 -0
- package/packages/visualizer/fixtures/removed/specs/coffee/ordering/checkout.scxml +82 -0
- package/packages/visualizer/fixtures/removed/specs/coffee/ordering/journeys.yaml +129 -0
- package/packages/visualizer/fixtures/removed/specs/coffee/ordering/known-issues.md +14 -0
- package/packages/visualizer/fixtures/removed/specs/coffee/ordering/machine.yaml +158 -0
- package/packages/visualizer/fixtures/removed/specs/coffee/ordering/open-questions.md +25 -0
- package/packages/visualizer/fixtures/spec-only/runs/.gitkeep +0 -0
- package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/checkout.scxml +82 -0
- package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/journeys.yaml +129 -0
- package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/known-issues.md +14 -0
- package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/machine.yaml +158 -0
- package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/open-questions.md +25 -0
- package/packages/visualizer/index.html +13 -0
- package/packages/visualizer/scripts/make-fixtures.ts +1490 -0
- package/packages/visualizer/scripts/publish-data.ts +22 -0
- package/packages/visualizer/src/app/AppShell.tsx +56 -0
- package/packages/visualizer/src/app/atlas-context.tsx +23 -0
- package/packages/visualizer/src/app/gazetteer.module.css +97 -0
- package/packages/visualizer/src/app/gazetteer.tsx +105 -0
- package/packages/visualizer/src/app/report-sources.tsx +122 -0
- package/packages/visualizer/src/app/router.tsx +69 -0
- package/packages/visualizer/src/app/search-query.tsx +14 -0
- package/packages/visualizer/src/components/DataIssues.module.css +136 -0
- package/packages/visualizer/src/components/DataIssues.tsx +70 -0
- package/packages/visualizer/src/components/Header.module.css +189 -0
- package/packages/visualizer/src/components/Header.tsx +127 -0
- package/packages/visualizer/src/components/Legend.module.css +84 -0
- package/packages/visualizer/src/components/Legend.tsx +50 -0
- package/packages/visualizer/src/components/Screen.module.css +312 -0
- package/packages/visualizer/src/components/Screen.tsx +141 -0
- package/packages/visualizer/src/components/Status.module.css +116 -0
- package/packages/visualizer/src/components/Status.tsx +60 -0
- package/packages/visualizer/src/components/icons.tsx +156 -0
- package/packages/visualizer/src/components/labels.tsx +22 -0
- package/packages/visualizer/src/data/adapters/adapter.ts +112 -0
- package/packages/visualizer/src/data/adapters/context.tsx +11 -0
- package/packages/visualizer/src/data/adapters/index.ts +29 -0
- package/packages/visualizer/src/data/adapters/report-backend.test.ts +96 -0
- package/packages/visualizer/src/data/adapters/report-backend.ts +42 -0
- package/packages/visualizer/src/data/fixtures.test.ts +407 -0
- package/packages/visualizer/src/data/model/build.ts +418 -0
- package/packages/visualizer/src/data/model/event-kind.test.ts +59 -0
- package/packages/visualizer/src/data/model/event-kind.ts +54 -0
- package/packages/visualizer/src/data/model/index.ts +3 -0
- package/packages/visualizer/src/data/model/journeys.test.ts +159 -0
- package/packages/visualizer/src/data/model/journeys.ts +29 -0
- package/packages/visualizer/src/data/model/simulation.test.ts +115 -0
- package/packages/visualizer/src/data/model/simulation.ts +187 -0
- package/packages/visualizer/src/data/model/status.test.ts +34 -0
- package/packages/visualizer/src/data/model/status.ts +43 -0
- package/packages/visualizer/src/data/model/types.ts +280 -0
- package/packages/visualizer/src/data/parse/issues.test.ts +82 -0
- package/packages/visualizer/src/data/parse/issues.ts +114 -0
- package/packages/visualizer/src/data/parse/manifest.ts +173 -0
- package/packages/visualizer/src/data/parse/markdown.test.ts +119 -0
- package/packages/visualizer/src/data/parse/markdown.ts +133 -0
- package/packages/visualizer/src/data/parse/spec.test.ts +106 -0
- package/packages/visualizer/src/data/parse/spec.ts +557 -0
- package/packages/visualizer/src/data/parse/structured.ts +44 -0
- package/packages/visualizer/src/data/queries.ts +369 -0
- package/packages/visualizer/src/data/testing/load-fixture.ts +63 -0
- package/packages/visualizer/src/evidence/api.ts +41 -0
- package/packages/visualizer/src/evidence/check-detail.tsx +257 -0
- package/packages/visualizer/src/evidence/decision-table.tsx +68 -0
- package/packages/visualizer/src/evidence/document-page.tsx +40 -0
- package/packages/visualizer/src/evidence/evidence-context.tsx +159 -0
- package/packages/visualizer/src/evidence/evidence.module.css +877 -0
- package/packages/visualizer/src/evidence/feature-page.tsx +88 -0
- package/packages/visualizer/src/evidence/format.ts +56 -0
- package/packages/visualizer/src/evidence/gherkin.ts +98 -0
- package/packages/visualizer/src/evidence/marks.tsx +118 -0
- package/packages/visualizer/src/evidence/model-page.tsx +60 -0
- package/packages/visualizer/src/evidence/model-trace.tsx +57 -0
- package/packages/visualizer/src/evidence/overview.tsx +134 -0
- package/packages/visualizer/src/evidence/quint.ts +45 -0
- package/packages/visualizer/src/evidence/recording-page.tsx +69 -0
- package/packages/visualizer/src/evidence/recording.module.css +464 -0
- package/packages/visualizer/src/evidence/recording.tsx +197 -0
- package/packages/visualizer/src/evidence/snapshot.tsx +108 -0
- package/packages/visualizer/src/evidence/sources-panel.tsx +134 -0
- package/packages/visualizer/src/evidence/sources.module.css +168 -0
- package/packages/visualizer/src/evidence/spec-header.tsx +64 -0
- package/packages/visualizer/src/evidence/spec-index.tsx +82 -0
- package/packages/visualizer/src/evidence/spec-page.tsx +92 -0
- package/packages/visualizer/src/evidence/spec-snapshot.tsx +26 -0
- package/packages/visualizer/src/layout/graph.test.ts +113 -0
- package/packages/visualizer/src/layout/graph.ts +324 -0
- package/packages/visualizer/src/layout/layout.ts +237 -0
- package/packages/visualizer/src/layout/use-chart-layout.ts +18 -0
- package/packages/visualizer/src/main.tsx +31 -0
- package/packages/visualizer/src/map/ChartMap.tsx +252 -0
- package/packages/visualizer/src/map/EventEdge.tsx +138 -0
- package/packages/visualizer/src/map/map.module.css +546 -0
- package/packages/visualizer/src/map/nodes.tsx +145 -0
- package/packages/visualizer/src/map/path.ts +24 -0
- package/packages/visualizer/src/reachable.test.ts +54 -0
- package/packages/visualizer/src/spec-kind.test.ts +27 -0
- package/packages/visualizer/src/spec-kind.ts +56 -0
- package/packages/visualizer/src/state/ui-store.ts +44 -0
- package/packages/visualizer/src/styles/global.css +105 -0
- package/packages/visualizer/src/styles/tokens.css +80 -0
- package/packages/visualizer/src/views/ChartPage.tsx +52 -0
- package/packages/visualizer/src/views/ProductPage.tsx +35 -0
- package/packages/visualizer/src/views/SidePanel.tsx +339 -0
- package/packages/visualizer/src/views/views.module.css +546 -0
- package/packages/visualizer/vite/atlas-dev-plugin.ts +169 -0
- package/packages/visualizer/vite/atlas-files.test.ts +119 -0
- package/packages/visualizer/vite/atlas-files.ts +199 -0
- package/packages/visualizer/vite/publish.test.ts +52 -0
- package/packages/visualizer/vite/publish.ts +99 -0
- package/packages/visualizer/vite/reports-dev-plugin.ts +82 -0
- package/packages/visualizer/vite.config.ts +13 -0
- package/packages/vitest/README.md +58 -0
- package/packages/webdriver/README.md +77 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Clip } from './types.js';
|
|
2
|
+
export type FrameRecorderOptions = {
|
|
3
|
+
/** The image format `capture` returns (default png). */
|
|
4
|
+
extension?: 'png' | 'jpg';
|
|
5
|
+
/** Upper bound on frames per second (default 25). */
|
|
6
|
+
maxFps?: number;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Record a clip from any driver that can take a screenshot: capture frames back to back while the
|
|
10
|
+
* step runs, then encode them with FFmpeg as H.264 MP4 at their real timing. Drivers without a
|
|
11
|
+
* native screen recorder (Bun WebView, WebDriver) use it; it needs `ffmpeg` on the PATH and
|
|
12
|
+
* returns no clip without it.
|
|
13
|
+
*/
|
|
14
|
+
export declare function recordFrames(capture: () => Promise<Uint8Array>, workDirectory: string, options?: FrameRecorderOptions): Promise<{
|
|
15
|
+
stop(output: string): Promise<Clip | null>;
|
|
16
|
+
}>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
/**
|
|
5
|
+
* Record a clip from any driver that can take a screenshot: capture frames back to back while the
|
|
6
|
+
* step runs, then encode them with FFmpeg as H.264 MP4 at their real timing. Drivers without a
|
|
7
|
+
* native screen recorder (Bun WebView, WebDriver) use it; it needs `ffmpeg` on the PATH and
|
|
8
|
+
* returns no clip without it.
|
|
9
|
+
*/
|
|
10
|
+
export async function recordFrames(capture, workDirectory, options = {}) {
|
|
11
|
+
mkdirSync(workDirectory, { recursive: true });
|
|
12
|
+
const extension = options.extension ?? 'png';
|
|
13
|
+
const gapMs = 1000 / (options.maxFps ?? 25);
|
|
14
|
+
const started = Date.now();
|
|
15
|
+
const frames = [];
|
|
16
|
+
let stopped = false;
|
|
17
|
+
const loop = (async () => {
|
|
18
|
+
while (!stopped) {
|
|
19
|
+
const at = Date.now();
|
|
20
|
+
const bytes = await capture().catch(() => null);
|
|
21
|
+
if (bytes && bytes.length) {
|
|
22
|
+
const file = `${String(frames.length).padStart(5, '0')}.${extension}`;
|
|
23
|
+
writeFileSync(path.join(workDirectory, file), bytes);
|
|
24
|
+
frames.push({ file, atMs: at - started });
|
|
25
|
+
}
|
|
26
|
+
const wait = gapMs - (Date.now() - at);
|
|
27
|
+
if (wait > 0)
|
|
28
|
+
await new Promise((r) => setTimeout(r, wait));
|
|
29
|
+
}
|
|
30
|
+
})();
|
|
31
|
+
return {
|
|
32
|
+
async stop(output) {
|
|
33
|
+
stopped = true;
|
|
34
|
+
await loop;
|
|
35
|
+
const durationMs = Date.now() - started;
|
|
36
|
+
const last = frames.at(-1);
|
|
37
|
+
if (!last)
|
|
38
|
+
return null;
|
|
39
|
+
const list = frames
|
|
40
|
+
.map((frame, i) => `file '${frame.file}'\nduration ${(((frames[i + 1]?.atMs ?? durationMs) - frame.atMs) / 1000).toFixed(3)}`)
|
|
41
|
+
.concat(`file '${last.file}'`)
|
|
42
|
+
.join('\n');
|
|
43
|
+
const listFile = path.join(workDirectory, 'frames.txt');
|
|
44
|
+
writeFileSync(listFile, `${list}\n`);
|
|
45
|
+
mkdirSync(path.dirname(output), { recursive: true });
|
|
46
|
+
const encoded = spawnSync('ffmpeg', ['-y', '-loglevel', 'error', '-f', 'concat', '-safe', '0', '-i', listFile, '-vf', 'scale=trunc(iw/2)*2:trunc(ih/2)*2,format=yuv420p', '-c:v', 'libx264', '-r', '30', '-movflags', '+faststart', output], { stdio: ['ignore', 'ignore', 'pipe'] });
|
|
47
|
+
if (encoded.error || encoded.status !== 0)
|
|
48
|
+
return null;
|
|
49
|
+
return { video: output, durationMs };
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Driver, Timeline } from './types.js';
|
|
2
|
+
export type HttpResponse = {
|
|
3
|
+
status: number;
|
|
4
|
+
ok: boolean;
|
|
5
|
+
headers: Headers;
|
|
6
|
+
text: string;
|
|
7
|
+
json: unknown;
|
|
8
|
+
};
|
|
9
|
+
export type HttpRequestOptions = {
|
|
10
|
+
body?: unknown;
|
|
11
|
+
headers?: Record<string, string>;
|
|
12
|
+
/** What the timeline says this call was for; `METHOD /path` when omitted. */
|
|
13
|
+
label?: string;
|
|
14
|
+
};
|
|
15
|
+
/** What every event and recogniser receives from an HTTP client: a fetch with a base URL and a cookie jar. */
|
|
16
|
+
export type HttpClient = {
|
|
17
|
+
baseUrl: string;
|
|
18
|
+
/** Sent with every request; set an `authorization` header here after signing in. */
|
|
19
|
+
headers: Record<string, string>;
|
|
20
|
+
cookies: Map<string, string>;
|
|
21
|
+
request(method: string, path: string, options?: HttpRequestOptions): Promise<HttpResponse>;
|
|
22
|
+
get(path: string, options?: HttpRequestOptions): Promise<HttpResponse>;
|
|
23
|
+
post(path: string, body?: unknown, options?: HttpRequestOptions): Promise<HttpResponse>;
|
|
24
|
+
put(path: string, body?: unknown, options?: HttpRequestOptions): Promise<HttpResponse>;
|
|
25
|
+
patch(path: string, body?: unknown, options?: HttpRequestOptions): Promise<HttpResponse>;
|
|
26
|
+
delete(path: string, options?: HttpRequestOptions): Promise<HttpResponse>;
|
|
27
|
+
};
|
|
28
|
+
export type HttpDriverOptions = {
|
|
29
|
+
name?: string;
|
|
30
|
+
headers?: Record<string, string>;
|
|
31
|
+
/** Per request, in milliseconds (default 30 000). */
|
|
32
|
+
timeoutMs?: number;
|
|
33
|
+
};
|
|
34
|
+
export declare function httpClient(baseUrl: string, timeline: Timeline, options?: HttpDriverOptions): HttpClient;
|
|
35
|
+
/**
|
|
36
|
+
* The fastest driver: a client of an HTTP API, with no browser or device. Use it for actors that
|
|
37
|
+
* only talk to the system (a partner webhook, an operator API, a back office job) or to drive a
|
|
38
|
+
* whole chart at the API level. Each path attempt gets a fresh cookie jar; every call is logged to
|
|
39
|
+
* the step's timeline (method, path, status; never bodies).
|
|
40
|
+
*/
|
|
41
|
+
export declare function httpDriver(baseUrl: string | (() => string | Promise<string>), options?: HttpDriverOptions): Driver<HttpClient>;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
function parseBody(text, contentType) {
|
|
2
|
+
if (!text || !contentType || !/[/+]json\b/i.test(contentType))
|
|
3
|
+
return null;
|
|
4
|
+
try {
|
|
5
|
+
return JSON.parse(text);
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function httpClient(baseUrl, timeline, options = {}) {
|
|
12
|
+
const source = options.name ?? 'http';
|
|
13
|
+
const client = {
|
|
14
|
+
baseUrl,
|
|
15
|
+
headers: { ...options.headers },
|
|
16
|
+
cookies: new Map(),
|
|
17
|
+
async request(method, path, { body, headers, label } = {}) {
|
|
18
|
+
const url = new URL(path, baseUrl);
|
|
19
|
+
const cookie = [...client.cookies].map(([k, v]) => `${k}=${v}`).join('; ');
|
|
20
|
+
const init = {
|
|
21
|
+
method,
|
|
22
|
+
headers: {
|
|
23
|
+
...client.headers,
|
|
24
|
+
...(body !== undefined && typeof body !== 'string' ? { 'content-type': 'application/json' } : {}),
|
|
25
|
+
...(cookie ? { cookie } : {}),
|
|
26
|
+
...headers
|
|
27
|
+
},
|
|
28
|
+
signal: AbortSignal.timeout(options.timeoutMs ?? 30_000),
|
|
29
|
+
...(body !== undefined ? { body: typeof body === 'string' ? body : JSON.stringify(body) } : {})
|
|
30
|
+
};
|
|
31
|
+
const response = await fetch(url, init);
|
|
32
|
+
for (const line of response.headers.getSetCookie()) {
|
|
33
|
+
const [pair] = line.split(';');
|
|
34
|
+
const at = pair?.indexOf('=') ?? -1;
|
|
35
|
+
if (pair && at > 0)
|
|
36
|
+
client.cookies.set(pair.slice(0, at).trim(), pair.slice(at + 1).trim());
|
|
37
|
+
}
|
|
38
|
+
const text = await response.text();
|
|
39
|
+
timeline.add({
|
|
40
|
+
kind: 'system',
|
|
41
|
+
label: label ?? `${method} ${url.pathname} → ${response.status}`,
|
|
42
|
+
system: { source, endpoint: `${method} ${url.pathname}`, responseStatus: response.status }
|
|
43
|
+
});
|
|
44
|
+
return { status: response.status, ok: response.ok, headers: response.headers, text, json: parseBody(text, response.headers.get('content-type')) };
|
|
45
|
+
},
|
|
46
|
+
get: (path, o) => client.request('GET', path, o),
|
|
47
|
+
post: (path, body, o) => client.request('POST', path, { ...o, body }),
|
|
48
|
+
put: (path, body, o) => client.request('PUT', path, { ...o, body }),
|
|
49
|
+
patch: (path, body, o) => client.request('PATCH', path, { ...o, body }),
|
|
50
|
+
delete: (path, o) => client.request('DELETE', path, o)
|
|
51
|
+
};
|
|
52
|
+
return client;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The fastest driver: a client of an HTTP API, with no browser or device. Use it for actors that
|
|
56
|
+
* only talk to the system (a partner webhook, an operator API, a back office job) or to drive a
|
|
57
|
+
* whole chart at the API level. Each path attempt gets a fresh cookie jar; every call is logged to
|
|
58
|
+
* the step's timeline (method, path, status; never bodies).
|
|
59
|
+
*/
|
|
60
|
+
export function httpDriver(baseUrl, options = {}) {
|
|
61
|
+
return {
|
|
62
|
+
name: options.name ?? 'http',
|
|
63
|
+
concurrency: Number.POSITIVE_INFINITY,
|
|
64
|
+
async open({ timeline }) {
|
|
65
|
+
return httpClient(typeof baseUrl === 'function' ? await baseUrl() : baseUrl, timeline, options);
|
|
66
|
+
},
|
|
67
|
+
async close() {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import type { CloudEvent } from '../events/cloudevents.js';
|
|
2
|
+
import type { StateValue } from '../graph.js';
|
|
3
|
+
import type { PlannedPath } from '../plan.js';
|
|
4
|
+
export type RunMode = 'fast' | 'showcase';
|
|
5
|
+
export type Status = 'passed' | 'failed' | 'flaky' | 'not-reached';
|
|
6
|
+
export type EventKind = 'user' | 'system' | 'time' | 'hand-off';
|
|
7
|
+
/** `client` names which client's screen it is in a multi-client run; `also` holds the other clients' screens at the same moment. */
|
|
8
|
+
export type Image = {
|
|
9
|
+
png: string;
|
|
10
|
+
webp?: string;
|
|
11
|
+
client?: string;
|
|
12
|
+
also?: Image[];
|
|
13
|
+
};
|
|
14
|
+
export type Clip = {
|
|
15
|
+
video: string;
|
|
16
|
+
poster?: string;
|
|
17
|
+
durationMs: number;
|
|
18
|
+
client?: string;
|
|
19
|
+
};
|
|
20
|
+
export type TimelineEntry = {
|
|
21
|
+
atMs: number;
|
|
22
|
+
kind: 'tap' | 'type' | 'system' | 'screen' | 'toast' | 'note' | 'time' | 'notification';
|
|
23
|
+
label: string;
|
|
24
|
+
x?: number;
|
|
25
|
+
y?: number;
|
|
26
|
+
text?: string;
|
|
27
|
+
system?: {
|
|
28
|
+
source?: string;
|
|
29
|
+
endpoint?: string;
|
|
30
|
+
eventType?: string;
|
|
31
|
+
payload?: unknown;
|
|
32
|
+
responseStatus?: number;
|
|
33
|
+
};
|
|
34
|
+
/** The client that did it, in a multi-client run. */
|
|
35
|
+
client?: string;
|
|
36
|
+
};
|
|
37
|
+
type TimelineState = {
|
|
38
|
+
origin: number;
|
|
39
|
+
entries: TimelineEntry[];
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* What a step records while it runs: taps, typing, system calls, the screen change. `for(client)`
|
|
43
|
+
* returns a view onto the same timeline that tags every entry with that client.
|
|
44
|
+
*/
|
|
45
|
+
export declare class Timeline {
|
|
46
|
+
private readonly state;
|
|
47
|
+
readonly client: string | undefined;
|
|
48
|
+
constructor(state?: TimelineState, client?: string);
|
|
49
|
+
get entries(): TimelineEntry[];
|
|
50
|
+
restart(): void;
|
|
51
|
+
add(entry: Omit<TimelineEntry, 'atMs'>): void;
|
|
52
|
+
for(client: string): Timeline;
|
|
53
|
+
}
|
|
54
|
+
export type RecognizerResult = {
|
|
55
|
+
matched: boolean;
|
|
56
|
+
signals: {
|
|
57
|
+
signal: string;
|
|
58
|
+
expected: 'visible' | 'hidden' | string;
|
|
59
|
+
visible: boolean;
|
|
60
|
+
}[];
|
|
61
|
+
};
|
|
62
|
+
export type CheckResult = {
|
|
63
|
+
check: string;
|
|
64
|
+
passed: boolean;
|
|
65
|
+
expected?: string;
|
|
66
|
+
actual?: string;
|
|
67
|
+
};
|
|
68
|
+
/** Per-attempt tools handed to every implementation. */
|
|
69
|
+
export type StepTools = {
|
|
70
|
+
timeline: Timeline;
|
|
71
|
+
mode: RunMode;
|
|
72
|
+
/** Pause for the pacing of the current mode (no-op in fast mode for the default pauses). */
|
|
73
|
+
hold(ms: number): Promise<void>;
|
|
74
|
+
/** Scratch space shared by the events of one path attempt. */
|
|
75
|
+
data: Record<string, unknown>;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Which client a media hook should look at, in a multi-client run: the client a state is
|
|
79
|
+
* recognised on, or the client an event is done on. Single-client drivers ignore it.
|
|
80
|
+
*/
|
|
81
|
+
export type Focus = {
|
|
82
|
+
client?: string;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* A driver owns the thing under test for one path attempt: a browser context (Playwright), a
|
|
86
|
+
* device (Detox, WebDriver/Appium), a model or an API client. Only `open` and `close` are
|
|
87
|
+
* required; media hooks are used when present. `combineDrivers` runs several at once.
|
|
88
|
+
*/
|
|
89
|
+
export type Driver<C> = {
|
|
90
|
+
name: string;
|
|
91
|
+
open(input: {
|
|
92
|
+
path: PlannedPath;
|
|
93
|
+
attempt: number;
|
|
94
|
+
mode: RunMode;
|
|
95
|
+
directory: string;
|
|
96
|
+
timeline: Timeline;
|
|
97
|
+
}): Promise<C>;
|
|
98
|
+
close(ctx: C, input: {
|
|
99
|
+
failed: boolean;
|
|
100
|
+
traceFile: string;
|
|
101
|
+
}): Promise<{
|
|
102
|
+
trace?: string;
|
|
103
|
+
traces?: Record<string, string>;
|
|
104
|
+
} | void>;
|
|
105
|
+
/** A settled, deterministic screenshot of the current screen. */
|
|
106
|
+
screenshot?(ctx: C, file: string, focus?: Focus): Promise<Image | null>;
|
|
107
|
+
/** Start recording one transition; `stop` encodes it and returns the clip. */
|
|
108
|
+
record?(ctx: C, workDirectory: string, focus?: Focus): Promise<{
|
|
109
|
+
stop(output: string): Promise<Clip | null>;
|
|
110
|
+
}>;
|
|
111
|
+
/** Visible text of the screen, for the privacy scan (every client's screen when unfocused). */
|
|
112
|
+
text?(ctx: C, focus?: Focus): Promise<string>;
|
|
113
|
+
/** Pause between actions; drivers can show it (a touch overlay idling) or ignore it. */
|
|
114
|
+
hold?(ctx: C, ms: number, focus?: Focus): Promise<void>;
|
|
115
|
+
/** The clients of a multi-client driver, by name, with the driver each runs on. */
|
|
116
|
+
clients?: Record<string, string>;
|
|
117
|
+
/** Pacing for showcase mode, in milliseconds. */
|
|
118
|
+
pacing?: {
|
|
119
|
+
before: number;
|
|
120
|
+
after: number;
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* How many path attempts can have a context open at once (browser contexts are independent; a
|
|
124
|
+
* single device is not). Runs use at most this many workers; 1 when omitted.
|
|
125
|
+
*/
|
|
126
|
+
concurrency?: number;
|
|
127
|
+
dispose?(): Promise<void>;
|
|
128
|
+
};
|
|
129
|
+
/** How one event is made to happen. Keyed by the event's exact name in the spec. */
|
|
130
|
+
export type EventImplementation<C> = {
|
|
131
|
+
kind: EventKind;
|
|
132
|
+
/** The client that does it, in a multi-client run: its screen is recorded for the clip. */
|
|
133
|
+
client?: string;
|
|
134
|
+
/** A plain-language note on how the runner makes it happen (shown to developers). */
|
|
135
|
+
how: string;
|
|
136
|
+
/** Test data the event needs before the path starts (a condition modelled as an event). */
|
|
137
|
+
prepare?(ctx: C, tools: StepTools): Promise<void>;
|
|
138
|
+
run(ctx: C, tools: StepTools): Promise<void>;
|
|
139
|
+
/** Set when the event cannot be triggered reliably yet: the path stops before it. */
|
|
140
|
+
blocked?: string;
|
|
141
|
+
};
|
|
142
|
+
/** How one state is recognised from the outside, and what is checked there. */
|
|
143
|
+
export type StateImplementation<C> = {
|
|
144
|
+
recognize(ctx: C): Promise<RecognizerResult>;
|
|
145
|
+
/** The client whose screen shows it, in a multi-client run: that screen is the screenshot. */
|
|
146
|
+
client?: string;
|
|
147
|
+
/** Shown too briefly to wait for: not seeing it is not a failure. */
|
|
148
|
+
transient?: boolean;
|
|
149
|
+
/** States the UI cannot tell apart; never reported as "looks like" each other. */
|
|
150
|
+
sameAs?: string;
|
|
151
|
+
/** Where to look when the state changes off-screen (open a tab, reload). */
|
|
152
|
+
lookIn?(ctx: C): Promise<void>;
|
|
153
|
+
/** Within-state actions after the screenshot (dismiss a success message). */
|
|
154
|
+
settle?(ctx: C): Promise<void>;
|
|
155
|
+
checks?(ctx: C): Promise<CheckResult[]>;
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* Puts the system directly in one configuration of the chart (create the data, sign in, open the
|
|
159
|
+
* screen), so paths can start there instead of walking every step before it. A seed must leave
|
|
160
|
+
* the system exactly as the steps that lead there would: then results of the stretch before it
|
|
161
|
+
* and the stretch after it compose, and Atlas checks that by recognising the state both ways.
|
|
162
|
+
*/
|
|
163
|
+
export type Seed<C> = {
|
|
164
|
+
/** A state name (with the default configuration inside and beside it) or a full state value. */
|
|
165
|
+
at: string | StateValue;
|
|
166
|
+
/** A plain-language note on how the seed gets there (shown to developers). */
|
|
167
|
+
how: string;
|
|
168
|
+
run(ctx: C, input: {
|
|
169
|
+
path: PlannedPath;
|
|
170
|
+
tools: StepTools;
|
|
171
|
+
}): Promise<void>;
|
|
172
|
+
/**
|
|
173
|
+
* The state the seed leaves on screen, recognised before the first step. In a parallel state
|
|
174
|
+
* it says which region the seed opens. The state `at` names (or its active leaf), or the last
|
|
175
|
+
* active leaf, when omitted.
|
|
176
|
+
*/
|
|
177
|
+
shows?: string;
|
|
178
|
+
/**
|
|
179
|
+
* Events this seed exists for: a variant of a configuration (the same states, different data,
|
|
180
|
+
* such as a member at an address no lab serves). It starts only paths that take one of these
|
|
181
|
+
* events, and paths that take one start from a seed that lists it.
|
|
182
|
+
*/
|
|
183
|
+
for?: string[];
|
|
184
|
+
/** Set when the configuration cannot be seeded yet: paths start from another seed. */
|
|
185
|
+
blocked?: string;
|
|
186
|
+
};
|
|
187
|
+
export type Implementation<C> = {
|
|
188
|
+
events: Record<string, EventImplementation<C>>;
|
|
189
|
+
states: Record<string, StateImplementation<C>>;
|
|
190
|
+
/**
|
|
191
|
+
* Named seeds: configurations paths can start from. Journeys are cut at every seeded
|
|
192
|
+
* configuration they pass through, so each stretch runs on its own and in parallel.
|
|
193
|
+
*/
|
|
194
|
+
seeds?: Record<string, Seed<C>>;
|
|
195
|
+
/** Put the system in the scope's start configuration, for paths that start without a seed. */
|
|
196
|
+
setup?(ctx: C, input: {
|
|
197
|
+
path: PlannedPath;
|
|
198
|
+
tools: StepTools;
|
|
199
|
+
}): Promise<void>;
|
|
200
|
+
/** Whether `setup` can start a path in this configuration; a string is the reason it cannot. */
|
|
201
|
+
canStart?(active: string[]): true | string;
|
|
202
|
+
/**
|
|
203
|
+
* Ids that tell this attempt's business events from those of attempts running beside it (a
|
|
204
|
+
* user id, a trace id). Shared event sources keep only events and log lines that contain one.
|
|
205
|
+
*/
|
|
206
|
+
correlate?(ctx: C): string[] | Promise<string[]>;
|
|
207
|
+
};
|
|
208
|
+
/** Where business events come from: a CloudEvents endpoint, a log, a message queue. */
|
|
209
|
+
export type EventSource = {
|
|
210
|
+
name: string;
|
|
211
|
+
/** Where "now" is in the source; `collect` returns what arrived after this mark. */
|
|
212
|
+
mark(): unknown;
|
|
213
|
+
collect(mark?: unknown): Promise<{
|
|
214
|
+
events: CloudEvent[];
|
|
215
|
+
text?: string;
|
|
216
|
+
}>;
|
|
217
|
+
close?(): Promise<void>;
|
|
218
|
+
};
|
|
219
|
+
/** How a business event named in `meta.events` is recognised in what a source collected. */
|
|
220
|
+
export type EventMatcher = {
|
|
221
|
+
type: string;
|
|
222
|
+
} | {
|
|
223
|
+
pattern: RegExp;
|
|
224
|
+
} | ((events: CloudEvent[], text: string) => boolean);
|
|
225
|
+
export type PrivacyRules = {
|
|
226
|
+
/** Patterns that must never appear on screen or in a manifest. */
|
|
227
|
+
deny?: {
|
|
228
|
+
name: string;
|
|
229
|
+
pattern: RegExp;
|
|
230
|
+
}[];
|
|
231
|
+
/** Emails that may appear (synthetic domains, support addresses). */
|
|
232
|
+
allowEmails?: RegExp[];
|
|
233
|
+
/** Hosts the run may target; loopback only by default. */
|
|
234
|
+
allowHosts?: string[];
|
|
235
|
+
};
|
|
236
|
+
/**
|
|
237
|
+
* A driver for anything you can reach from Node: a domain model, an API client, a CLI. `create`
|
|
238
|
+
* returns a fresh context per path attempt; recognisers and events work on it directly.
|
|
239
|
+
*/
|
|
240
|
+
export declare function functionDriver<C>(create: (input: {
|
|
241
|
+
path: PlannedPath;
|
|
242
|
+
timeline: Timeline;
|
|
243
|
+
}) => C | Promise<C>, options?: {
|
|
244
|
+
name?: string;
|
|
245
|
+
dispose?: (ctx: C) => void | Promise<void>;
|
|
246
|
+
concurrency?: number;
|
|
247
|
+
}): Driver<C>;
|
|
248
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a step records while it runs: taps, typing, system calls, the screen change. `for(client)`
|
|
3
|
+
* returns a view onto the same timeline that tags every entry with that client.
|
|
4
|
+
*/
|
|
5
|
+
export class Timeline {
|
|
6
|
+
state;
|
|
7
|
+
client;
|
|
8
|
+
constructor(state = { origin: Date.now(), entries: [] }, client) {
|
|
9
|
+
this.state = state;
|
|
10
|
+
this.client = client;
|
|
11
|
+
}
|
|
12
|
+
get entries() {
|
|
13
|
+
return this.state.entries;
|
|
14
|
+
}
|
|
15
|
+
restart() {
|
|
16
|
+
this.state.origin = Date.now();
|
|
17
|
+
this.state.entries = [];
|
|
18
|
+
}
|
|
19
|
+
add(entry) {
|
|
20
|
+
this.state.entries.push({ atMs: Date.now() - this.state.origin, ...(this.client ? { client: this.client } : {}), ...entry });
|
|
21
|
+
}
|
|
22
|
+
for(client) {
|
|
23
|
+
return new Timeline(this.state, client);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A driver for anything you can reach from Node: a domain model, an API client, a CLI. `create`
|
|
28
|
+
* returns a fresh context per path attempt; recognisers and events work on it directly.
|
|
29
|
+
*/
|
|
30
|
+
export function functionDriver(create, options = {}) {
|
|
31
|
+
return {
|
|
32
|
+
name: options.name ?? 'function',
|
|
33
|
+
concurrency: options.concurrency ?? Number.POSITIVE_INFINITY,
|
|
34
|
+
open: ({ path, timeline }) => Promise.resolve(create({ path, timeline })),
|
|
35
|
+
close: async (ctx) => {
|
|
36
|
+
await options.dispose?.(ctx);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { StateImplementation } from './run/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* A UI signal: something visible (or not) that proves where the app is. Test IDs first, then
|
|
4
|
+
* accessible roles and names, then labels and text, as the Testing Library guidance orders them.
|
|
5
|
+
* The same values work with every driver that recognises screens by signals (Playwright, Bun
|
|
6
|
+
* WebView, WebDriver); each resolves them against its own UI tree.
|
|
7
|
+
*/
|
|
8
|
+
export type Signal = {
|
|
9
|
+
testId: string;
|
|
10
|
+
} | {
|
|
11
|
+
role: string;
|
|
12
|
+
name?: string | RegExp;
|
|
13
|
+
exact?: boolean;
|
|
14
|
+
} | {
|
|
15
|
+
text: string | RegExp;
|
|
16
|
+
exact?: boolean;
|
|
17
|
+
} | {
|
|
18
|
+
label: string | RegExp;
|
|
19
|
+
} | {
|
|
20
|
+
css: string;
|
|
21
|
+
};
|
|
22
|
+
export declare const testId: (id: string) => Signal;
|
|
23
|
+
export declare const text: (value: string | RegExp, options?: {
|
|
24
|
+
exact?: boolean;
|
|
25
|
+
}) => Signal;
|
|
26
|
+
export declare const role: (r: string, name?: string | RegExp, options?: {
|
|
27
|
+
exact?: boolean;
|
|
28
|
+
}) => Signal;
|
|
29
|
+
export declare const label: (value: string | RegExp) => Signal;
|
|
30
|
+
export declare const css: (selector: string) => Signal;
|
|
31
|
+
export declare function describeSignal(signal: Signal): string;
|
|
32
|
+
export type SignatureSpec<S = Signal> = {
|
|
33
|
+
all?: S[];
|
|
34
|
+
any?: S[];
|
|
35
|
+
none?: S[];
|
|
36
|
+
};
|
|
37
|
+
export type ScreenSpec<C, S = Signal> = SignatureSpec<S> & {
|
|
38
|
+
checks?: {
|
|
39
|
+
check: string;
|
|
40
|
+
signal: S;
|
|
41
|
+
}[];
|
|
42
|
+
transient?: boolean;
|
|
43
|
+
sameAs?: string;
|
|
44
|
+
lookIn?: (ctx: C) => Promise<void>;
|
|
45
|
+
settle?: (ctx: C) => Promise<void>;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Build `screen()` for a driver from one question: is this signal visible right now? A state is
|
|
49
|
+
* recognised when every `all` is visible, one `any` is visible and no `none` is. Drivers with
|
|
50
|
+
* their own locators (WebDriver's) pass their signal type and how to describe it.
|
|
51
|
+
*/
|
|
52
|
+
export declare function signatureScreen<C, S = Signal>(isVisible: (ctx: C, signal: S) => Promise<boolean>, describe: (signal: S) => string): (spec: ScreenSpec<C, S>) => StateImplementation<C>;
|
|
53
|
+
/**
|
|
54
|
+
* The driver-neutral surface of a screen: Playwright, Bun WebView and WebDriver (web and native)
|
|
55
|
+
* contexts all provide it, so an implementation written against it runs on any of them, and the
|
|
56
|
+
* clients of one run can use different drivers.
|
|
57
|
+
*/
|
|
58
|
+
export type SignalContext = {
|
|
59
|
+
/** Open a URL (a path resolves against the driver's base URL; a deep link in a native app). */
|
|
60
|
+
goto(url: string): Promise<void>;
|
|
61
|
+
isVisible(signal: Signal): Promise<boolean>;
|
|
62
|
+
user: {
|
|
63
|
+
tap(target: Signal, label: string): Promise<void>;
|
|
64
|
+
type(target: Signal, text: string, label: string): Promise<void>;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
/** A state recognised from signals on any driver that provides a `SignalContext`. */
|
|
68
|
+
export declare const screen: (spec: ScreenSpec<SignalContext, Signal>) => StateImplementation<SignalContext>;
|
|
69
|
+
type WireMatch = {
|
|
70
|
+
text: string;
|
|
71
|
+
exact: boolean;
|
|
72
|
+
} | {
|
|
73
|
+
regex: string;
|
|
74
|
+
flags: string;
|
|
75
|
+
};
|
|
76
|
+
export type WireSignal = {
|
|
77
|
+
kind: 'css';
|
|
78
|
+
selector: string;
|
|
79
|
+
} | {
|
|
80
|
+
kind: 'testId';
|
|
81
|
+
id: string;
|
|
82
|
+
} | {
|
|
83
|
+
kind: 'role';
|
|
84
|
+
role: string;
|
|
85
|
+
name: WireMatch | null;
|
|
86
|
+
} | {
|
|
87
|
+
kind: 'label';
|
|
88
|
+
match: WireMatch;
|
|
89
|
+
} | {
|
|
90
|
+
kind: 'text';
|
|
91
|
+
match: WireMatch;
|
|
92
|
+
};
|
|
93
|
+
/** A signal as JSON, for a probe that runs inside the page. */
|
|
94
|
+
export declare function toWire(signal: Signal): WireSignal;
|
|
95
|
+
/** Where a probe found a signal: whether it is visible, and the centre of the first visible match in CSS pixels. */
|
|
96
|
+
export type DomProbeResult = {
|
|
97
|
+
visible: boolean;
|
|
98
|
+
count: number;
|
|
99
|
+
x?: number;
|
|
100
|
+
y?: number;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* A function expression, as source, that finds a wire signal in a DOM: `(signal, scroll,
|
|
104
|
+
* withElement) => DomProbeResult`, plus the element itself when `withElement` is set (WebDriver
|
|
105
|
+
* returns it as an element reference). It is plain JavaScript so any driver can run it in a page (Bun WebView's
|
|
106
|
+
* `evaluate`, WebDriver's Execute Script). Roles follow the HTML-AAM implicit role mapping for the
|
|
107
|
+
* common elements; names follow aria-label, the associated label, then text content.
|
|
108
|
+
*/
|
|
109
|
+
export declare const DOM_PROBE = "(signal, scroll, withElement) => {\n const norm = (s) => String(s || '').replace(/\\s+/g, ' ').trim();\n const matches = (value, m) => (m.regex !== undefined ? new RegExp(m.regex, m.flags).test(value) : m.exact ? value === m.text : value.toLowerCase().includes(m.text.toLowerCase()));\n const shown = (el) => {\n const r = el.getBoundingClientRect();\n const st = getComputedStyle(el);\n return r.width > 0 && r.height > 0 && st.visibility !== 'hidden' && st.display !== 'none' && Number(st.opacity) !== 0;\n };\n const ROLES = {\n button: 'button,[role=button],input[type=button],input[type=submit],input[type=reset]',\n heading: 'h1,h2,h3,h4,h5,h6,[role=heading]',\n link: 'a[href],[role=link]',\n textbox: 'input:not([type]),input[type=text],input[type=email],input[type=tel],input[type=url],input[type=search],input[type=password],textarea,[role=textbox]',\n checkbox: 'input[type=checkbox],[role=checkbox]',\n radio: 'input[type=radio],[role=radio]',\n combobox: 'select,[role=combobox]',\n listitem: 'li,[role=listitem]',\n list: 'ul,ol,[role=list]',\n status: 'output,[role=status]',\n alert: '[role=alert]',\n dialog: 'dialog,[role=dialog]',\n img: 'img[alt],[role=img]'\n };\n const labelOf = (el) => norm(el.getAttribute('aria-label') || (el.labels && el.labels[0] ? el.labels[0].textContent : ''));\n const nameOf = (el) => labelOf(el) || norm(el.textContent) || norm(el.getAttribute('alt') || el.getAttribute('title') || el.getAttribute('placeholder') || (el.type === 'submit' || el.type === 'button' ? el.value : ''));\n const ownText = (el) => Array.from(el.childNodes).some((n) => n.nodeType === 3 && n.textContent.trim());\n let found = [];\n if (signal.kind === 'css') found = Array.from(document.querySelectorAll(signal.selector));\n else if (signal.kind === 'testId') found = Array.from(document.querySelectorAll('[data-testid=\"' + CSS.escape(signal.id) + '\"]'));\n else if (signal.kind === 'role') found = Array.from(document.querySelectorAll(ROLES[signal.role] || '[role=\"' + signal.role + '\"]')).filter((el) => !signal.name || matches(nameOf(el), signal.name));\n else if (signal.kind === 'label') found = Array.from(document.querySelectorAll('input,textarea,select,[aria-label]')).filter((el) => matches(labelOf(el), signal.match));\n else found = Array.from(document.querySelectorAll('body *')).filter((el) => ownText(el) && matches(norm(el.textContent), signal.match));\n const el = found.find(shown);\n if (!el) return { visible: false, count: found.length };\n if (scroll) el.scrollIntoView({ block: 'center', inline: 'center' });\n const r = el.getBoundingClientRect();\n const at = { visible: true, count: found.length, x: r.x + r.width / 2, y: r.y + r.height / 2 };\n return withElement ? Object.assign(at, { element: el }) : at;\n}";
|
|
110
|
+
export {};
|