@crvouga/atlas 0.3.0 → 0.5.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 +12 -0
- package/README.md +178 -604
- package/dist/bun/src/driver.d.ts +41 -7
- package/dist/bun/src/driver.js +47 -6
- package/dist/bun/src/index.d.ts +8 -0
- package/dist/bun/src/index.js +8 -0
- package/dist/core/src/cli.d.ts +14 -1
- package/dist/core/src/cli.js +30 -1
- package/dist/core/src/config.d.ts +70 -4
- package/dist/core/src/config.js +62 -3
- package/dist/core/src/events/cloudevents.d.ts +54 -9
- package/dist/core/src/events/cloudevents.js +60 -9
- package/dist/core/src/graph.d.ts +21 -0
- package/dist/core/src/graph.js +26 -0
- package/dist/core/src/index.d.ts +11 -0
- package/dist/core/src/index.js +11 -0
- package/dist/core/src/lint.d.ts +30 -0
- package/dist/core/src/lint.js +13 -0
- package/dist/core/src/plan.d.ts +39 -1
- package/dist/core/src/plan.js +28 -1
- package/dist/core/src/privacy.d.ts +29 -2
- package/dist/core/src/privacy.js +19 -2
- package/dist/core/src/report/formats.d.ts +34 -4
- package/dist/core/src/report/formats.js +24 -4
- package/dist/core/src/report/markdown.d.ts +15 -0
- package/dist/core/src/report/markdown.js +8 -0
- package/dist/core/src/run/clients.d.ts +44 -5
- package/dist/core/src/run/clients.js +46 -2
- package/dist/core/src/run/execute.d.ts +69 -16
- package/dist/core/src/run/execute.js +67 -16
- package/dist/core/src/run/frames.d.ts +13 -4
- package/dist/core/src/run/frames.js +19 -4
- package/dist/core/src/run/http.d.ts +34 -1
- package/dist/core/src/run/http.js +14 -1
- package/dist/core/src/run/types.d.ts +76 -3
- package/dist/core/src/run/types.js +19 -3
- package/dist/core/src/signals.d.ts +49 -5
- package/dist/core/src/signals.js +22 -5
- package/dist/core/src/spec/compose.d.ts +23 -1
- package/dist/core/src/spec/compose.js +10 -1
- package/dist/core/src/spec/index.d.ts +9 -1
- package/dist/core/src/spec/index.js +9 -1
- package/dist/core/src/spec/load.d.ts +22 -1
- package/dist/core/src/spec/load.js +31 -1
- package/dist/core/src/spec/parse.d.ts +16 -2
- package/dist/core/src/spec/parse.js +25 -2
- package/dist/core/src/spec/scxml.d.ts +25 -4
- package/dist/core/src/spec/scxml.js +36 -4
- package/dist/core/src/spec/types.d.ts +52 -1
- package/dist/core/src/spec/types.js +24 -0
- package/dist/detox/src/index.d.ts +54 -11
- package/dist/detox/src/index.js +45 -7
- package/dist/playwright/src/driver.d.ts +39 -3
- package/dist/playwright/src/driver.js +27 -3
- package/dist/playwright/src/index.d.ts +10 -0
- package/dist/playwright/src/index.js +10 -0
- package/dist/playwright/src/media.d.ts +50 -4
- package/dist/playwright/src/media.js +55 -4
- package/dist/playwright/src/signals.d.ts +44 -5
- package/dist/playwright/src/signals.js +29 -5
- package/dist/reports/src/attachment-files.d.ts +44 -0
- package/dist/reports/src/attachment-files.js +121 -0
- package/dist/reports/src/attachment-response.d.ts +31 -0
- package/dist/reports/src/attachment-response.js +55 -0
- package/dist/reports/src/aws-credentials.d.ts +48 -0
- package/dist/reports/src/aws-credentials.js +221 -0
- package/dist/reports/src/browser-navigation.d.ts +14 -0
- package/dist/reports/src/browser-navigation.js +7 -0
- package/dist/reports/src/bundle.d.ts +34 -2
- package/dist/reports/src/bundle.js +38 -2
- package/dist/reports/src/catalog.d.ts +34 -3
- package/dist/reports/src/catalog.js +17 -3
- package/dist/reports/src/cli-stores.d.ts +36 -0
- package/dist/reports/src/cli-stores.js +73 -0
- package/dist/reports/src/clock.d.ts +7 -2
- package/dist/reports/src/clock.js +5 -2
- package/dist/reports/src/completion-order.d.ts +18 -5
- package/dist/reports/src/completion-order.js +18 -5
- package/dist/reports/src/compose.d.ts +80 -0
- package/dist/reports/src/compose.js +117 -0
- package/dist/reports/src/copy-store.d.ts +29 -0
- package/dist/reports/src/copy-store.js +52 -0
- package/dist/reports/src/directory-outline.d.ts +38 -0
- package/dist/reports/src/directory-outline.js +103 -0
- package/dist/reports/src/directory-store.d.ts +20 -0
- package/dist/reports/src/directory-store.js +166 -0
- package/dist/reports/src/doctor.d.ts +29 -0
- package/dist/reports/src/doctor.js +83 -0
- package/dist/reports/src/effective-delta.d.ts +34 -0
- package/dist/reports/src/effective-delta.js +25 -0
- package/dist/reports/src/evidence-detail.d.ts +64 -0
- package/dist/reports/src/evidence-detail.js +92 -0
- package/dist/reports/src/evidence-live.d.ts +40 -4
- package/dist/reports/src/evidence-live.js +52 -4
- package/dist/reports/src/evidence-types.d.ts +70 -1
- package/dist/reports/src/evidence-types.js +5 -1
- package/dist/reports/src/evidence-view.d.ts +58 -6
- package/dist/reports/src/evidence-view.js +44 -5
- package/dist/reports/src/explorer-types.d.ts +40 -3
- package/dist/reports/src/explorer-types.js +8 -0
- package/dist/reports/src/explorer-versions.d.ts +9 -1
- package/dist/reports/src/explorer-versions.js +18 -1
- package/dist/reports/src/export-evidence.d.ts +16 -1
- package/dist/reports/src/export-evidence.js +52 -1
- package/dist/reports/src/fetcher.d.ts +27 -3
- package/dist/reports/src/fetcher.js +11 -3
- package/dist/reports/src/format-date.d.ts +6 -0
- package/dist/reports/src/format-date.js +6 -0
- package/dist/reports/src/format.d.ts +16 -0
- package/dist/reports/src/format.js +10 -0
- package/dist/reports/src/frames.d.ts +36 -3
- package/dist/reports/src/frames.js +22 -3
- package/dist/reports/src/hash.d.ts +18 -0
- package/dist/reports/src/hash.js +13 -0
- package/dist/reports/src/host.d.ts +29 -0
- package/dist/reports/src/host.js +64 -0
- package/dist/reports/src/html-frame.d.ts +5 -6
- package/dist/reports/src/html-frame.js +12 -1
- package/dist/reports/src/http-store.d.ts +52 -0
- package/dist/reports/src/http-store.js +145 -0
- package/dist/reports/src/http.d.ts +7 -0
- package/dist/reports/src/http.js +6 -0
- package/dist/reports/src/ingest.d.ts +54 -0
- package/dist/reports/src/ingest.js +210 -0
- package/dist/reports/src/init.d.ts +40 -0
- package/dist/reports/src/init.js +364 -0
- package/dist/reports/src/junit.d.ts +33 -6
- package/dist/reports/src/junit.js +87 -21
- package/dist/reports/src/keyboard.d.ts +20 -0
- package/dist/reports/src/keyboard.js +11 -0
- package/dist/reports/src/keys.d.ts +21 -3
- package/dist/reports/src/keys.js +21 -3
- package/dist/reports/src/layer-axes.d.ts +48 -0
- package/dist/reports/src/layer-axes.js +71 -0
- package/dist/reports/src/layer-catalog.d.ts +28 -1
- package/dist/reports/src/layer-catalog.js +19 -2
- package/dist/reports/src/layer-merge.d.ts +98 -9
- package/dist/reports/src/layer-merge.js +154 -33
- package/dist/reports/src/layer-source.d.ts +18 -0
- package/dist/reports/src/layer-source.js +14 -0
- package/dist/reports/src/layer-store.d.ts +42 -0
- package/dist/reports/src/layer-store.js +63 -5
- package/dist/reports/src/layer-types.d.ts +34 -1
- package/dist/reports/src/layers-route.d.ts +47 -4
- package/dist/reports/src/layers-route.js +88 -12
- package/dist/reports/src/media-types.d.ts +11 -0
- package/dist/reports/src/media-types.js +22 -0
- package/dist/reports/src/namespace-guard.d.ts +10 -1
- package/dist/reports/src/namespace-guard.js +10 -1
- package/dist/reports/src/navigation.d.ts +12 -0
- package/dist/reports/src/navigation.js +7 -0
- package/dist/reports/src/object-io.d.ts +11 -4
- package/dist/reports/src/object-io.js +4 -4
- package/dist/reports/src/object-store-conformance.d.ts +27 -0
- package/dist/reports/src/object-store-conformance.js +87 -0
- package/dist/reports/src/object-store.d.ts +33 -24
- package/dist/reports/src/object-store.js +17 -24
- package/dist/reports/src/parse-with.d.ts +16 -0
- package/dist/reports/src/parse-with.js +14 -0
- package/dist/reports/src/performance-part.d.ts +25 -1
- package/dist/reports/src/performance-part.js +15 -1
- package/dist/reports/src/performance.d.ts +22 -2
- package/dist/reports/src/performance.js +12 -2
- package/dist/reports/src/persist.d.ts +12 -3
- package/dist/reports/src/persist.js +12 -3
- package/dist/reports/src/phone.d.ts +18 -1
- package/dist/reports/src/phone.js +18 -1
- package/dist/reports/src/protocol.d.ts +30 -4
- package/dist/reports/src/protocol.js +15 -4
- package/dist/reports/src/publication.d.ts +21 -1
- package/dist/reports/src/publication.js +21 -1
- package/dist/reports/src/publish-checks.d.ts +35 -0
- package/dist/reports/src/publish-checks.js +122 -0
- package/dist/reports/src/publish.d.ts +44 -9
- package/dist/reports/src/publish.js +40 -7
- package/dist/reports/src/read.d.ts +46 -16
- package/dist/reports/src/read.js +38 -14
- package/dist/reports/src/recording-bundle.d.ts +13 -2
- package/dist/reports/src/recording-bundle.js +4 -2
- package/dist/reports/src/recording-keys.d.ts +15 -1
- package/dist/reports/src/recording-keys.js +15 -1
- package/dist/reports/src/remote-report.d.ts +28 -7
- package/dist/reports/src/remote-report.js +15 -7
- package/dist/reports/src/report-cli.d.ts +51 -0
- package/dist/reports/src/report-cli.js +485 -0
- package/dist/reports/src/report-index.d.ts +99 -0
- package/dist/reports/src/report-index.js +337 -0
- package/dist/reports/src/report-loader.d.ts +10 -0
- package/dist/reports/src/report-loader.js +6 -0
- package/dist/reports/src/report-parts.d.ts +29 -3
- package/dist/reports/src/report-parts.js +40 -3
- package/dist/reports/src/report-status.d.ts +48 -0
- package/dist/reports/src/report-status.js +156 -0
- package/dist/reports/src/report-types.d.ts +73 -0
- package/dist/reports/src/report-types.js +3 -0
- package/dist/reports/src/reporter.d.ts +67 -0
- package/dist/reports/src/reporter.js +128 -0
- package/dist/reports/src/reports-explorer-route.d.ts +541 -0
- package/dist/reports/src/reports-explorer-route.js +11 -0
- package/dist/reports/src/reports-list-route.d.ts +9 -0
- package/dist/reports/src/reports-list-route.js +9 -0
- package/dist/reports/src/reports-route.d.ts +561 -22
- package/dist/reports/src/reports-route.js +11 -3
- package/dist/reports/src/reports-store.d.ts +19 -2
- package/dist/reports/src/reports-store.js +10 -2
- package/dist/reports/src/resilient-cache.d.ts +14 -1
- package/dist/reports/src/resilient-cache.js +8 -1
- package/dist/reports/src/retention.d.ts +17 -1
- package/dist/reports/src/retention.js +5 -1
- package/dist/reports/src/run-bundle.d.ts +63 -0
- package/dist/reports/src/run-bundle.js +159 -0
- package/dist/reports/src/s3-store.d.ts +79 -0
- package/dist/reports/src/s3-store.js +295 -0
- package/dist/reports/src/scenario.d.ts +14 -4
- package/dist/reports/src/scenario.js +5 -4
- package/dist/reports/src/sigv4.d.ts +72 -0
- package/dist/reports/src/sigv4.js +96 -0
- package/dist/reports/src/snapshot-bundle.d.ts +24 -1
- package/dist/reports/src/snapshot-bundle.js +27 -2
- package/dist/reports/src/snapshot-surface.d.ts +20 -9
- package/dist/reports/src/snapshot-surface.js +32 -19
- package/dist/reports/src/source-content.d.ts +23 -0
- package/dist/reports/src/source-content.js +30 -1
- package/dist/reports/src/source-entries.d.ts +13 -0
- package/dist/reports/src/source-entries.js +6 -0
- package/dist/reports/src/source-part.d.ts +15 -0
- package/dist/reports/src/source-part.js +8 -0
- package/dist/reports/src/source-reader.d.ts +11 -0
- package/dist/reports/src/source-reader.js +5 -0
- package/dist/reports/src/spec-evidence.d.ts +12 -2
- package/dist/reports/src/spec-evidence.js +6 -2
- package/dist/reports/src/spec-inventory.d.ts +15 -1
- package/dist/reports/src/spec-inventory.js +22 -1
- package/dist/reports/src/spec-link.d.ts +28 -0
- package/dist/reports/src/spec-link.js +70 -0
- package/dist/reports/src/spec-set.d.ts +63 -0
- package/dist/reports/src/spec-set.js +177 -0
- package/dist/reports/src/status.d.ts +10 -0
- package/dist/reports/src/status.js +5 -0
- package/dist/reports/src/store-prefix.d.ts +28 -0
- package/dist/reports/src/store-prefix.js +22 -0
- package/dist/reports/src/store-url.d.ts +89 -0
- package/dist/reports/src/store-url.js +160 -0
- package/dist/reports/src/test-catalog-entity.d.ts +11 -0
- package/dist/reports/src/test-catalog-entity.js +6 -0
- package/dist/reports/src/types.d.ts +6 -1
- package/dist/reports/src/use-report-nav.d.ts +35 -0
- package/dist/reports/src/use-report-nav.js +12 -0
- package/dist/schema/src/api.d.ts +799 -0
- package/dist/schema/src/api.js +201 -0
- package/dist/schema/src/cli-results.d.ts +210 -0
- package/dist/schema/src/cli-results.js +124 -0
- package/dist/schema/src/common.d.ts +53 -0
- package/dist/schema/src/common.js +42 -0
- package/dist/schema/src/index.d.ts +14 -0
- package/dist/schema/src/index.js +14 -0
- package/dist/schema/src/layer.d.ts +2273 -0
- package/dist/schema/src/layer.js +462 -0
- package/dist/schema/src/manifest.d.ts +95 -0
- package/dist/schema/src/manifest.js +84 -0
- package/dist/schema/src/report-sources.d.ts +28 -0
- package/dist/schema/src/report-sources.js +25 -0
- package/dist/schema/src/runs-index.d.ts +16 -0
- package/dist/schema/src/runs-index.js +15 -0
- package/dist/schema/src/server-config.d.ts +93 -0
- package/dist/schema/src/server-config.js +73 -0
- package/dist/schema/src/spec.d.ts +69 -0
- package/dist/schema/src/spec.js +58 -0
- package/dist/server/src/app.d.ts +62 -0
- package/dist/server/src/app.js +419 -0
- package/dist/server/src/auth.d.ts +41 -0
- package/dist/server/src/auth.js +59 -0
- package/dist/server/src/config.d.ts +83 -0
- package/dist/server/src/config.js +187 -0
- package/dist/server/src/dev.d.ts +12 -0
- package/dist/server/src/dev.js +80 -0
- package/dist/server/src/events.d.ts +29 -0
- package/dist/server/src/events.js +101 -0
- package/dist/server/src/host.d.ts +30 -0
- package/dist/server/src/host.js +115 -0
- package/dist/server/src/index.d.ts +16 -0
- package/dist/server/src/index.js +16 -0
- package/dist/server/src/llms.d.ts +19 -0
- package/dist/server/src/llms.js +63 -0
- package/dist/server/src/main.d.ts +30 -0
- package/dist/server/src/main.js +112 -0
- package/dist/server/src/openapi.d.ts +59 -0
- package/dist/server/src/openapi.js +374 -0
- package/dist/server/src/problem.d.ts +8 -0
- package/dist/server/src/problem.js +39 -0
- package/dist/server/src/site.d.ts +13 -0
- package/dist/server/src/site.js +43 -0
- package/dist/server/src/store-api.d.ts +28 -0
- package/dist/server/src/store-api.js +159 -0
- package/dist/server/src/validate.d.ts +71 -0
- package/dist/server/src/validate.js +197 -0
- package/dist/vitest/src/index.d.ts +27 -5
- package/dist/vitest/src/index.js +18 -5
- package/dist/webdriver/src/driver.d.ts +63 -11
- package/dist/webdriver/src/driver.js +57 -6
- package/dist/webdriver/src/index.d.ts +8 -0
- package/dist/webdriver/src/index.js +1 -0
- package/dist/webdriver/src/protocol.d.ts +75 -6
- package/dist/webdriver/src/protocol.js +79 -6
- package/docs/agents.md +137 -0
- package/docs/deploying.md +345 -0
- package/docs/dogfooding.md +175 -0
- package/docs/extending.md +242 -0
- package/docs/integrating.md +485 -0
- package/docs/reference/bun.md +141 -0
- package/docs/reference/cli.md +146 -0
- package/docs/reference/core.md +2426 -0
- package/docs/reference/detox.md +150 -0
- package/docs/reference/http-api.md +303 -0
- package/docs/reference/playwright.md +303 -0
- package/docs/reference/reports.md +7098 -0
- package/docs/reference/schema.md +1651 -0
- package/docs/reference/server.md +685 -0
- package/docs/reference/vitest.md +45 -0
- package/docs/reference/webdriver.md +330 -0
- package/docs/report-backends.md +144 -0
- package/docs/report-contract.md +400 -0
- package/docs/reporting-issues.md +160 -0
- package/docs/server.md +285 -0
- package/docs/statecharts.md +641 -0
- package/llms-full.txt +3506 -0
- package/llms.txt +47 -0
- package/package.json +33 -5
- package/packages/core/README.md +2 -1
- package/packages/reports/README.md +69 -2
- package/packages/reports/STORAGE.md +5 -1
- package/packages/schema/README.md +14 -0
- package/packages/schema/schemas/check-detail.schema.json +1032 -0
- package/packages/schema/schemas/checks-result.schema.json +26 -0
- package/packages/schema/schemas/command-error.schema.json +35 -0
- package/packages/schema/schemas/doctor-result.schema.json +60 -0
- package/packages/schema/schemas/effective-delta.schema.json +490 -0
- package/packages/schema/schemas/effective-evidence.schema.json +471 -0
- package/packages/schema/schemas/evidence-page.schema.json +271 -0
- package/packages/schema/schemas/hello-event.schema.json +22 -0
- package/packages/schema/schemas/init-plan.schema.json +347 -0
- package/packages/schema/schemas/layer-rows.schema.json +199 -0
- package/packages/schema/schemas/layer.schema.json +2888 -0
- package/packages/schema/schemas/merge-result.schema.json +40 -0
- package/packages/schema/schemas/outline.schema.json +62 -0
- package/packages/schema/schemas/problem.schema.json +37 -0
- package/packages/schema/schemas/publish-checks.schema.json +1413 -0
- package/packages/schema/schemas/publish-result.schema.json +168 -0
- package/packages/schema/schemas/ready.schema.json +68 -0
- package/packages/schema/schemas/report-event.schema.json +100 -0
- package/packages/schema/schemas/report-status.schema.json +370 -0
- package/packages/schema/schemas/server-config.schema.json +194 -0
- package/packages/schema/schemas/server-info.schema.json +114 -0
- package/packages/schema/schemas/spec-set.schema.json +103 -0
- package/packages/schema/schemas/store-listing.schema.json +29 -0
- package/packages/schema/schemas/store-write-result.schema.json +28 -0
- package/packages/schema/schemas/stream-result.schema.json +59 -0
- package/packages/server/README.md +43 -0
- package/packages/server/openapi.json +6699 -0
- package/packages/visualizer/README.md +27 -5
- package/packages/visualizer/example/specs/coffee/ordering/cart.qnt +7 -0
- package/packages/visualizer/example/specs/coffee/ordering/checkout.openslo.yaml +10 -0
- package/packages/visualizer/example/specs/coffee/ordering/drink-price.dmn +24 -0
- package/packages/visualizer/example/specs/coffee/ordering/loyalty.feature +7 -0
- package/packages/visualizer/example/specs/coffee/ordering/ordering.feature +36 -0
- package/packages/visualizer/example/specs/coffee/ordering/payment.als +4 -0
- package/packages/visualizer/fixtures/failures/specs/coffee/ordering/cart.qnt +7 -0
- package/packages/visualizer/fixtures/failures/specs/coffee/ordering/checkout.openslo.yaml +10 -0
- package/packages/visualizer/fixtures/failures/specs/coffee/ordering/drink-price.dmn +24 -0
- package/packages/visualizer/fixtures/failures/specs/coffee/ordering/loyalty.feature +7 -0
- package/packages/visualizer/fixtures/failures/specs/coffee/ordering/ordering.feature +36 -0
- package/packages/visualizer/fixtures/failures/specs/coffee/ordering/payment.als +4 -0
- package/packages/visualizer/fixtures/full/specs/coffee/ordering/cart.qnt +7 -0
- package/packages/visualizer/fixtures/full/specs/coffee/ordering/checkout.openslo.yaml +10 -0
- package/packages/visualizer/fixtures/full/specs/coffee/ordering/drink-price.dmn +24 -0
- package/packages/visualizer/fixtures/full/specs/coffee/ordering/loyalty.feature +7 -0
- package/packages/visualizer/fixtures/full/specs/coffee/ordering/ordering.feature +36 -0
- package/packages/visualizer/fixtures/full/specs/coffee/ordering/payment.als +4 -0
- package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/cart.qnt +7 -0
- package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/checkout.openslo.yaml +10 -0
- package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/drink-price.dmn +24 -0
- package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/loyalty.feature +7 -0
- package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/ordering.feature +36 -0
- package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/payment.als +4 -0
- package/packages/visualizer/fixtures/partial/specs/coffee/ordering/cart.qnt +7 -0
- package/packages/visualizer/fixtures/partial/specs/coffee/ordering/checkout.openslo.yaml +10 -0
- package/packages/visualizer/fixtures/partial/specs/coffee/ordering/drink-price.dmn +24 -0
- package/packages/visualizer/fixtures/partial/specs/coffee/ordering/loyalty.feature +7 -0
- package/packages/visualizer/fixtures/partial/specs/coffee/ordering/ordering.feature +36 -0
- package/packages/visualizer/fixtures/partial/specs/coffee/ordering/payment.als +4 -0
- package/packages/visualizer/fixtures/removed/specs/coffee/ordering/cart.qnt +7 -0
- package/packages/visualizer/fixtures/removed/specs/coffee/ordering/checkout.openslo.yaml +10 -0
- package/packages/visualizer/fixtures/removed/specs/coffee/ordering/drink-price.dmn +24 -0
- package/packages/visualizer/fixtures/removed/specs/coffee/ordering/loyalty.feature +7 -0
- package/packages/visualizer/fixtures/removed/specs/coffee/ordering/ordering.feature +36 -0
- package/packages/visualizer/fixtures/removed/specs/coffee/ordering/payment.als +4 -0
- package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/cart.qnt +7 -0
- package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/checkout.openslo.yaml +10 -0
- package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/drink-price.dmn +24 -0
- package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/loyalty.feature +7 -0
- package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/ordering.feature +36 -0
- package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/payment.als +4 -0
- package/packages/visualizer/scripts/make-fixtures.ts +2 -0
- package/packages/visualizer/scripts/publish-data.ts +1 -2
- package/packages/visualizer/src/app/AppShell.tsx +9 -2
- package/packages/visualizer/src/app/report-sources.tsx +6 -4
- package/packages/visualizer/src/app/router.tsx +3 -3
- package/packages/visualizer/src/components/Header.module.css +35 -0
- package/packages/visualizer/src/components/Header.tsx +41 -4
- package/packages/visualizer/src/data/adapters/adapter.ts +5 -17
- package/packages/visualizer/src/data/adapters/index.ts +10 -1
- package/packages/visualizer/src/evidence/api.ts +14 -2
- package/packages/visualizer/src/evidence/artifacts.module.css +213 -0
- package/packages/visualizer/src/evidence/artifacts.tsx +272 -0
- package/packages/visualizer/src/evidence/check-detail.tsx +38 -4
- package/packages/visualizer/src/evidence/evidence-context.tsx +74 -12
- package/packages/visualizer/src/evidence/evidence.module.css +20 -0
- package/packages/visualizer/src/evidence/marks.tsx +2 -0
- package/packages/visualizer/src/evidence/overview.tsx +3 -3
- package/packages/visualizer/src/evidence/sources-panel.tsx +88 -34
- package/packages/visualizer/src/evidence/spec-page.tsx +23 -16
- package/packages/visualizer/src/find/Finder.tsx +1 -7
- package/packages/visualizer/src/find/open.ts +4 -0
- package/packages/visualizer/src/live/live-stream.ts +204 -0
- package/packages/visualizer/src/runtime.ts +19 -0
- package/packages/visualizer/src/state/ui-store.ts +6 -2
- package/packages/visualizer/vite/atlas-server-proxy.ts +36 -0
- package/packages/visualizer/vite/example-reports.ts +475 -0
- package/packages/visualizer/vite.config.ts +18 -2
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
# Integrating Atlas into a project
|
|
2
|
+
|
|
3
|
+
This guide takes a project from nothing to a layered, gated report of its specs. It is written for
|
|
4
|
+
people and for coding agents: every step ends with a command and the output that means it worked, so
|
|
5
|
+
an agent can follow it without asking anyone.
|
|
6
|
+
|
|
7
|
+
Atlas reports on **specs of any kind**: Gherkin features, Quint models, DMN tables, Alloy
|
|
8
|
+
structures, OpenSLO objectives, unit and end-to-end tests, linters, and statecharts that Atlas can run
|
|
9
|
+
itself. Anything that ends in "this check passed or failed" can publish a **layer**. Atlas lays the
|
|
10
|
+
layers over your specs, whatever produced them, whichever machine or branch they came from.
|
|
11
|
+
|
|
12
|
+
**The fast path:** `bunx @crvouga/atlas init --server <url>` detects your test runners, specs and CI and prints the exact
|
|
13
|
+
commands of this guide for your project (`--write` applies them; `--format json` is for agents). See
|
|
14
|
+
[Atlas for AI agents](agents.md). The rest of this guide explains what those commands do.
|
|
15
|
+
|
|
16
|
+
Read [the report contract](report-contract.md) once if you want the exact rules. You do not need it to
|
|
17
|
+
integrate. To run it for a whole team, with a bucket and one node everyone looks at, see
|
|
18
|
+
[running Atlas for a project](deploying.md). This guide ships with the package, matching your version, at
|
|
19
|
+
`node_modules/@crvouga/atlas/docs/integrating.md`.
|
|
20
|
+
|
|
21
|
+
> [!IMPORTANT]
|
|
22
|
+
> Install `@crvouga/atlas` from npm. Never edit Atlas from your project: no submodule, no vendored
|
|
23
|
+
> copy, no patch to `node_modules`. When Atlas is wrong or missing something, [file an
|
|
24
|
+
> issue](reporting-issues.md). See [dogfooding](dogfooding.md).
|
|
25
|
+
|
|
26
|
+
## How it fits together
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
node 1: suite A, ios ──▶ layer ─┐
|
|
30
|
+
node 2: suite A, android ──▶ layer ─┤ ┌──▶ atlas report status (gate: exit 1 on failure)
|
|
31
|
+
node 3: suite B, shard 1 ──▶ layer ─┼──▶ backends ──▶ combine ──┼──▶ the viewer (browse it)
|
|
32
|
+
node 4: suite B, shard 2 ──▶ layer ─┤ └──▶ your own code (combineBackends)
|
|
33
|
+
a laptop, one scenario ──▶ layer ─┘
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- Each run publishes **a layer**: only the checks it ran.
|
|
37
|
+
- Layers go to **backends**: a directory, a bucket, any store. Several backends are one report.
|
|
38
|
+
- The report is **computed** from all layers. The newest completed result wins each check, per
|
|
39
|
+
environment. Nothing is overwritten and nothing needs to coordinate.
|
|
40
|
+
|
|
41
|
+
That is why partial runs work: a shard, a branch, a re-run of one scenario or a device lab each add a
|
|
42
|
+
layer, and the report fills in.
|
|
43
|
+
|
|
44
|
+
## 1. Decide four things
|
|
45
|
+
|
|
46
|
+
| Decision | Rule of thumb | Example |
|
|
47
|
+
| --- | --- | --- |
|
|
48
|
+
| **Producers** | One per suite or tool. A short, stable, lowercase name. | `gherkin`, `web-e2e`, `quint`, `slo` |
|
|
49
|
+
| **Environments** | One per client you check on. Leave it out when there is only one. | `desktop-web`, `mobile-web`, `ios`, `android` |
|
|
50
|
+
| **Check ids** | Stable across runs, unique within a layer. Derive from file, suite and name. | `specs/join.feature > Joins a list` |
|
|
51
|
+
| **Backend** | A directory in CI artifacts to start. A shared bucket when reports must outlive a workflow. | `atlas-reports/` |
|
|
52
|
+
|
|
53
|
+
Check ids and producers are the identity of a result. If a check changes its id or a suite changes its
|
|
54
|
+
producer, the old result stays in the report next to the new one. Choose them once.
|
|
55
|
+
|
|
56
|
+
## 2. Install and check
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
bun add -d @crvouga/atlas # or: npm install -D @crvouga/atlas, pnpm add -D @crvouga/atlas
|
|
60
|
+
bunx atlas report --help # npx atlas report --help
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Expected: the usage text of `atlas report`. Atlas runs on Bun and on Node 22.18 or later. Add the
|
|
64
|
+
directory you publish to (`atlas-reports/`) to `.gitignore`.
|
|
65
|
+
|
|
66
|
+
## 3. Make each suite publish a layer
|
|
67
|
+
|
|
68
|
+
Pick the first row that fits.
|
|
69
|
+
|
|
70
|
+
| Your suite writes | Publish with |
|
|
71
|
+
| --- | --- |
|
|
72
|
+
| JUnit XML. Most runners can: Cucumber (`--format junit:out.xml`), Jest (jest-junit), Vitest (`--reporter=junit`), Bun (`--reporter=junit --reporter-outfile=out.xml`), pytest (`--junitxml`), `gotestsum --junitfile` | `--junit out.xml` |
|
|
73
|
+
| [CTRF](https://ctrf.io) JSON | `--ctrf ctrf.json` |
|
|
74
|
+
| An Atlas statechart run | `--manifest atlas-runs/<run>/manifest.json` |
|
|
75
|
+
| Nothing: a script, a model checker, a linter, an SLO evaluation | `--checks checks.json`, or `publishChecks` from code |
|
|
76
|
+
|
|
77
|
+
### From a report file
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
bunx atlas report publish --store atlas-reports --producer web-e2e --junit out.xml --environment desktop-web
|
|
81
|
+
# Published layer 3fa9c2d41b07: 42 checks (41 passed, 1 failed, 0 not run) as "web-e2e" on desktop-web
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`--sha`, `--branch` and `--run-url` are read from the CI's own variables (GitHub Actions, GitLab,
|
|
85
|
+
Buildkite, CircleCI) and then from git. Pass them to override. Outside a git checkout, or before the
|
|
86
|
+
first commit, they are `null`: that is provenance missing, not an error, and never changes which
|
|
87
|
+
result wins. `--param key=value` (repeatable) adds a parameter that makes a result its own slot, such
|
|
88
|
+
as `--param device=iphone-15`.
|
|
89
|
+
|
|
90
|
+
The time the checks ran comes from the report (CTRF `summary.stop`, a JUnit `timestamp`, a manifest's
|
|
91
|
+
`finishedAt`), or failing that from the report file's modification time, in milliseconds. Publish in
|
|
92
|
+
the same job that wrote the report and that is the time it ran. If you copy the report first, pass
|
|
93
|
+
`--recorded-at <iso|ms>`, which overrides both. Either way, publishing the same report twice writes
|
|
94
|
+
the same layer.
|
|
95
|
+
|
|
96
|
+
### Tell Atlas which spec a check belongs to
|
|
97
|
+
|
|
98
|
+
A test report rarely says which spec a test checks. Without that, results are counted but listed
|
|
99
|
+
under no spec. Say it once, per report:
|
|
100
|
+
|
|
101
|
+
| Flag | Meaning |
|
|
102
|
+
| --- | --- |
|
|
103
|
+
| `--spec specs/cart.feature` | Everything in this report checks that spec. Use it when you run one report per spec. |
|
|
104
|
+
| `--specs ./specs` | Atlas reads the spec files and links each check: by a path the report gives that is one of the specs; else by the suite, class or file name the report gives that matches a spec's title or file name (Cucumber names each suite after its feature); else by the part of the check's name before ` > `. |
|
|
105
|
+
|
|
106
|
+
A spec's **title**, which the name is matched against, is: the `Feature:` line of a `.feature` file,
|
|
107
|
+
the `module` name of a `.qnt` file, and the file name for everything else (`latency.openslo.yaml`).
|
|
108
|
+
Its file name without extensions matches too (`cart` for `specs/cart.feature`). Matching ignores case
|
|
109
|
+
and punctuation. If two specs share a title, the one whose path sorts first wins.
|
|
110
|
+
|
|
111
|
+
A check that matches nothing stays unlinked, never linked to a wrong spec. With either flag the layer
|
|
112
|
+
also records the spec and a fingerprint of its text, so a later reader can warn "spec changed since
|
|
113
|
+
this ran". A check file or code names the spec per check with `specPath`.
|
|
114
|
+
|
|
115
|
+
Specs that nothing has run yet are known from where Atlas is told the specs are: `--specs ./specs` on
|
|
116
|
+
`status`, or else the spec set that `publish --specs` put in the store (the newest from `main`), so a gate
|
|
117
|
+
needs no checkout. `atlas report status --store all` lists them in `specsWithoutEvidence`, and
|
|
118
|
+
`--require-all-specs` fails the gate until every spec has a result.
|
|
119
|
+
|
|
120
|
+
```sh
|
|
121
|
+
bunx atlas report publish --store atlas-reports --producer bdd --junit cucumber.xml --specs ./specs --environment ios
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### From nothing: a checks file
|
|
125
|
+
|
|
126
|
+
For specs no tool reports on, write what you verified:
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"producer": "slo",
|
|
131
|
+
"kind": "objective",
|
|
132
|
+
"environment": "desktop-web",
|
|
133
|
+
"recordedAtMs": 1760000000000,
|
|
134
|
+
"checks": [
|
|
135
|
+
{ "id": "specs/latency.openslo.yaml > p99 under 300ms", "title": "p99 under 300ms", "status": "passed",
|
|
136
|
+
"specPath": "specs/latency.openslo.yaml",
|
|
137
|
+
"measurements": [{ "name": "p99", "value": 212, "unit": "ms", "limit": 300 }] },
|
|
138
|
+
{ "id": "specs/latency.openslo.yaml > error budget", "title": "Error budget", "status": "failed",
|
|
139
|
+
"specPath": "specs/latency.openslo.yaml", "detail": "42% of the budget burned this week" }
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
```sh
|
|
145
|
+
bunx atlas report publish --store atlas-reports --checks checks.json
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
The file is a [`publish-checks`](../packages/schema/schemas/publish-checks.schema.json) document.
|
|
149
|
+
`status` is `passed`, `failed`, `running` or `not-run`. The `producer` can be in the file or on the
|
|
150
|
+
command line (`--producer`), and any other field may also be given as a flag, which wins.
|
|
151
|
+
`recordedAtMs` is when you ran the checks; without it the file's modification time is used.
|
|
152
|
+
|
|
153
|
+
Take `recordedAtMs` from the measurement itself, or from `Date.now()` in the script that measures. Do
|
|
154
|
+
not rely on a data file's modification time in CI: a fresh checkout stamps every file with the time of
|
|
155
|
+
the checkout, so an old number would look new and win over a genuinely newer layer.
|
|
156
|
+
|
|
157
|
+
Atlas records a status, it does not judge a measurement. A measurement over its `limit` is shown and
|
|
158
|
+
**never** fails a check by itself, so your script decides `status`. For an SLO, that is a comparison:
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
// scripts/slo-checks.ts
|
|
162
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
163
|
+
|
|
164
|
+
const metrics = JSON.parse(readFileSync('metrics.json', 'utf8'));
|
|
165
|
+
const limit = 300;
|
|
166
|
+
const spec = 'specs/latency.openslo.yaml';
|
|
167
|
+
writeFileSync('slo-checks.json', JSON.stringify({
|
|
168
|
+
producer: 'slo',
|
|
169
|
+
kind: 'objective',
|
|
170
|
+
environment: 'desktop-web',
|
|
171
|
+
recordedAtMs: metrics.measuredAtMs ?? Date.now(), // when the numbers were measured
|
|
172
|
+
checks: [{
|
|
173
|
+
id: `${spec} > checkout p99 under ${limit}ms`, title: `Checkout p99 under ${limit}ms`, specPath: spec,
|
|
174
|
+
status: metrics.checkout_p99_ms <= limit ? 'passed' : 'failed',
|
|
175
|
+
detail: `p99 was ${metrics.checkout_p99_ms}ms`,
|
|
176
|
+
measurements: [{ name: 'p99', value: metrics.checkout_p99_ms, unit: 'ms', limit }]
|
|
177
|
+
}]
|
|
178
|
+
}));
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### From code
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
import { directoryStore } from '@crvouga/atlas/reports/directory-store';
|
|
185
|
+
import { publishChecks } from '@crvouga/atlas/reports/publish-checks';
|
|
186
|
+
|
|
187
|
+
await publishChecks(directoryStore('atlas-reports'), {
|
|
188
|
+
producer: 'quint',
|
|
189
|
+
kind: 'model',
|
|
190
|
+
environment: 'desktop-web',
|
|
191
|
+
recordedAtMs: Date.now(), // when the checks ran
|
|
192
|
+
sha, branch, // provenance; never part of a result's identity
|
|
193
|
+
checks: results.map((r) => ({ id: `specs/booking.qnt > ${r.invariant}`, title: r.invariant, status: r.ok ? 'passed' : 'failed', specPath: 'specs/booking.qnt', detail: r.counterexample ?? '' }))
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
`publishChecks` validates its input and throws, naming each problem, before anything is written. It
|
|
198
|
+
returns the layer.
|
|
199
|
+
|
|
200
|
+
### Screenshots, videos, traces, logs and the rest
|
|
201
|
+
|
|
202
|
+
A result may carry any evidence your framework produces: attachments of any media type, a timeline of steps,
|
|
203
|
+
annotations, retries, tags and labels. Most of it arrives by itself (files a report names are read from its own
|
|
204
|
+
folder and from each `--attach-root`, never from elsewhere): a CTRF report's attachments, screenshots,
|
|
205
|
+
logs, steps and retries, and a JUnit report's output and properties, are published with the results. For the
|
|
206
|
+
rest, name files in a checks file (`"attachments": [{ "name": "failure.png", "path": "evidence/failure.png" }]`),
|
|
207
|
+
or attach files to the whole run:
|
|
208
|
+
|
|
209
|
+
```sh
|
|
210
|
+
bunx atlas report publish --producer e2e --junit out.xml --attach ci.log --attach trace=traces.zip --label build=4821
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Files are stored in the layer by content, shown by what they are (pictures, videos, page snapshots, text) and
|
|
214
|
+
offered for download otherwise. [Evidence](extending.md) is the full model, and why a new kind of evidence never
|
|
215
|
+
breaks anything.
|
|
216
|
+
|
|
217
|
+
### Statecharts
|
|
218
|
+
|
|
219
|
+
Atlas can also run statecharts against the real product (see [executable statecharts](statecharts.md)).
|
|
220
|
+
Publish each run, shard or re-run as its own layer:
|
|
221
|
+
|
|
222
|
+
```sh
|
|
223
|
+
bunx atlas run --config atlas.config.ts --shard 1/2
|
|
224
|
+
bunx atlas report publish --store atlas-reports --producer statecharts --environment desktop-web \
|
|
225
|
+
--manifest atlas-runs/<run>/manifest.json
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Do this instead of `atlas merge` when you also want the result to combine with other suites,
|
|
229
|
+
branches and environments. A path's `key` is its check id, so the same path in a later run replaces
|
|
230
|
+
the earlier result.
|
|
231
|
+
|
|
232
|
+
**Check:** `bunx atlas report status --store atlas-reports` prints `PASS …` (or `FAIL …` naming the
|
|
233
|
+
failing checks) and exits 0 or 1. If it prints `No checks were found`, the `--store` directory does not
|
|
234
|
+
contain `layers/` yet.
|
|
235
|
+
|
|
236
|
+
## 4. Build the report across nodes and branches
|
|
237
|
+
|
|
238
|
+
Every node publishes **its own** layers into **its own** store directory and uploads it. One job
|
|
239
|
+
downloads them all, and the gate reads the union. This is the whole GitHub Actions setup, for suites
|
|
240
|
+
of one kind on several nodes plus a producer that is not a test runner:
|
|
241
|
+
|
|
242
|
+
```yaml
|
|
243
|
+
name: specs
|
|
244
|
+
on: [push, pull_request]
|
|
245
|
+
|
|
246
|
+
jobs:
|
|
247
|
+
# One matrix entry per node. A node runs `run`, which writes JUnit XML to out.xml, and publishes it.
|
|
248
|
+
suite:
|
|
249
|
+
runs-on: ubuntu-latest
|
|
250
|
+
strategy:
|
|
251
|
+
fail-fast: false
|
|
252
|
+
matrix:
|
|
253
|
+
include:
|
|
254
|
+
- { name: cart-web, producer: unit, environment: desktop-web, run: bun test tests/cart.test.ts --reporter=junit --reporter-outfile=out.xml }
|
|
255
|
+
- { name: checkout-web, producer: unit, environment: desktop-web, run: bun test tests/checkout.test.ts --reporter=junit --reporter-outfile=out.xml }
|
|
256
|
+
- { name: e2e-ios, producer: e2e, environment: ios, run: ./scripts/e2e-ios --junit out.xml }
|
|
257
|
+
steps:
|
|
258
|
+
- uses: actions/checkout@v4
|
|
259
|
+
- uses: oven-sh/setup-bun@v2
|
|
260
|
+
- run: bun install --frozen-lockfile
|
|
261
|
+
- run: ${{ matrix.run }}
|
|
262
|
+
continue-on-error: true # a failing suite must still publish: a failure is evidence
|
|
263
|
+
- run: >
|
|
264
|
+
bunx atlas report publish --store store --producer ${{ matrix.producer }}
|
|
265
|
+
--junit out.xml --specs ./specs --environment ${{ matrix.environment }}
|
|
266
|
+
if: always()
|
|
267
|
+
- uses: actions/upload-artifact@v4
|
|
268
|
+
if: always()
|
|
269
|
+
with:
|
|
270
|
+
name: layers-${{ matrix.name }}
|
|
271
|
+
path: store
|
|
272
|
+
|
|
273
|
+
# Checks that no test runner reports: your script writes a checks file, Atlas publishes it.
|
|
274
|
+
slo:
|
|
275
|
+
runs-on: ubuntu-latest
|
|
276
|
+
steps:
|
|
277
|
+
- uses: actions/checkout@v4
|
|
278
|
+
- uses: oven-sh/setup-bun@v2
|
|
279
|
+
- run: bun install --frozen-lockfile
|
|
280
|
+
- run: bun scripts/slo-checks.ts # writes slo-checks.json
|
|
281
|
+
- run: bunx atlas report publish --store store --checks slo-checks.json
|
|
282
|
+
- uses: actions/upload-artifact@v4
|
|
283
|
+
with: { name: layers-slo, path: store }
|
|
284
|
+
|
|
285
|
+
# The aggregate: every node's layers, one gate.
|
|
286
|
+
report:
|
|
287
|
+
needs: [suite, slo]
|
|
288
|
+
if: always()
|
|
289
|
+
runs-on: ubuntu-latest
|
|
290
|
+
steps:
|
|
291
|
+
- uses: actions/checkout@v4
|
|
292
|
+
- uses: oven-sh/setup-bun@v2
|
|
293
|
+
- run: bun install --frozen-lockfile
|
|
294
|
+
- uses: actions/download-artifact@v4
|
|
295
|
+
with: { pattern: 'layers-*', path: all, merge-multiple: true } # directories merge: layers never collide
|
|
296
|
+
- run: bunx atlas report status --store all --specs ./specs --format markdown >> "$GITHUB_STEP_SUMMARY" || true
|
|
297
|
+
- run: bunx atlas report status --store all --specs ./specs --require-all-specs --require-environments desktop-web,ios
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
Each artifact is a store directory itself (it contains `layers/`), so `merge-multiple` into `all`
|
|
301
|
+
produces one store. A `--store` directory that does not exist is an error, not an empty store: a node
|
|
302
|
+
that failed to upload is noticed instead of silently contributing nothing.
|
|
303
|
+
|
|
304
|
+
To try it on one machine first, run the same steps by hand. A failing suite exits non-zero; publish
|
|
305
|
+
its report anyway.
|
|
306
|
+
|
|
307
|
+
```sh
|
|
308
|
+
bun test tests/cart.test.ts --reporter=junit --reporter-outfile=out/a.xml
|
|
309
|
+
bunx atlas report publish --store out/node-a --producer unit --junit out/a.xml --specs ./specs --environment desktop-web
|
|
310
|
+
bun test tests/checkout.test.ts --reporter=junit --reporter-outfile=out/b.xml
|
|
311
|
+
bunx atlas report publish --store out/node-b --producer unit --junit out/b.xml --specs ./specs --environment desktop-web
|
|
312
|
+
|
|
313
|
+
bunx atlas report merge --store out/node-a --store out/node-b --into out/all
|
|
314
|
+
bunx atlas report status --store out/all --specs ./specs --require-all-specs; echo "exit $?"
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Why this is safe to do in any shape:
|
|
318
|
+
|
|
319
|
+
- Layer files are named by their content. Two nodes cannot write different bytes to one name, so
|
|
320
|
+
merging directories (`merge-multiple`, `cp -R`, `rsync`, `atlas report merge`) is a plain union.
|
|
321
|
+
- Shards of one suite check different things, so they fill different slots and need no marker.
|
|
322
|
+
**Never** pass the shard, node or run number as a `--param`: every distinct parameter set is its own
|
|
323
|
+
slot, and shards are re-balanced between runs, so a stale result would sit beside the fresh one.
|
|
324
|
+
- Combining is incremental: `atlas report merge --into all` can reuse the same directory again and
|
|
325
|
+
again. It copies only what is missing, so a later run adds its layers and changes nothing else.
|
|
326
|
+
- A node that never publishes contributes nothing, and the gate cannot know what it should have run.
|
|
327
|
+
`--require-environments` catches an environment that is missing entirely. A node that publishes late
|
|
328
|
+
only adds its slots.
|
|
329
|
+
|
|
330
|
+
### Across runs and branches
|
|
331
|
+
|
|
332
|
+
Layers from another branch or an earlier run fill the same slots by recency. To let a pull request inherit
|
|
333
|
+
the unchanged results of `main`, put layers somewhere that outlives the workflow: **a bucket**. Every node
|
|
334
|
+
then publishes straight to it, with no artifacts to merge:
|
|
335
|
+
|
|
336
|
+
```sh
|
|
337
|
+
export ATLAS_STORE=s3://my-bucket/atlas/my-project # AWS credentials from a role, SSO or the environment
|
|
338
|
+
bunx atlas report publish --producer unit --junit out.xml --specs ./specs --environment desktop-web
|
|
339
|
+
bunx atlas report status --branch "$BRANCH" --branch main --ignore-modified --require-all-specs
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Developers publish from their laptops the same way, and `atlas serve` shows everyone the whole
|
|
343
|
+
project. Better still, point everything at the project's server (`ATLAS_STORE=https://atlas.example.com`,
|
|
344
|
+
`ATLAS_TOKEN=…`): the same commands upload to it, results are in everyone's view at once, `atlas report stream`
|
|
345
|
+
sends a suite's checks as they finish, and the gate is answered by the server. See [the Atlas server](server.md).
|
|
346
|
+
[Running Atlas for a project](deploying.md) is the full guide: the server, the bucket and its IAM policies,
|
|
347
|
+
CI with OIDC, auth and filters.
|
|
348
|
+
|
|
349
|
+
To fold a directory of layers (an artifact, a laptop's `atlas-reports/`) into the bucket after the fact:
|
|
350
|
+
`atlas report merge --store ./all --into s3://my-bucket/atlas/my-project`. It copies what is missing and is
|
|
351
|
+
safe to repeat; nothing is ever overwritten, so nothing is lost if two workflows copy at once.
|
|
352
|
+
|
|
353
|
+
## 5. Backends
|
|
354
|
+
|
|
355
|
+
A backend is any `ObjectStore`. Atlas ships two: a directory, and S3 (AWS S3, Cloudflare R2, MinIO and
|
|
356
|
+
anything else that speaks the S3 protocol, with no SDK). Name one with a URL, anywhere a `--store` goes:
|
|
357
|
+
|
|
358
|
+
| Store | URL |
|
|
359
|
+
| --- | --- |
|
|
360
|
+
| A folder | `./atlas-reports`, `/srv/atlas` |
|
|
361
|
+
| S3 | `s3://bucket/folder`, `s3://bucket/folder?region=eu-west-1` |
|
|
362
|
+
| R2, MinIO, others | `s3://bucket/folder?endpoint=https://…®ion=auto` |
|
|
363
|
+
|
|
364
|
+
Keys never go in the URL: they come from `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`, `aws sso login`, or
|
|
365
|
+
a role. `atlas report doctor --store <url>` checks a store end to end and says what is missing. From code:
|
|
366
|
+
`s3Store({ bucket, prefix, region, endpoint })` from `@crvouga/atlas/reports/s3-store`.
|
|
367
|
+
|
|
368
|
+
For any other store, implement `ObjectStore` (see [the report contract](report-contract.md#backends)) and
|
|
369
|
+
prove the adapter before trusting it:
|
|
370
|
+
|
|
371
|
+
```ts
|
|
372
|
+
import { verifyObjectStore } from '@crvouga/atlas/reports/object-store-conformance';
|
|
373
|
+
|
|
374
|
+
const { ok, failures } = await verifyObjectStore(myStore);
|
|
375
|
+
if (!ok) throw new Error(failures.join('\n'));
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
Combine any number of backends from code:
|
|
379
|
+
|
|
380
|
+
```ts
|
|
381
|
+
import { combineBackends } from '@crvouga/atlas/reports/compose';
|
|
382
|
+
import { reportStatus } from '@crvouga/atlas/reports/report-status';
|
|
383
|
+
import { s3Store } from '@crvouga/atlas/reports/s3-store';
|
|
384
|
+
|
|
385
|
+
const report = await combineBackends([
|
|
386
|
+
{ id: 'ci', label: 'CI', store: s3Store({ bucket: 'my-bucket', prefix: 'atlas/my-project' }) },
|
|
387
|
+
{ id: 'lab', label: 'Device lab', store: deviceLabStore() }
|
|
388
|
+
]);
|
|
389
|
+
const status = reportStatus(report, { requireEnvironments: ['ios'] }); // status.ok, status.failing, …
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
A backend that is down is named in `report.notices` and the rest is combined; the gate fails because
|
|
393
|
+
unknown is not a pass.
|
|
394
|
+
|
|
395
|
+
## 6. Browse it
|
|
396
|
+
|
|
397
|
+
The visualizer lays your stores over your specs directory. Add a module to your project:
|
|
398
|
+
|
|
399
|
+
```ts
|
|
400
|
+
// atlas.reports.ts
|
|
401
|
+
import { reportsHost } from '@crvouga/atlas/reports/host';
|
|
402
|
+
|
|
403
|
+
export const reportsDevFetch = reportsHost({ specs: './specs', stores: ['./atlas-reports', './all'] });
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
```sh
|
|
407
|
+
ATLAS_REPORTS_MODULE="$(pwd)/atlas.reports.ts" bunx atlas-visualizer dev --specs ./specs
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
`reportsHost(options)` returns `(request: Request, repoRoot: string) => Promise<Response>`, the
|
|
411
|
+
function the viewer calls for every `/api/reports/…` request. `specs` and directory `stores` resolve
|
|
412
|
+
against `repoRoot`, which the viewer sets to where you ran the command (`INIT_CWD`), not against the
|
|
413
|
+
module. A wrong path comes back as a JSON error that names it. A `stores` entry that is not a string is
|
|
414
|
+
a backend of your own: `{ id, label?, store }`. You can call it yourself to look at what the viewer
|
|
415
|
+
sees:
|
|
416
|
+
|
|
417
|
+
```ts
|
|
418
|
+
import { reportsDevFetch } from './atlas.reports';
|
|
419
|
+
|
|
420
|
+
const page = await (await reportsDevFetch(new Request('http://x/api/reports/evidence'), process.cwd())).json();
|
|
421
|
+
// page.layers: one header per layer (producer, environment, branch, sha, counts, backend), newest first
|
|
422
|
+
// page.backends, page.notices: which stores answered, and what could not be read
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
| Route (after `/api/reports`) | Returns |
|
|
426
|
+
| --- | --- |
|
|
427
|
+
| `/evidence?cursor=` | A page of layer headers, the backends and any notices. The viewer combines them with the specs. |
|
|
428
|
+
| `/evidence/rows/:backend/:id` | One layer's checks. |
|
|
429
|
+
| `/outline`, `/outline/spec?path=` | The specs directory as an outline, and one spec's text. |
|
|
430
|
+
|
|
431
|
+
The combined result of each spec is computed in the viewer. To get it without a browser, use
|
|
432
|
+
`atlas report status --format json`: its `specs` array has each spec's counts per environment.
|
|
433
|
+
|
|
434
|
+
Specs are the files of the specs directory (`.feature` as Gherkin, `.qnt` as Quint, `.dmn`, `.als`,
|
|
435
|
+
`.openslo.yaml`, and the rest by extension); each shows the combined result of its checks, per
|
|
436
|
+
environment, with the layer behind it. A check names its spec with `specPath`: the spec file's path
|
|
437
|
+
relative to the specs directory, with `specs/` in front, exactly as `atlas report status` prints it
|
|
438
|
+
(`specs/cart.feature` for `./specs/cart.feature`, `specs/billing/refunds.feature` for a nested one). Statecharts (`.scxml`, `.machine.yaml`) render as the product map; see the
|
|
439
|
+
[visualizer](../packages/visualizer/README.md).
|
|
440
|
+
|
|
441
|
+
## 7. Done when
|
|
442
|
+
|
|
443
|
+
An integration is complete when each of these holds. Run them and keep the output.
|
|
444
|
+
|
|
445
|
+
| Check | Command | Expect |
|
|
446
|
+
| --- | --- | --- |
|
|
447
|
+
| Each suite publishes | `bunx atlas report publish …` | `Published layer …: N checks` |
|
|
448
|
+
| Publishing twice changes nothing | run the same publish again, then `status --format json` | `layers` is unchanged |
|
|
449
|
+
| The report combines | `bunx atlas report status --store <dir> --format json` | `ok`, `checks.total` equal to the checks you run, `byEnvironment` listing every environment |
|
|
450
|
+
| Every spec has results | `status --specs ./specs --format json` | `specsWithoutEvidence` is empty, or lists only specs you have not run yet. `--require-all-specs` makes it a gate |
|
|
451
|
+
| A failure is caught | publish a failing check, run `status` | exit code 1, the check named |
|
|
452
|
+
| A fix clears it | publish the same check passing (a later `--recorded-at`), run `status` | exit code 0 |
|
|
453
|
+
| The gate is in CI | the `report` job above | red when a layer failed, red when an environment is missing |
|
|
454
|
+
| Code compiles | your usual type-check, if you import Atlas from code | no errors |
|
|
455
|
+
|
|
456
|
+
## Troubleshooting
|
|
457
|
+
|
|
458
|
+
| You see | Cause and fix |
|
|
459
|
+
| --- | --- |
|
|
460
|
+
| `No check has completed: everything was skipped or not run` | Every check in every layer is `not-run`. Skipped tests are not evidence: run them, or publish the ones that did run. |
|
|
461
|
+
| `No checks were found in any layer` | The `--store` directory is empty or is the wrong level. It must contain `layers/`. |
|
|
462
|
+
| Results show under no spec | The report did not say which spec each check belongs to. Pass `--spec <path>` or `--specs <dir>`, or give `specPath`. |
|
|
463
|
+
| An old result keeps showing | The new run used a different check id, producer, environment or parameter, so it filled another slot. Or its time is older: check `recordedAtMs` and `--recorded-at`. |
|
|
464
|
+
| The same check appears twice | Two environments, two parameter sets, or two kinds. That is by design; compare their layers. |
|
|
465
|
+
| One environment has no results | No layer from that environment reached the store. Add it to `--require-environments` so CI says so. |
|
|
466
|
+
| `Written with layer schema version 2…` | A newer Atlas wrote it. Upgrade `@crvouga/atlas` where you read it. |
|
|
467
|
+
| `a layer could not be read, so its outcome is unknown` | A corrupted or half-copied file. Re-run that node's publish and merge again. |
|
|
468
|
+
| `atlas report: Store directory not found` (exit 2) | A `--store` path does not exist. Check the path, and whether the server that should have produced it uploaded its layers. |
|
|
469
|
+
| `X is unavailable` | A backend is down. The rest were combined; fix it or leave it out. |
|
|
470
|
+
| `check id "…" appears twice` | Your suite emits two checks with one name. Make the names unique. Importers number repeats as `#2`. |
|
|
471
|
+
| `Potentially outdated: spec changed` | The spec changed since the layer was recorded. Advisory: the recorded outcome still counts. Re-run to refresh. |
|
|
472
|
+
| Viewer shows `No report store is configured` | `ATLAS_REPORTS_MODULE` is unset, or `stores` is empty. |
|
|
473
|
+
|
|
474
|
+
## Rules
|
|
475
|
+
|
|
476
|
+
- Publish even when the suite fails. A failure is the point of evidence.
|
|
477
|
+
- Take `recordedAtMs` from the run, not from the moment of publishing.
|
|
478
|
+
- Never rewrite or delete a layer by hand. Publish a newer one.
|
|
479
|
+
- Keep a check's id and a producer's name stable. Rename deliberately.
|
|
480
|
+
- Commit your specs, config and `atlas.reports.ts`. Do not commit `atlas-reports/` or `atlas-runs/`.
|
|
481
|
+
- Failure messages are published as written. Keep real personal data out of check ids, details and
|
|
482
|
+
parameters; a layer is meant to be shared. (Statechart runs are also scanned by Atlas's privacy
|
|
483
|
+
check.)
|
|
484
|
+
- Do not parse the text output of `atlas report status`. Use `--format json`, which is a
|
|
485
|
+
[stable schema](../packages/schema/schemas/report-status.schema.json).
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Reference: bun
|
|
2
|
+
|
|
3
|
+
The Bun WebView driver for statechart runs. Import path `@crvouga/atlas/bun`.
|
|
4
|
+
|
|
5
|
+
> Generated from the doc comments of `packages/bun/src` by `bun run docs`. Do not edit: change the comment next to the code.
|
|
6
|
+
|
|
7
|
+
### Bun WebView driver
|
|
8
|
+
|
|
9
|
+
Source: `packages/bun/src/driver.ts`
|
|
10
|
+
|
|
11
|
+
`bunWebViewDriver()` is the core `Driver` that runs a statechart's paths in Bun's built-in headless browser
|
|
12
|
+
(`Bun.WebView`), the quickest way to run a chart against a real page. It provides a `WebViewContext` whose
|
|
13
|
+
`user.tap` and `user.type` act on `Signal`s, found by the shared in-page DOM probe from core, so an implementation
|
|
14
|
+
written against `SignalContext` runs here and on the other web drivers unchanged. `Bun.WebView` is typed
|
|
15
|
+
structurally (`BunWebView`), so this package builds without Bun's types; at run time the Bun runtime is required.
|
|
16
|
+
|
|
17
|
+
See docs/statecharts.md
|
|
18
|
+
|
|
19
|
+
#### `BunWebView`
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
export type BunWebView = {
|
|
23
|
+
readonly url: string;
|
|
24
|
+
navigate(url: string): Promise<void>;
|
|
25
|
+
reload(): Promise<void>;
|
|
26
|
+
evaluate(script: string): Promise<unknown>;
|
|
27
|
+
screenshot(options?: { format?: 'png' | 'jpeg' | 'webp'; quality?: number; encoding?: 'buffer' }): Promise<Uint8Array>;
|
|
28
|
+
click(x: number, y: number): Promise<void>;
|
|
29
|
+
type(text: string): Promise<void>;
|
|
30
|
+
press(key: string, options?: { modifiers?: string[] }): Promise<void>;
|
|
31
|
+
resize(width: number, height: number): Promise<void>;
|
|
32
|
+
close(): void;
|
|
33
|
+
};
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The parts of `Bun.WebView` the driver uses, typed structurally so it builds without Bun's types.
|
|
37
|
+
|
|
38
|
+
#### `WebViewContext`
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
export type WebViewContext = SignalContext & {
|
|
42
|
+
view: BunWebView;
|
|
43
|
+
baseUrl: string | undefined;
|
|
44
|
+
/** Navigate, relative to `baseUrl`. */
|
|
45
|
+
goto(url: string): Promise<void>;
|
|
46
|
+
/** Run a JavaScript expression in the page and return its JSON result. */
|
|
47
|
+
evaluate(script: string): Promise<unknown>;
|
|
48
|
+
/** Where a signal is on screen right now. */
|
|
49
|
+
find(signal: Signal, options?: { scroll?: boolean }): Promise<DomProbeResult>;
|
|
50
|
+
user: {
|
|
51
|
+
tap(target: Signal, label: string): Promise<void>;
|
|
52
|
+
type(target: Signal, text: string, label: string): Promise<void>;
|
|
53
|
+
press(key: string, label?: string): Promise<void>;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
What every event and recogniser receives: the view, and paced user actions logged to the timeline.
|
|
59
|
+
|
|
60
|
+
#### `BunWebViewDriverOptions`
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
export type BunWebViewDriverOptions = {
|
|
64
|
+
/** Where `goto` paths resolve; the implementation's setup decides where to open. */
|
|
65
|
+
baseUrl?: string | (() => string | Promise<string>);
|
|
66
|
+
/** Viewport in CSS pixels; a 390×844 phone by default. */
|
|
67
|
+
width?: number;
|
|
68
|
+
height?: number;
|
|
69
|
+
/** `webkit` (macOS default, the system WKWebView) or `chrome` (CDP; the default elsewhere). */
|
|
70
|
+
backend?: 'webkit' | 'chrome';
|
|
71
|
+
/** How long a tap waits for its target to show, in milliseconds (default 10 000). */
|
|
72
|
+
actionTimeoutMs?: number;
|
|
73
|
+
/**
|
|
74
|
+
* Showcase pacing, in milliseconds: the hold before each event runs and after its state shows (default 400 and
|
|
75
|
+
* 900).
|
|
76
|
+
*/
|
|
77
|
+
pacing?: { before: number; after: number };
|
|
78
|
+
/** Views open at once (one per worker); 8 when omitted. */
|
|
79
|
+
concurrency?: number;
|
|
80
|
+
};
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Options of `bunWebViewDriver`; every field is optional.
|
|
84
|
+
|
|
85
|
+
#### `bunWebViewDriver`
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
export function bunWebViewDriver(options: BunWebViewDriverOptions = {}): Driver<WebViewContext>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Drives a web app in Bun's built-in headless browser for `atlas run`: the system WebKit on macOS (nothing to
|
|
92
|
+
install), Chrome over CDP elsewhere. A view starts in milliseconds and screenshots take about ten, so it is the
|
|
93
|
+
quickest way to run a chart against a real page. Each path attempt gets its own view, closed afterwards. Screenshots
|
|
94
|
+
are PNG files without a thumbnail. Clips are encoded from screenshots with FFmpeg (no clip is recorded without it).
|
|
95
|
+
`user.tap` and `user.type` wait up to `actionTimeoutMs` for the target signal to show, then click its centre; a
|
|
96
|
+
target that never shows fails the step with "<signal> is not on screen". Needs the Bun runtime (run
|
|
97
|
+
`bun --bun atlas run`), and throws on open without it. There is no fake clock, so time events use the app's own
|
|
98
|
+
controls.
|
|
99
|
+
|
|
100
|
+
See /statecharts.md
|
|
101
|
+
|
|
102
|
+
**Example**
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import { defineConfig } from '@crvouga/atlas';
|
|
106
|
+
import { bunWebViewDriver, screen, text } from '@crvouga/atlas/bun';
|
|
107
|
+
|
|
108
|
+
export default defineConfig({
|
|
109
|
+
specs: './specs',
|
|
110
|
+
driver: () => bunWebViewDriver({ baseUrl: 'http://127.0.0.1:4317' }),
|
|
111
|
+
implementation: {
|
|
112
|
+
async setup(ctx) { await ctx.goto('/'); },
|
|
113
|
+
events: {
|
|
114
|
+
// one entry per event of the spec
|
|
115
|
+
},
|
|
116
|
+
states: { 'No todos': screen({ all: [text('Nothing to do yet')] }) }
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
#### `screen`
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
export const screen = …
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Builds a state implementation for a `WebViewContext` from its signals in the page: every `all` signal visible, one
|
|
128
|
+
`any` signal visible (when given), no `none` signal visible. It is core's `signatureScreen` over `ctx.isVisible`, so
|
|
129
|
+
it takes the same spec as `screen` from `@crvouga/atlas/signals` (`checks`, `transient`, `sameAs`, `lookIn`,
|
|
130
|
+
`settle` included).
|
|
131
|
+
|
|
132
|
+
See /statecharts.md
|
|
133
|
+
|
|
134
|
+
### Bun WebView driver entry point (`@crvouga/atlas/bun`)
|
|
135
|
+
|
|
136
|
+
Source: `packages/bun/src/index.ts`. Import: `@crvouga/atlas/bun`
|
|
137
|
+
|
|
138
|
+
Re-exports the Bun WebView driver for statechart runs (`bunWebViewDriver`), its context and option types, `screen`
|
|
139
|
+
for recognising states from signals, and the signal constructors. Needs the Bun runtime.
|
|
140
|
+
|
|
141
|
+
See docs/statecharts.md
|