@crvouga/atlas 0.2.0 → 0.4.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 +13 -1
- package/README.md +21 -2
- package/dist/reports/src/evidence-live.d.ts +6 -0
- package/dist/reports/src/evidence-live.js +35 -3
- package/dist/reports/src/evidence-types.d.ts +2 -0
- package/dist/reports/src/evidence-view.d.ts +15 -2
- package/dist/reports/src/evidence-view.js +31 -3
- package/dist/reports/src/export-evidence.js +2 -10
- package/dist/reports/src/frames.d.ts +3 -1
- package/dist/reports/src/frames.js +21 -0
- package/dist/reports/src/layer-axes.d.ts +18 -0
- package/dist/reports/src/layer-axes.js +51 -0
- package/dist/reports/src/layer-catalog.js +1 -1
- package/dist/reports/src/layer-merge.d.ts +1 -1
- package/dist/reports/src/layer-merge.js +9 -4
- package/dist/reports/src/layer-source.js +3 -0
- package/dist/reports/src/layer-types.d.ts +2 -0
- package/dist/reports/src/layers-route.js +2 -5
- package/dist/reports/src/protocol.d.ts +4 -0
- package/dist/reports/src/publish.d.ts +2 -0
- package/dist/reports/src/publish.js +6 -11
- package/dist/reports/src/recording-keys.js +4 -0
- package/dist/reports/src/report-parts.js +3 -0
- package/dist/reports/src/report-types.d.ts +19 -2
- package/dist/reports/src/source-entries.js +2 -12
- package/package.json +5 -4
- package/packages/reports/README.md +4 -2
- package/packages/reports/STORAGE.md +1 -1
- package/packages/visualizer/README.md +9 -6
- 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 +11 -12
- package/packages/visualizer/src/app/gazetteer.module.css +12 -2
- package/packages/visualizer/src/app/gazetteer.tsx +38 -26
- package/packages/visualizer/src/components/Header.module.css +20 -4
- package/packages/visualizer/src/components/Header.tsx +7 -4
- package/packages/visualizer/src/data/model/build.ts +17 -5
- package/packages/visualizer/src/data/model/types.ts +10 -1
- package/packages/visualizer/src/evidence/api.ts +6 -1
- package/packages/visualizer/src/evidence/check-detail.tsx +35 -3
- 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/recording-page.tsx +19 -2
- package/packages/visualizer/src/evidence/recording.module.css +4 -8
- package/packages/visualizer/src/evidence/recording.tsx +74 -83
- package/packages/visualizer/src/evidence/snapshot.tsx +5 -4
- package/packages/visualizer/src/evidence/sources-panel.tsx +88 -34
- package/packages/visualizer/src/evidence/spec-index.tsx +3 -11
- package/packages/visualizer/src/find/Finder.module.css +168 -0
- package/packages/visualizer/src/find/Finder.tsx +303 -0
- package/packages/visualizer/src/find/corpus.test.ts +77 -0
- package/packages/visualizer/src/find/corpus.ts +368 -0
- package/packages/visualizer/src/find/open.ts +51 -0
- package/packages/visualizer/src/find/rank.test.ts +237 -0
- package/packages/visualizer/src/find/rank.ts +405 -0
- package/packages/visualizer/src/find/semantic.test.ts +62 -0
- package/packages/visualizer/src/find/semantic.ts +93 -0
- package/packages/visualizer/src/find/semantic.worker.ts +40 -0
- package/packages/visualizer/src/looks/Stage.tsx +322 -0
- package/packages/visualizer/src/looks/collect.test.ts +158 -0
- package/packages/visualizer/src/looks/collect.ts +245 -0
- package/packages/visualizer/src/looks/stage.module.css +300 -0
- package/packages/visualizer/src/reachable.test.ts +1 -1
- package/packages/visualizer/src/state/ui-store.ts +6 -2
- package/packages/visualizer/src/views/SidePanel.tsx +39 -49
- package/packages/visualizer/vite/example-reports.ts +475 -0
- package/packages/visualizer/vite.config.ts +9 -1
- package/packages/visualizer/src/app/search-query.tsx +0 -14
|
@@ -18,8 +18,12 @@ export type ReportPerformanceOptions = {
|
|
|
18
18
|
/** Diagnostic threshold, not a portable CPU or paint-time assertion. */
|
|
19
19
|
readonly slowStepMs: number;
|
|
20
20
|
};
|
|
21
|
-
/**
|
|
22
|
-
|
|
21
|
+
/**
|
|
22
|
+
* How a captured value is encoded on disk and rendered in the report.
|
|
23
|
+
* `png` is a still, `html` is a page snapshot, and `video` is an mp4 of the moment or the whole test.
|
|
24
|
+
* A runner may record any mix. The viewer treats a still, a video, and a timeline of frames as the same kind of evidence.
|
|
25
|
+
*/
|
|
26
|
+
export type SnapshotMedia = 'json' | 'html' | 'png' | 'text' | 'bytes' | 'video';
|
|
23
27
|
export type ReportStepStatus = 'passed' | 'failed';
|
|
24
28
|
/** Test outcome after the harness (e.g. the test runner) has weighed in. */
|
|
25
29
|
export type ReportTestStatus = 'passed' | 'failed' | 'skipped';
|
|
@@ -102,10 +106,23 @@ export type RunReportMeta = {
|
|
|
102
106
|
readonly error?: string;
|
|
103
107
|
readonly errorStack?: string;
|
|
104
108
|
};
|
|
109
|
+
/**
|
|
110
|
+
* A file attached to the whole test. A runner that can capture each step puts stills and page
|
|
111
|
+
* snapshots on `steps[].frames` instead, and the viewer builds a timeline from those. This list
|
|
112
|
+
* is for what the runner can attach when it cannot: a video of the test, a few screenshots, a log.
|
|
113
|
+
*/
|
|
114
|
+
export type ReportArtifact = {
|
|
115
|
+
readonly name: string;
|
|
116
|
+
readonly media: SnapshotMedia;
|
|
117
|
+
readonly file: string;
|
|
118
|
+
readonly poster?: string;
|
|
119
|
+
readonly captions?: string;
|
|
120
|
+
};
|
|
105
121
|
/** In-memory / persisted timeline for one test run. */
|
|
106
122
|
export type RunReport = {
|
|
107
123
|
readonly meta: RunReportMeta;
|
|
108
124
|
readonly steps: readonly ReportStep[];
|
|
125
|
+
readonly artifacts?: readonly ReportArtifact[];
|
|
109
126
|
};
|
|
110
127
|
export type SuiteTestSummary = {
|
|
111
128
|
readonly testId: string;
|
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
import { testFrameKey } from './recording-keys.js';
|
|
2
|
+
import { capturedFiles } from './frames.js';
|
|
2
3
|
import { remoteTestFileKey, remoteTestReportKey } from './keys.js';
|
|
3
4
|
const JSON_TYPE = 'application/json; charset=utf-8';
|
|
4
|
-
function frameFiles(steps, out) {
|
|
5
|
-
for (const step of steps) {
|
|
6
|
-
for (const frame of step.frames) {
|
|
7
|
-
for (const blob of frame.snapshots)
|
|
8
|
-
out.add(blob.file);
|
|
9
|
-
}
|
|
10
|
-
frameFiles(step.steps, out);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
5
|
export async function* sourceEntries(args, source, tests, runId) {
|
|
14
6
|
for (const { report } of [...tests].sort((a, b) => a.report.meta.testId < b.report.meta.testId ? -1 : 1)) {
|
|
15
7
|
const { testId } = report.meta;
|
|
@@ -18,9 +10,7 @@ export async function* sourceEntries(args, source, tests, runId) {
|
|
|
18
10
|
bytes: new TextEncoder().encode(JSON.stringify(report)),
|
|
19
11
|
contentType: JSON_TYPE,
|
|
20
12
|
};
|
|
21
|
-
const
|
|
22
|
-
frameFiles(report.steps, files);
|
|
23
|
-
for (const file of [...files].sort()) {
|
|
13
|
+
for (const file of capturedFiles(report).sort()) {
|
|
24
14
|
const obj = await args.local.get(testFrameKey(runId, testId, file));
|
|
25
15
|
if (obj === null)
|
|
26
16
|
throw new Error(`Missing report snapshot: ${file}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crvouga/atlas",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Atlas: executable statecharts. Spec a product's flows as statecharts, run them against the real app with any driver, and browse what happened.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
"test": "bun test && bun test --cwd packages/visualizer --preload ./tests/preload.ts tests",
|
|
108
108
|
"type-check": "for dir in packages/* scripts examples/todo; do tsc --noEmit -p \"$dir\" || exit 1; done",
|
|
109
109
|
"schemas": "bun packages/schema/scripts/emit-json-schemas.ts",
|
|
110
|
-
"viz:dev": "
|
|
110
|
+
"viz:dev": "bun packages/visualizer/bin/atlas-visualizer.mjs dev --specs \"$(pwd)/packages/visualizer/fixtures/full/specs\" --runs \"$(pwd)/packages/visualizer/fixtures/full/runs\"",
|
|
111
111
|
"viz:build": "cd packages/visualizer && INIT_CWD=\"$OLDPWD\" bun --bun vite build --configLoader runner",
|
|
112
112
|
"viz:publish-data": "bun packages/visualizer/scripts/publish-data.ts",
|
|
113
113
|
"viz:fixtures": "bun packages/visualizer/scripts/make-fixtures.ts",
|
|
@@ -115,11 +115,11 @@
|
|
|
115
115
|
"example:lint": "bun --cwd examples/todo ../../packages/core/bin/atlas.mjs lint --require-implementations",
|
|
116
116
|
"example:plan": "bun --cwd examples/todo ../../packages/core/bin/atlas.mjs plan",
|
|
117
117
|
"example:fast": "bun --cwd examples/todo ../../packages/core/bin/atlas.mjs run --mode fast",
|
|
118
|
-
"example:run": "bun
|
|
118
|
+
"example:run": "bun examples/todo/run-all.ts",
|
|
119
119
|
"example:clients": "bun --cwd examples/todo ../../packages/core/bin/atlas.mjs run --config clients/atlas.config.ts --mode showcase",
|
|
120
120
|
"example:clients:bun": "ATLAS_DESKTOP=bun bun --cwd examples/todo ../../packages/core/bin/atlas.mjs run --config clients/atlas.config.ts --mode showcase",
|
|
121
121
|
"atlas:run": "status=0; bun run example:clients || status=$?; bun run example:run || status=$?; exit $status",
|
|
122
|
-
"atlas:viz": "bun packages/visualizer/bin/atlas-visualizer.mjs dev --specs examples/todo/specs --runs examples/todo/atlas-runs",
|
|
122
|
+
"atlas:viz": "ATLAS_REPORTS_MODULE=\"$(pwd)/examples/todo/reports-dev.ts\" bun packages/visualizer/bin/atlas-visualizer.mjs dev --specs examples/todo/specs --runs examples/todo/atlas-runs",
|
|
123
123
|
"release:plan": "bun scripts/release/plan.ts",
|
|
124
124
|
"release:publish": "bun scripts/release/publish.ts",
|
|
125
125
|
"release:smoke": "bun scripts/release/consumer-smoke.ts",
|
|
@@ -171,6 +171,7 @@
|
|
|
171
171
|
"devDependencies": {
|
|
172
172
|
"@commitlint/cli": "19.8.1",
|
|
173
173
|
"@commitlint/config-conventional": "19.8.1",
|
|
174
|
+
"@informalsystems/quint": "^0.33.0",
|
|
174
175
|
"@types/bun": "1.4.3",
|
|
175
176
|
"@types/node": "^22.20.3",
|
|
176
177
|
"@types/react": "19.2.7",
|
|
@@ -10,11 +10,11 @@ The Atlas visualizer shows each kind of spec in its own tab, with every spec's r
|
|
|
10
10
|
|
|
11
11
|
## Combining evidence
|
|
12
12
|
|
|
13
|
-
Current specs define the outline. `combineEvidence` fills
|
|
13
|
+
Current specs define the outline. A layer is one focused recording: the checks it actually ran, on one environment, from one version and branch, in one store. `combineEvidence` fills the outline from every layer. The newest completed result wins only its own producer, check, environment and parameter set. Desktop web, mobile web, iOS and Android of the same check all stay visible, and any other recorded environment does too. A layer that ran one scenario leaves every other scenario as the newest layer that did run it, so the report fills without one suite that runs everything. Equal-time conflicts favor failure. Unfinished runs do not erase completed outcomes. Missing specs stay visible and removed specs retain their evidence outside the outline. `evidenceView` groups those results by check: the outcomes, the recorded timings that qualify them, and a summary per spec. A timing over its allowance never fails a check. `checkHistory` returns every layer's own record of one check, so a superseded result stays readable. Leaving a backend, an environment, a branch, a version or one layer out (`contributes`) is how earlier outcomes are inspected.
|
|
14
14
|
|
|
15
15
|
## Backends
|
|
16
16
|
|
|
17
|
-
`createReportsApp` combines layers from several stores. `localStore` is the backend `local` ("This machine"), `store` is `shared` ("Shared reports"), and `backends` adds any number of further named stores
|
|
17
|
+
`createReportsApp` combines layers from several stores. `localStore` is the backend `local` ("This machine"), `store` is `shared` ("Shared reports"), and `backends` adds any number of further named stores. A backend is any `ObjectStore`: the local disk, a shared bucket, S3, or a device lab. Every layer says which backend, version, branch and environment it came from. An unavailable backend is named in the page's notices and leaves the others usable; `GET /evidence?retry=1` asks it again without waiting.
|
|
18
18
|
|
|
19
19
|
| Route | Returns |
|
|
20
20
|
| --- | --- |
|
|
@@ -40,6 +40,8 @@ Freshness warnings preserve the recorded outcome. Changed spec fingerprints or r
|
|
|
40
40
|
|
|
41
41
|
Configure `ATLAS_REPORTS_MODULE` with a host composition module exporting `reportsDevFetch(request, repoRoot)`. Atlas's Vite middleware serves it at `/api/reports`, alongside specs and chart runs. `INIT_CWD` identifies the consuming repository. Credentials stay in that server module.
|
|
42
42
|
|
|
43
|
+
When that module is unset and the open specs are the coffee example or the todo example, the visualizer dev server serves an in-memory layered report for those documents instead. Any other spec set is left alone. The todo example's own module serves that same layered report and adds the desktop web layer `example:run` writes.
|
|
44
|
+
|
|
43
45
|
For a separately hosted reports API, set `VITE_ATLAS_REPORTS_URL` when building the visualizer. Otherwise a built site reads `data/evidence/`, populated with `exportEvidence`. Atlas still browses specs if evidence is absent.
|
|
44
46
|
|
|
45
47
|
## Verification
|
|
@@ -7,7 +7,7 @@ storage and time ports from its caller.
|
|
|
7
7
|
|
|
8
8
|
`layers/index/<inverted-time>-<digest>.json` discovers immutable manifests at `layers/manifests/<digest>.json`. Each records producer, origin, parameters, checks, spec fingerprints and a recording bundle. The manifest is written after its blobs and the index last. Distinct results at the same timestamp retain separate identities. Compressed blobs under `layers/blobs/` are addressed by content and reused across runs; ordinary source publication shares its bundle directly with its layer without recompressing snapshots.
|
|
9
9
|
|
|
10
|
-
Git commits are provenance and exact historical recording addresses, never a report partition. `combineEvidence` chooses completed
|
|
10
|
+
Git commits are provenance and exact historical recording addresses, never a report partition. `combineEvidence` chooses the newest completed result per check, environment and parameters, and keeps every other cell. An environment is the client that was checked (`desktop-web`, `mobile-web`, `ios`, `android`, or any other recorded name). The same check on two environments contributes twice. A layer that checks one scenario fills only that scenario. `publishSource` accepts `environment` and `parameters`, and a part may name its environment in `parameters.environment`. Inventory must be published before results for fingerprint comparison to be available.
|
|
11
11
|
|
|
12
12
|
## Commit inventory
|
|
13
13
|
|
|
@@ -11,7 +11,9 @@ reads two independent sources and works with whatever exists:
|
|
|
11
11
|
|
|
12
12
|
The explorer is one header, an open index and one plate. The index lists every place and journey of
|
|
13
13
|
the product; each kind of spec (Gherkin, Quint, DMN, Alloy, OpenSLO) has its own tab, with the
|
|
14
|
-
recorded result of every spec in its index.
|
|
14
|
+
recorded result of every spec in its index. The header finds a flow in ordinary language across
|
|
15
|
+
charts, specs and recorded runs. ⌘K (Ctrl+K on other keyboards) opens it, and `/` does the same
|
|
16
|
+
when you are not already typing. Local directories, published HTTP files and HTTP APIs
|
|
15
17
|
can supply reports simultaneously. Reports update through file watching, polling or server events.
|
|
16
18
|
Latest includes running reports; one unavailable backend leaves the others usable.
|
|
17
19
|
|
|
@@ -36,8 +38,8 @@ atlas-visualizer dev --specs ./specs --runs ./atlas-runs
|
|
|
36
38
|
| `--port <n>`, `--host <host>` | `dev`: where to listen (default `localhost:5180`, or the next free port). |
|
|
37
39
|
|
|
38
40
|
Relative paths resolve against the directory the command was run from. Without flags the
|
|
39
|
-
environment is read: `ATLAS_SPECS_ROOT
|
|
40
|
-
manager sets it to where you ran the command, or the current directory)
|
|
41
|
+
environment is read: `ATLAS_SPECS_ROOT` and `ATLAS_RUNS_ROOT` (relative to `INIT_CWD` when your package
|
|
42
|
+
manager sets it to where you ran the command, or the current directory). With nothing configured and no
|
|
41
43
|
`specs/` directory, the `full` example is shown.
|
|
42
44
|
|
|
43
45
|
Editing a spec file or a run publishing a snapshot updates the open page in about a second, without a reload,
|
|
@@ -60,8 +62,7 @@ sets how often the site checks for new runs (default 60 s, plus when the tab reg
|
|
|
60
62
|
### Inside this repository
|
|
61
63
|
|
|
62
64
|
```sh
|
|
63
|
-
bun run viz:dev #
|
|
64
|
-
ATLAS_FIXTURE=partial bun run viz:dev # one of the fixtures
|
|
65
|
+
bun run viz:dev # the full coffee example, charts and layered report
|
|
65
66
|
bun test packages/visualizer/src packages/visualizer/vite # parsing, composition, statuses, every fixture
|
|
66
67
|
bun run viz:fixtures # regenerate the fixtures (needs ImageMagick, cwebp, ffmpeg)
|
|
67
68
|
```
|
|
@@ -147,7 +148,9 @@ MIT
|
|
|
147
148
|
|
|
148
149
|
Beside the statechart map, every other kind of spec has its own tab: Gherkin features, Quint models, DMN decision tables, Alloy structures and OpenSLO objectives. A tab appears when the specs folder has files of its kind. The index lists every spec with what was recorded for it, and filters to those with results, those failing, or those with none. A spec page shows each scenario, trace or check with its outcome; opening one shows the recorded steps, the error, the timings, every other run of the same check, and its recording.
|
|
149
150
|
|
|
150
|
-
Results come from the Atlas reports API (`/api/reports` in dev, `VITE_ATLAS_REPORTS_URL` when hosted elsewhere) or from a static `data/evidence` export. They combine across backends, branches and
|
|
151
|
+
Results come from the Atlas reports API (`/api/reports` in dev, `VITE_ATLAS_REPORTS_URL` when hosted elsewhere) or from a static `data/evidence` export. They combine across backends, branches, versions, environments and layers; **Sources** in the header switches any of them off. While a spec suite is running, the header says so and each finished test appears within a couple of seconds. See [Atlas reports](../reports/README.md) for the API and host configuration.
|
|
152
|
+
|
|
153
|
+
The coffee example ships those documents and a layered report. `bun run viz:dev` opens that full example, and the same report is the fallback when a working directory has no `specs/` and `ATLAS_REPORTS_MODULE` is unset. `atlas:viz` serves the same kind of report for the todo example, and adds the desktop web layer `example:run` writes. Each built-in report is five layers: an older desktop web run, a mobile web branch, Android from a device lab, a focused iOS run, and a newer desktop web run that repeated one scenario. The same check stays visible on each environment. A feature with no layer stays empty.
|
|
151
154
|
|
|
152
155
|
The header title is the product's name, taken from `atlas.yaml`'s `title` up to its first dash or colon, or "Atlas".
|
|
153
156
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<definitions xmlns="https://www.omg.org/spec/DMN/20191111/MODEL/">
|
|
3
|
+
<decision id="drink-price" name="Drink price">
|
|
4
|
+
<decisionTable id="Drink price" hitPolicy="UNIQUE">
|
|
5
|
+
<input label="Size">
|
|
6
|
+
<inputExpression typeRef="string"><text>size</text></inputExpression>
|
|
7
|
+
</input>
|
|
8
|
+
<input label="Milk">
|
|
9
|
+
<inputExpression typeRef="string"><text>milk</text></inputExpression>
|
|
10
|
+
</input>
|
|
11
|
+
<output label="Price" name="price" />
|
|
12
|
+
<rule>
|
|
13
|
+
<inputEntry><text>"Small"</text></inputEntry>
|
|
14
|
+
<inputEntry><text>"None"</text></inputEntry>
|
|
15
|
+
<outputEntry><text>3</text></outputEntry>
|
|
16
|
+
</rule>
|
|
17
|
+
<rule>
|
|
18
|
+
<inputEntry><text>"Large"</text></inputEntry>
|
|
19
|
+
<inputEntry><text>"Oat"</text></inputEntry>
|
|
20
|
+
<outputEntry><text>5</text></outputEntry>
|
|
21
|
+
</rule>
|
|
22
|
+
</decisionTable>
|
|
23
|
+
</decision>
|
|
24
|
+
</definitions>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
Feature: Order a drink
|
|
2
|
+
A customer picks a drink, pays, and picks it up.
|
|
3
|
+
|
|
4
|
+
Rule: Paying for the order
|
|
5
|
+
|
|
6
|
+
Scenario: Pays by card
|
|
7
|
+
Given a drink in the cart
|
|
8
|
+
When the customer pays by card
|
|
9
|
+
Then the barista can start the drink
|
|
10
|
+
|
|
11
|
+
Scenario: Pays with a wallet
|
|
12
|
+
Given a drink in the cart
|
|
13
|
+
When the customer pays with a wallet
|
|
14
|
+
Then the order is paid
|
|
15
|
+
|
|
16
|
+
Scenario: Card declined, then a wallet works
|
|
17
|
+
Given a drink in the cart
|
|
18
|
+
When the card is declined
|
|
19
|
+
And the customer pays with a wallet
|
|
20
|
+
Then the order is paid
|
|
21
|
+
|
|
22
|
+
Scenario: Slow payment
|
|
23
|
+
Given a drink in the cart
|
|
24
|
+
When the payment takes longer than a minute
|
|
25
|
+
Then the customer can check the payment again
|
|
26
|
+
|
|
27
|
+
Scenario: Leaves checkout and comes back
|
|
28
|
+
Given a drink in the cart
|
|
29
|
+
When the customer closes checkout
|
|
30
|
+
And the customer starts checkout again
|
|
31
|
+
Then checkout is open
|
|
32
|
+
|
|
33
|
+
Scenario: Drink left too long
|
|
34
|
+
Given a finished drink
|
|
35
|
+
When nobody picks it up
|
|
36
|
+
Then the drink is thrown away and refunded
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<definitions xmlns="https://www.omg.org/spec/DMN/20191111/MODEL/">
|
|
3
|
+
<decision id="drink-price" name="Drink price">
|
|
4
|
+
<decisionTable id="Drink price" hitPolicy="UNIQUE">
|
|
5
|
+
<input label="Size">
|
|
6
|
+
<inputExpression typeRef="string"><text>size</text></inputExpression>
|
|
7
|
+
</input>
|
|
8
|
+
<input label="Milk">
|
|
9
|
+
<inputExpression typeRef="string"><text>milk</text></inputExpression>
|
|
10
|
+
</input>
|
|
11
|
+
<output label="Price" name="price" />
|
|
12
|
+
<rule>
|
|
13
|
+
<inputEntry><text>"Small"</text></inputEntry>
|
|
14
|
+
<inputEntry><text>"None"</text></inputEntry>
|
|
15
|
+
<outputEntry><text>3</text></outputEntry>
|
|
16
|
+
</rule>
|
|
17
|
+
<rule>
|
|
18
|
+
<inputEntry><text>"Large"</text></inputEntry>
|
|
19
|
+
<inputEntry><text>"Oat"</text></inputEntry>
|
|
20
|
+
<outputEntry><text>5</text></outputEntry>
|
|
21
|
+
</rule>
|
|
22
|
+
</decisionTable>
|
|
23
|
+
</decision>
|
|
24
|
+
</definitions>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
Feature: Order a drink
|
|
2
|
+
A customer picks a drink, pays, and picks it up.
|
|
3
|
+
|
|
4
|
+
Rule: Paying for the order
|
|
5
|
+
|
|
6
|
+
Scenario: Pays by card
|
|
7
|
+
Given a drink in the cart
|
|
8
|
+
When the customer pays by card
|
|
9
|
+
Then the barista can start the drink
|
|
10
|
+
|
|
11
|
+
Scenario: Pays with a wallet
|
|
12
|
+
Given a drink in the cart
|
|
13
|
+
When the customer pays with a wallet
|
|
14
|
+
Then the order is paid
|
|
15
|
+
|
|
16
|
+
Scenario: Card declined, then a wallet works
|
|
17
|
+
Given a drink in the cart
|
|
18
|
+
When the card is declined
|
|
19
|
+
And the customer pays with a wallet
|
|
20
|
+
Then the order is paid
|
|
21
|
+
|
|
22
|
+
Scenario: Slow payment
|
|
23
|
+
Given a drink in the cart
|
|
24
|
+
When the payment takes longer than a minute
|
|
25
|
+
Then the customer can check the payment again
|
|
26
|
+
|
|
27
|
+
Scenario: Leaves checkout and comes back
|
|
28
|
+
Given a drink in the cart
|
|
29
|
+
When the customer closes checkout
|
|
30
|
+
And the customer starts checkout again
|
|
31
|
+
Then checkout is open
|
|
32
|
+
|
|
33
|
+
Scenario: Drink left too long
|
|
34
|
+
Given a finished drink
|
|
35
|
+
When nobody picks it up
|
|
36
|
+
Then the drink is thrown away and refunded
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<definitions xmlns="https://www.omg.org/spec/DMN/20191111/MODEL/">
|
|
3
|
+
<decision id="drink-price" name="Drink price">
|
|
4
|
+
<decisionTable id="Drink price" hitPolicy="UNIQUE">
|
|
5
|
+
<input label="Size">
|
|
6
|
+
<inputExpression typeRef="string"><text>size</text></inputExpression>
|
|
7
|
+
</input>
|
|
8
|
+
<input label="Milk">
|
|
9
|
+
<inputExpression typeRef="string"><text>milk</text></inputExpression>
|
|
10
|
+
</input>
|
|
11
|
+
<output label="Price" name="price" />
|
|
12
|
+
<rule>
|
|
13
|
+
<inputEntry><text>"Small"</text></inputEntry>
|
|
14
|
+
<inputEntry><text>"None"</text></inputEntry>
|
|
15
|
+
<outputEntry><text>3</text></outputEntry>
|
|
16
|
+
</rule>
|
|
17
|
+
<rule>
|
|
18
|
+
<inputEntry><text>"Large"</text></inputEntry>
|
|
19
|
+
<inputEntry><text>"Oat"</text></inputEntry>
|
|
20
|
+
<outputEntry><text>5</text></outputEntry>
|
|
21
|
+
</rule>
|
|
22
|
+
</decisionTable>
|
|
23
|
+
</decision>
|
|
24
|
+
</definitions>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
Feature: Order a drink
|
|
2
|
+
A customer picks a drink, pays, and picks it up.
|
|
3
|
+
|
|
4
|
+
Rule: Paying for the order
|
|
5
|
+
|
|
6
|
+
Scenario: Pays by card
|
|
7
|
+
Given a drink in the cart
|
|
8
|
+
When the customer pays by card
|
|
9
|
+
Then the barista can start the drink
|
|
10
|
+
|
|
11
|
+
Scenario: Pays with a wallet
|
|
12
|
+
Given a drink in the cart
|
|
13
|
+
When the customer pays with a wallet
|
|
14
|
+
Then the order is paid
|
|
15
|
+
|
|
16
|
+
Scenario: Card declined, then a wallet works
|
|
17
|
+
Given a drink in the cart
|
|
18
|
+
When the card is declined
|
|
19
|
+
And the customer pays with a wallet
|
|
20
|
+
Then the order is paid
|
|
21
|
+
|
|
22
|
+
Scenario: Slow payment
|
|
23
|
+
Given a drink in the cart
|
|
24
|
+
When the payment takes longer than a minute
|
|
25
|
+
Then the customer can check the payment again
|
|
26
|
+
|
|
27
|
+
Scenario: Leaves checkout and comes back
|
|
28
|
+
Given a drink in the cart
|
|
29
|
+
When the customer closes checkout
|
|
30
|
+
And the customer starts checkout again
|
|
31
|
+
Then checkout is open
|
|
32
|
+
|
|
33
|
+
Scenario: Drink left too long
|
|
34
|
+
Given a finished drink
|
|
35
|
+
When nobody picks it up
|
|
36
|
+
Then the drink is thrown away and refunded
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<definitions xmlns="https://www.omg.org/spec/DMN/20191111/MODEL/">
|
|
3
|
+
<decision id="drink-price" name="Drink price">
|
|
4
|
+
<decisionTable id="Drink price" hitPolicy="UNIQUE">
|
|
5
|
+
<input label="Size">
|
|
6
|
+
<inputExpression typeRef="string"><text>size</text></inputExpression>
|
|
7
|
+
</input>
|
|
8
|
+
<input label="Milk">
|
|
9
|
+
<inputExpression typeRef="string"><text>milk</text></inputExpression>
|
|
10
|
+
</input>
|
|
11
|
+
<output label="Price" name="price" />
|
|
12
|
+
<rule>
|
|
13
|
+
<inputEntry><text>"Small"</text></inputEntry>
|
|
14
|
+
<inputEntry><text>"None"</text></inputEntry>
|
|
15
|
+
<outputEntry><text>3</text></outputEntry>
|
|
16
|
+
</rule>
|
|
17
|
+
<rule>
|
|
18
|
+
<inputEntry><text>"Large"</text></inputEntry>
|
|
19
|
+
<inputEntry><text>"Oat"</text></inputEntry>
|
|
20
|
+
<outputEntry><text>5</text></outputEntry>
|
|
21
|
+
</rule>
|
|
22
|
+
</decisionTable>
|
|
23
|
+
</decision>
|
|
24
|
+
</definitions>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
Feature: Order a drink
|
|
2
|
+
A customer picks a drink, pays, and picks it up.
|
|
3
|
+
|
|
4
|
+
Rule: Paying for the order
|
|
5
|
+
|
|
6
|
+
Scenario: Pays by card
|
|
7
|
+
Given a drink in the cart
|
|
8
|
+
When the customer pays by card
|
|
9
|
+
Then the barista can start the drink
|
|
10
|
+
|
|
11
|
+
Scenario: Pays with a wallet
|
|
12
|
+
Given a drink in the cart
|
|
13
|
+
When the customer pays with a wallet
|
|
14
|
+
Then the order is paid
|
|
15
|
+
|
|
16
|
+
Scenario: Card declined, then a wallet works
|
|
17
|
+
Given a drink in the cart
|
|
18
|
+
When the card is declined
|
|
19
|
+
And the customer pays with a wallet
|
|
20
|
+
Then the order is paid
|
|
21
|
+
|
|
22
|
+
Scenario: Slow payment
|
|
23
|
+
Given a drink in the cart
|
|
24
|
+
When the payment takes longer than a minute
|
|
25
|
+
Then the customer can check the payment again
|
|
26
|
+
|
|
27
|
+
Scenario: Leaves checkout and comes back
|
|
28
|
+
Given a drink in the cart
|
|
29
|
+
When the customer closes checkout
|
|
30
|
+
And the customer starts checkout again
|
|
31
|
+
Then checkout is open
|
|
32
|
+
|
|
33
|
+
Scenario: Drink left too long
|
|
34
|
+
Given a finished drink
|
|
35
|
+
When nobody picks it up
|
|
36
|
+
Then the drink is thrown away and refunded
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<definitions xmlns="https://www.omg.org/spec/DMN/20191111/MODEL/">
|
|
3
|
+
<decision id="drink-price" name="Drink price">
|
|
4
|
+
<decisionTable id="Drink price" hitPolicy="UNIQUE">
|
|
5
|
+
<input label="Size">
|
|
6
|
+
<inputExpression typeRef="string"><text>size</text></inputExpression>
|
|
7
|
+
</input>
|
|
8
|
+
<input label="Milk">
|
|
9
|
+
<inputExpression typeRef="string"><text>milk</text></inputExpression>
|
|
10
|
+
</input>
|
|
11
|
+
<output label="Price" name="price" />
|
|
12
|
+
<rule>
|
|
13
|
+
<inputEntry><text>"Small"</text></inputEntry>
|
|
14
|
+
<inputEntry><text>"None"</text></inputEntry>
|
|
15
|
+
<outputEntry><text>3</text></outputEntry>
|
|
16
|
+
</rule>
|
|
17
|
+
<rule>
|
|
18
|
+
<inputEntry><text>"Large"</text></inputEntry>
|
|
19
|
+
<inputEntry><text>"Oat"</text></inputEntry>
|
|
20
|
+
<outputEntry><text>5</text></outputEntry>
|
|
21
|
+
</rule>
|
|
22
|
+
</decisionTable>
|
|
23
|
+
</decision>
|
|
24
|
+
</definitions>
|