@crvouga/atlas 1.19.0 → 1.21.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/dist/core/src/cli.d.ts +1 -1
- package/dist/core/src/cli.js +3 -0
- package/dist/reports/src/compose.d.ts +23 -1
- package/dist/reports/src/compose.js +29 -19
- package/dist/reports/src/report-cli.d.ts +13 -0
- package/dist/reports/src/report-cli.js +6 -4
- package/dist/reports/src/ui-catalog-cli.d.ts +10 -0
- package/dist/reports/src/ui-catalog-cli.js +391 -0
- package/dist/reports/src/ui-catalog-diff.d.ts +104 -0
- package/dist/reports/src/ui-catalog-diff.js +130 -0
- package/dist/reports/src/ui-catalog-export.d.ts +82 -0
- package/dist/reports/src/ui-catalog-export.js +221 -0
- package/dist/schema/src/api.d.ts +55 -0
- package/dist/schema/src/api.js +33 -0
- package/dist/schema/src/cli-results.d.ts +318 -1
- package/dist/schema/src/cli-results.js +89 -1
- package/dist/server/src/app.js +3 -1
- package/dist/server/src/openapi.d.ts +1 -1
- package/dist/server/src/openapi.js +24 -2
- package/dist/server/src/recording-verification.d.ts +34 -0
- package/dist/server/src/recording-verification.js +118 -0
- package/docs/agents.md +5 -0
- package/docs/reference/cli.md +56 -1
- package/docs/reference/http-api.md +52 -0
- package/docs/reference/reports.md +392 -0
- package/docs/reference/schema.md +82 -1
- package/docs/reference/server.md +39 -0
- package/docs/rich-evidence.md +12 -0
- package/docs/server.md +12 -0
- package/docs/ui-catalog.md +106 -12
- package/docs/ui.md +6 -1
- package/llms-full.txt +246 -11
- package/package.json +1 -1
- package/packages/schema/schemas/ui-catalog-diff-result.schema.json +201 -0
- package/packages/schema/schemas/ui-catalog-export-result.schema.json +83 -0
- package/packages/schema/schemas/ui-catalog-publish-result.schema.json +116 -0
- package/packages/schema/schemas/ui-catalog-status.schema.json +197 -0
- package/packages/server/openapi.json +527 -1
- package/packages/visualizer/src/catalog/Picture.tsx +32 -0
- package/packages/visualizer/src/catalog/UiCatalogCompare.tsx +289 -0
- package/packages/visualizer/src/catalog/UiCatalogPage.tsx +18 -28
- package/packages/visualizer/src/catalog/history.ts +61 -0
- package/packages/visualizer/src/catalog/search.ts +14 -3
- package/packages/visualizer/src/evidence/evidence-context.tsx +2 -1
- package/packages/visualizer/src/explorer/RunsView.tsx +32 -6
- package/packages/visualizer/src/explorer/catalog.tsx +24 -1
- package/packages/visualizer/src/explorer/recording-verification.ts +58 -0
package/docs/ui-catalog.md
CHANGED
|
@@ -7,16 +7,19 @@ thousands of captures can be watched while it happens and split across as many m
|
|
|
7
7
|
|
|
8
8
|
Nothing about it is new to the report contract. A state is an ordinary check with a screenshot, the expected set is an ordinary
|
|
9
9
|
layer, and the stream is the one every viewer already holds. This page is the convention that makes those usable as a catalog, the
|
|
10
|
-
decisions behind it, and what
|
|
10
|
+
decisions behind it, the command line, and what stays in your project.
|
|
11
11
|
|
|
12
12
|
- [How a state is written](#how-a-state-is-written)
|
|
13
13
|
- [What is expected](#what-is-expected)
|
|
14
14
|
- [Publishing from any collector](#publishing-from-any-collector)
|
|
15
|
+
- [The command line](#the-command-line)
|
|
15
16
|
- [Sharding](#sharding)
|
|
16
17
|
- [Streaming and loading](#streaming-and-loading)
|
|
17
18
|
- [Exploring it](#exploring-it)
|
|
19
|
+
- [Comparing two commits or two profiles](#comparing-two-commits-or-two-profiles)
|
|
20
|
+
- [A single file that needs no server](#a-single-file-that-needs-no-server)
|
|
18
21
|
- [Decisions](#decisions)
|
|
19
|
-
- [What stays in your project, and what
|
|
22
|
+
- [What stays in your project, and what Atlas does not do](#what-stays-in-your-project-and-what-atlas-does-not-do)
|
|
20
23
|
|
|
21
24
|
## How a state is written
|
|
22
25
|
|
|
@@ -101,6 +104,35 @@ for a readiness check (bounded), photographs the page and returns the capture fo
|
|
|
101
104
|
a `failed` capture that says why (with a picture of what it showed), never an exception that ends the run. Nothing that reads,
|
|
102
105
|
composes or shows the catalog imports a collection framework, and a test keeps it that way.
|
|
103
106
|
|
|
107
|
+
## The command line
|
|
108
|
+
|
|
109
|
+
`atlas ui-catalog` does the same without a script. Every subcommand prints a JSON document with `--format json`
|
|
110
|
+
([`atlas ui-catalog --help`](reference/cli.md) lists every flag), and exits `0` it worked, `1` the answer is no, `2` the command was wrong.
|
|
111
|
+
|
|
112
|
+
```sh
|
|
113
|
+
# The expected set under one profile. The file is {"states":[{"id":"checkout/payment","covers":["payment-form"]},{"id":"settings","inventory":true}]}.
|
|
114
|
+
atlas ui-catalog plan --states plan.json --producer catalog-plan --environment mobile-web --param viewport=390x844 --param scheme=dark
|
|
115
|
+
|
|
116
|
+
# The states one collector or shard captured. "screenshot" names a file beside captures.json.
|
|
117
|
+
atlas ui-catalog publish --captures captures.json --producer web-capture --environment mobile-web --param viewport=390x844 --param scheme=dark --shard 2/8
|
|
118
|
+
|
|
119
|
+
atlas ui-catalog status # exit 1 while anything failed, is missing, is still being captured or could not be read
|
|
120
|
+
atlas ui-catalog diff --from 3f9a2c1 --to 8b41d70 # two commits (the whole id, or at least 7 digits)
|
|
121
|
+
atlas ui-catalog export --out public/catalog.html # one file, no server
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
`captures.json` is `{"states":[…]}` (or just the list); a state is `{"id","title"?,"status"?,"detail"?,"route"?,"fixture"?,"cohort"?,"area"?,
|
|
125
|
+
"flags"?,"covers"?,"labels"?,"tags"?,"durationMs"?,"screenshot"?}` with `screenshot` a file name or `{"path"|"uri","width"?,"height"?,"contentType"?}`.
|
|
126
|
+
A misspelled field is refused with its path, not ignored. A picture file is read from beside the file and from each `--attach-root`,
|
|
127
|
+
never from a hidden file or a link out. **A `passed` state whose picture cannot be read is published as `failed`, with the reason**: a
|
|
128
|
+
state without its picture is not shown as captured. `--recorded-at` defaults to the file's modification time, so publishing the same
|
|
129
|
+
file twice is the same layer.
|
|
130
|
+
|
|
131
|
+
`status` is the gate: it exits `1` unless the catalog holds a state and nothing needs attention (a failed capture, a state a plan expects
|
|
132
|
+
with nothing captured, a capture still in progress, a backend or layer that could not be read). Without a plan nothing is expected, so
|
|
133
|
+
nothing can be missing: it says so. A skipped cell is counted, not a problem. Schemas: `ui-catalog-publish-result`,
|
|
134
|
+
`ui-catalog-status`, `ui-catalog-diff-result`, `ui-catalog-export-result`.
|
|
135
|
+
|
|
104
136
|
## Sharding
|
|
105
137
|
|
|
106
138
|
A shard is **any publisher that does not know the others**: by case, by profile, by area or by machine; Atlas does not care which.
|
|
@@ -144,6 +176,47 @@ curl "$ATLAS_SERVER_URL/api/reports/ui-catalog?coverage=failed,missing&profile=
|
|
|
144
176
|
`@crvouga/atlas/reports/ui-catalog`), filtered by `q`, `coverage`, `profile`, `area`, `route`, `cohort`, `flag`, `surface` and
|
|
145
177
|
`producer`, paged with `limit` and `offset`, with an ETag. Its picture `path` is relative to `/api/reports`.
|
|
146
178
|
|
|
179
|
+
## Comparing two commits or two profiles
|
|
180
|
+
|
|
181
|
+
The viewer's **Compare** button on `/catalog` (`?compare=commit&from=<commit>&to=<commit>`, or `?compare=profile&from=<profile>&to=<profile>`,
|
|
182
|
+
so a link reproduces it) and `atlas ui-catalog diff` set one side against the other. Every pair is one state in one profile.
|
|
183
|
+
|
|
184
|
+
| A pair is | When |
|
|
185
|
+
| --- | --- |
|
|
186
|
+
| **Unchanged** | the same coverage and, when captured, the same stored picture |
|
|
187
|
+
| **Picture changed** | captured on both sides, and the picture's bytes (SHA-256) differ. This is not a measure of how many pixels differ |
|
|
188
|
+
| **Coverage changed** | it stands differently (captured against failed, failed against not captured yet…). A capture that did not pass is never compared by picture |
|
|
189
|
+
| **Cannot tell** | captured on both sides, but a picture has no content hash (it is given only by address, or was left out) |
|
|
190
|
+
| **Only after** / **Only before** | one side has no such cell. It may be new, renamed, or the other side's shard may not have run: it is not called a regression |
|
|
191
|
+
|
|
192
|
+
- **Two commits** compares the layers recorded at each commit. A layer replaces the older one of its slot, so the report keeps only the
|
|
193
|
+
newest capture of every state; the comparison therefore reads the layers themselves (the viewer asks for the layer list and the rows of
|
|
194
|
+
the two commits only; the command line reads the stores). Layers recorded from a checkout with uncommitted changes are not a commit's
|
|
195
|
+
own result and are left out. A commit is the whole id or at least 7 digits that name exactly one commit; anything else is an error
|
|
196
|
+
that lists the commits found, never a guess.
|
|
197
|
+
- **Two profiles** sets each state's cell in one profile beside its cell in another (desktop against mobile, light against dark) in
|
|
198
|
+
the report the viewer holds.
|
|
199
|
+
- A layer or backend that could not be read is named, and what it held is unknown, never "unchanged": `diff` exits `1` for it.
|
|
200
|
+
`--fail-on-change` also exits `1` for any difference, for a gate that must stay the same.
|
|
201
|
+
- The filters (words, area, route, cohort, flag, surface, producer) narrow a comparison; coverage does not, because coverage is what is
|
|
202
|
+
compared.
|
|
203
|
+
|
|
204
|
+
## A single file that needs no server
|
|
205
|
+
|
|
206
|
+
`atlas ui-catalog export --out catalog.html` writes the catalog as **one HTML file**: the pictures embedded as `data:` addresses, the
|
|
207
|
+
manifest embedded as JSON (`<script type="application/json" id="ui-catalog">`), a search box and a coverage filter. Open it from a disk,
|
|
208
|
+
attach it to a ticket or serve it as a file. It is the catalog at the moment it was made, and says so; it does not stream (for that,
|
|
209
|
+
serve the store with `atlas serve` or build the site with `atlas client build`, which shows the same catalog).
|
|
210
|
+
|
|
211
|
+
- **Size.** Hosting platforms cap the size of one file. `--max-mb` (default 32) limits the embedded pictures; pictures past it are listed
|
|
212
|
+
in the page as left out, with the reason, in the order the page shows them, and the manifest stays complete. `--images none` embeds none.
|
|
213
|
+
`--manifest catalog.json` also writes the manifest as its own file.
|
|
214
|
+
- **Safe to open.** The page is generated from data written by test runs, and treats it so: text is escaped, only PNG, JPEG, GIF and WebP
|
|
215
|
+
bytes (by their first bytes, never SVG, never a layer's claimed type) are embedded, a picture given by address is linked only if it is
|
|
216
|
+
`http` or `https`, and a Content-Security-Policy forbids every network request. Without scripts every state is simply shown.
|
|
217
|
+
- It is a generated document, not the viewer: it carries its own small inline style and script because it must work with no build
|
|
218
|
+
and no server, which [the viewer's UI conventions](ui.md) forbid inside the viewer.
|
|
219
|
+
|
|
147
220
|
## Decisions
|
|
148
221
|
|
|
149
222
|
The questions the original proposal left open, and how they are answered here. Each is the simplest answer that stays inside the
|
|
@@ -161,13 +234,34 @@ The questions the original proposal left open, and how they are answered here. E
|
|
|
161
234
|
| What moves | Reading, composing, the viewer, the document and the API, the publish builders, a Playwright capture adapter. Staying with a product: its state declarations, its inventory, its fixtures and its runner. |
|
|
162
235
|
| Where it lives | `@crvouga/atlas/reports/ui-catalog` (model), `…/ui-catalog-publish` (builders), `…/ui-state` (convention); the viewer's `/catalog`; the server's `/api/reports/ui-catalog`; `@crvouga/atlas/playwright`'s `captureUiState`. |
|
|
163
236
|
| Exploration capabilities | Search, filters, profile comparison, coverage and surface coverage, failure diagnostics, deep links, manifest export. |
|
|
164
|
-
| Static export | The catalog is computed from the layers a viewer holds, so
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
237
|
+
| Static export | Two ways, neither needs a server. The catalog is computed from the layers a viewer holds, so the static site (`atlas client build`) shows it, without streaming. `atlas ui-catalog export` writes it as one self-contained HTML file with a size budget. |
|
|
238
|
+
| Comparing | Two commits (from the layers recorded at each, because the report keeps only the newest) or two profiles; pictures by content hash, never by a pixel measure; one-sided states are not regressions. |
|
|
239
|
+
| Command line | `atlas ui-catalog plan`, `publish`, `status`, `diff` and `export`, each with `--format json`. Running a collector is not one: that is the product's. |
|
|
240
|
+
|
|
241
|
+
## What stays in your project, and what Atlas does not do
|
|
242
|
+
|
|
243
|
+
A project that had its own catalog moves each role it had to Atlas, and keeps only what is specific to its product. The eight roles, and
|
|
244
|
+
where each now is:
|
|
245
|
+
|
|
246
|
+
| # | Role | In Atlas | Stays in your project |
|
|
247
|
+
| --- | --- | --- | --- |
|
|
248
|
+
| 1 | Declaration of the states to capture, and the plan of what is expected | The plan format (`ui-plan` layers), `uiPlanLayer`, `atlas ui-catalog plan` | **The list itself**: which states and profiles your product has |
|
|
249
|
+
| 2 | A capture helper, with readiness checks and diagnostics | An optional adapter, `captureUiState` in `@crvouga/atlas/playwright`; any other tool writes the same layer | **The readiness condition of each screen**, and the helper for a framework Atlas has no adapter for |
|
|
250
|
+
| 3 | An evidence store: one atomic record per capture, images by content | Layers and the stores that hold them (`publishChecks`, a directory, S3, a server) | Nothing |
|
|
251
|
+
| 4 | An inventory of the product's surfaces, and reconciliation against it | Reconciliation: `inventory` plan entries and `covers`, the surface coverage table | **The inventory**: the list of surfaces your product has |
|
|
252
|
+
| 5 | A manifest and report builder | `uiCatalog`, the JSON manifest, Markdown, the single HTML file | Nothing |
|
|
253
|
+
| 6 | A viewer: as a single file, as a site, and live | `atlas ui-catalog export`, `atlas client build`, and `/catalog` on `atlas serve` | Nothing |
|
|
254
|
+
| 7 | A command line (list, run, report, publish, watch) | `atlas ui-catalog plan\|publish\|status\|diff\|export`; watching is the live `/catalog` and `atlas report stream` | **Run**: the runner that drives your product to each state |
|
|
255
|
+
| 8 | A publish step to a hosting platform | Not in Atlas, see below | **The deploy step** of your platform |
|
|
256
|
+
|
|
257
|
+
What stays is, in one list: the states and profiles to capture, the inventory of surfaces, the fixtures and test data, the runner that
|
|
258
|
+
drives the product to each state, the readiness condition of each screen, and the deploy step of your hosting platform. Nothing else is
|
|
259
|
+
specific to your product, so a project that installs a release holds none of the reporting and exploring code, only that.
|
|
260
|
+
|
|
261
|
+
**A hosting publish step is not a command, on purpose.** Publishing to a platform needs that platform's credentials and API, which Atlas
|
|
262
|
+
neither holds nor should. Hand the platform what Atlas produces: the `export` file (or a folder of them) for any host that serves
|
|
263
|
+
files, the output of `atlas client build` for a static site, or run `atlas serve` for a live one. Keep the credentials in the CI of the
|
|
264
|
+
project, where they already are.
|
|
265
|
+
|
|
266
|
+
**Not built:** reconciliation against an external inventory beyond `inventory` entries and `covers`; a comparison of pictures by pixels
|
|
267
|
+
(only by content); a comparison fetched from the server (the viewer and the command line read the layers themselves).
|
package/docs/ui.md
CHANGED
|
@@ -167,6 +167,11 @@ it works without a server. Cards are Mantine `Card`s in a responsive `SimpleGrid
|
|
|
167
167
|
incomplete. Waiting follows the loading policy below, and layers still arriving are counted.
|
|
168
168
|
- Pictures are `loading="lazy"` and only the cards on screen are fetched. The grid is bounded with *Show more*.
|
|
169
169
|
- The open state shows every profile side by side with the layer, backend, producer, shard, commit and time of each picture.
|
|
170
|
+
- **Compare** (`catalog/UiCatalogCompare.tsx`, `?compare=commit|profile&from&to`) sets two commits or two profiles against each other. Two
|
|
171
|
+
commits need the layers a newer layer replaced, which the held report no longer has, so `catalog/history.ts` reads the layer list and
|
|
172
|
+
the rows of the two commits only while the comparison is open (sharing the rows cache). Say what "changed" means (the stored bytes
|
|
173
|
+
differ, not a pixel measure), never call a one-sided state a regression, and say a layer that could not be read is unknown. The
|
|
174
|
+
coverage filter does not apply to a comparison.
|
|
170
175
|
|
|
171
176
|
## Reliability
|
|
172
177
|
|
|
@@ -384,7 +389,7 @@ The narrowly scoped exceptions are:
|
|
|
384
389
|
| Area | Screens/interactions | Mantine composition |
|
|
385
390
|
| --- | --- | --- |
|
|
386
391
|
| Shared shell | Project switching, spec navigation, run selection, connection status, diagnostics, mobile index | AppShell, Burger, NavLink, Menu, Popover, NativeSelect, Drawer |
|
|
387
|
-
| UI catalog | Captured UI states per profile as cards with coverage badges, filters in the index column, surface coverage, an open state with its profiles side by side and where each picture came from, manifest download | AppShell navbar, SimpleGrid, Card, Image, MultiSelect, TextInput, Drawer, Accordion, Table, Badge, Alert |
|
|
392
|
+
| UI catalog | Captured UI states per profile as cards with coverage badges, filters in the index column, surface coverage, an open state with its profiles side by side and where each picture came from, manifest download, a Compare of two commits or profiles (SegmentedControl, NativeSelect, Switch) | AppShell navbar, SimpleGrid, Card, Image, MultiSelect, TextInput, Drawer, Accordion, Table, Badge, Alert |
|
|
388
393
|
| Project home | Tests/runs/artifacts/compare/catalog health tabs, a two-run comparison with promise, outcome, recording and figure tabs per behavior, a run's Artifacts (files of its layers, shared recordings, direct links), Watch playlist of a filtered set, metrics, search, status/environment/domain/artifact-tag filters, run and artifact facets with saved views, grouping, sorting, show more | Container, Tabs, SimpleGrid, Paper, TextInput, MultiSelect, Popover, Button, Accordion, Modal, Grid, Switch |
|
|
389
394
|
| Test detail | Current outcomes, statistics, duration graph, product latency with budgets and baselines, history, artifacts, recording; the `layer` address parameter pins it to one run's result, labelled "This run" against "Latest combined evidence" | Drawer, Table, Badge, Alert, Stage |
|
|
390
395
|
| Specs | All six existing kinds, overview/index with title search and folder or declared-domain grouping, Gherkin rules/scenarios/examples with a coverage summary and Read / Watch / Inspect per behavior, Quint declarations/traces, DMN tables, source text | SpecHeader, Accordion, Tabs, Table, CodeHighlightTabs, ResultRow |
|
package/llms-full.txt
CHANGED
|
@@ -173,6 +173,11 @@ JSON Schema (`@crvouga/atlas/schemas/<name>.schema.json`, draft 2020-12):
|
|
|
173
173
|
| `atlas report doctor` | `doctor-result` |
|
|
174
174
|
| `atlas report status` | `report-status` |
|
|
175
175
|
| `atlas report verify-recordings` | `verify-recordings-result` |
|
|
176
|
+
| `atlas ui-catalog plan` | `ui-catalog-publish-result` |
|
|
177
|
+
| `atlas ui-catalog publish` | `ui-catalog-publish-result` |
|
|
178
|
+
| `atlas ui-catalog status` | `ui-catalog-status` |
|
|
179
|
+
| `atlas ui-catalog diff` | `ui-catalog-diff-result` |
|
|
180
|
+
| `atlas ui-catalog export` | `ui-catalog-export-result` |
|
|
176
181
|
| `a command that was wrong (standard error)` | `command-error` |
|
|
177
182
|
<!-- /generated:json-command-schemas -->
|
|
178
183
|
|
|
@@ -1493,6 +1498,18 @@ two ways without touching a check's result:
|
|
|
1493
1498
|
`--format json` prints the `verify-recordings-result` document. `--layer <id>` and `--limit <n>` narrow the work, since
|
|
1494
1499
|
it reads blobs. A store that cannot answer is `unreadable`, never verified. Test results are unchanged either way.
|
|
1495
1500
|
|
|
1501
|
+
- **In the viewer.** A publish token starts the same read-back on the server with
|
|
1502
|
+
`POST /api/reports/recordings/verification` (body optional: `{ "layers": ["<id prefix>"], "limit": 20 }`; the newest
|
|
1503
|
+
20 layers by default, at most 200, one read-back at a time; a reader token, a browser sign-in box or an anonymous
|
|
1504
|
+
caller is refused because it reads blobs). Anyone who can read the report then sees the result with
|
|
1505
|
+
`GET /api/reports/recordings/verification` (which reads no blob): per layer, its run, how many videos were read back, how
|
|
1506
|
+
many passed and each gap. The Runs tab and an opened run show `Recording unavailable: 1 of 3 stored videos failed the
|
|
1507
|
+
read-back (1 file gone from storage)` beside the green outcomes, or `3 stored videos verified`, and a run whose stored
|
|
1508
|
+
videos all failed offers no Watch action. A run whose layers were never read back shows nothing: unknown is not
|
|
1509
|
+
verified. The result lives in the server's memory only, so a restart empties it, and a layer that garbage collection
|
|
1510
|
+
removed drops out. An older server has no such route and the viewer then shows nothing. No status, slot or winner is
|
|
1511
|
+
affected; `capabilities.recordingVerification` in `GET /api/server` says a server offers it.
|
|
1512
|
+
|
|
1496
1513
|
Both are statements about stored bytes. Atlas does not check that a stored video plays in a given browser (a valid header
|
|
1497
1514
|
can still have an unsupported codec or be truncated), and acknowledging an upload is not playback. Videos given only by
|
|
1498
1515
|
`uri` are counted as referenced and not checked.
|
|
@@ -1508,16 +1525,19 @@ thousands of captures can be watched while it happens and split across as many m
|
|
|
1508
1525
|
|
|
1509
1526
|
Nothing about it is new to the report contract. A state is an ordinary check with a screenshot, the expected set is an ordinary
|
|
1510
1527
|
layer, and the stream is the one every viewer already holds. This page is the convention that makes those usable as a catalog, the
|
|
1511
|
-
decisions behind it, and what
|
|
1528
|
+
decisions behind it, the command line, and what stays in your project.
|
|
1512
1529
|
|
|
1513
1530
|
- [How a state is written](#how-a-state-is-written)
|
|
1514
1531
|
- [What is expected](#what-is-expected)
|
|
1515
1532
|
- [Publishing from any collector](#publishing-from-any-collector)
|
|
1533
|
+
- [The command line](#the-command-line)
|
|
1516
1534
|
- [Sharding](#sharding)
|
|
1517
1535
|
- [Streaming and loading](#streaming-and-loading)
|
|
1518
1536
|
- [Exploring it](#exploring-it)
|
|
1537
|
+
- [Comparing two commits or two profiles](#comparing-two-commits-or-two-profiles)
|
|
1538
|
+
- [A single file that needs no server](#a-single-file-that-needs-no-server)
|
|
1519
1539
|
- [Decisions](#decisions)
|
|
1520
|
-
- [What stays in your project, and what
|
|
1540
|
+
- [What stays in your project, and what Atlas does not do](#what-stays-in-your-project-and-what-atlas-does-not-do)
|
|
1521
1541
|
|
|
1522
1542
|
## How a state is written
|
|
1523
1543
|
|
|
@@ -1602,6 +1622,35 @@ for a readiness check (bounded), photographs the page and returns the capture fo
|
|
|
1602
1622
|
a `failed` capture that says why (with a picture of what it showed), never an exception that ends the run. Nothing that reads,
|
|
1603
1623
|
composes or shows the catalog imports a collection framework, and a test keeps it that way.
|
|
1604
1624
|
|
|
1625
|
+
## The command line
|
|
1626
|
+
|
|
1627
|
+
`atlas ui-catalog` does the same without a script. Every subcommand prints a JSON document with `--format json`
|
|
1628
|
+
([`atlas ui-catalog --help`](reference/cli.md) lists every flag), and exits `0` it worked, `1` the answer is no, `2` the command was wrong.
|
|
1629
|
+
|
|
1630
|
+
```sh
|
|
1631
|
+
# The expected set under one profile. The file is {"states":[{"id":"checkout/payment","covers":["payment-form"]},{"id":"settings","inventory":true}]}.
|
|
1632
|
+
atlas ui-catalog plan --states plan.json --producer catalog-plan --environment mobile-web --param viewport=390x844 --param scheme=dark
|
|
1633
|
+
|
|
1634
|
+
# The states one collector or shard captured. "screenshot" names a file beside captures.json.
|
|
1635
|
+
atlas ui-catalog publish --captures captures.json --producer web-capture --environment mobile-web --param viewport=390x844 --param scheme=dark --shard 2/8
|
|
1636
|
+
|
|
1637
|
+
atlas ui-catalog status # exit 1 while anything failed, is missing, is still being captured or could not be read
|
|
1638
|
+
atlas ui-catalog diff --from 3f9a2c1 --to 8b41d70 # two commits (the whole id, or at least 7 digits)
|
|
1639
|
+
atlas ui-catalog export --out public/catalog.html # one file, no server
|
|
1640
|
+
```
|
|
1641
|
+
|
|
1642
|
+
`captures.json` is `{"states":[…]}` (or just the list); a state is `{"id","title"?,"status"?,"detail"?,"route"?,"fixture"?,"cohort"?,"area"?,
|
|
1643
|
+
"flags"?,"covers"?,"labels"?,"tags"?,"durationMs"?,"screenshot"?}` with `screenshot` a file name or `{"path"|"uri","width"?,"height"?,"contentType"?}`.
|
|
1644
|
+
A misspelled field is refused with its path, not ignored. A picture file is read from beside the file and from each `--attach-root`,
|
|
1645
|
+
never from a hidden file or a link out. **A `passed` state whose picture cannot be read is published as `failed`, with the reason**: a
|
|
1646
|
+
state without its picture is not shown as captured. `--recorded-at` defaults to the file's modification time, so publishing the same
|
|
1647
|
+
file twice is the same layer.
|
|
1648
|
+
|
|
1649
|
+
`status` is the gate: it exits `1` unless the catalog holds a state and nothing needs attention (a failed capture, a state a plan expects
|
|
1650
|
+
with nothing captured, a capture still in progress, a backend or layer that could not be read). Without a plan nothing is expected, so
|
|
1651
|
+
nothing can be missing: it says so. A skipped cell is counted, not a problem. Schemas: `ui-catalog-publish-result`,
|
|
1652
|
+
`ui-catalog-status`, `ui-catalog-diff-result`, `ui-catalog-export-result`.
|
|
1653
|
+
|
|
1605
1654
|
## Sharding
|
|
1606
1655
|
|
|
1607
1656
|
A shard is **any publisher that does not know the others**: by case, by profile, by area or by machine; Atlas does not care which.
|
|
@@ -1645,6 +1694,47 @@ curl "$ATLAS_SERVER_URL/api/reports/ui-catalog?coverage=failed,missing&profile=
|
|
|
1645
1694
|
`@crvouga/atlas/reports/ui-catalog`), filtered by `q`, `coverage`, `profile`, `area`, `route`, `cohort`, `flag`, `surface` and
|
|
1646
1695
|
`producer`, paged with `limit` and `offset`, with an ETag. Its picture `path` is relative to `/api/reports`.
|
|
1647
1696
|
|
|
1697
|
+
## Comparing two commits or two profiles
|
|
1698
|
+
|
|
1699
|
+
The viewer's **Compare** button on `/catalog` (`?compare=commit&from=<commit>&to=<commit>`, or `?compare=profile&from=<profile>&to=<profile>`,
|
|
1700
|
+
so a link reproduces it) and `atlas ui-catalog diff` set one side against the other. Every pair is one state in one profile.
|
|
1701
|
+
|
|
1702
|
+
| A pair is | When |
|
|
1703
|
+
| --- | --- |
|
|
1704
|
+
| **Unchanged** | the same coverage and, when captured, the same stored picture |
|
|
1705
|
+
| **Picture changed** | captured on both sides, and the picture's bytes (SHA-256) differ. This is not a measure of how many pixels differ |
|
|
1706
|
+
| **Coverage changed** | it stands differently (captured against failed, failed against not captured yet…). A capture that did not pass is never compared by picture |
|
|
1707
|
+
| **Cannot tell** | captured on both sides, but a picture has no content hash (it is given only by address, or was left out) |
|
|
1708
|
+
| **Only after** / **Only before** | one side has no such cell. It may be new, renamed, or the other side's shard may not have run: it is not called a regression |
|
|
1709
|
+
|
|
1710
|
+
- **Two commits** compares the layers recorded at each commit. A layer replaces the older one of its slot, so the report keeps only the
|
|
1711
|
+
newest capture of every state; the comparison therefore reads the layers themselves (the viewer asks for the layer list and the rows of
|
|
1712
|
+
the two commits only; the command line reads the stores). Layers recorded from a checkout with uncommitted changes are not a commit's
|
|
1713
|
+
own result and are left out. A commit is the whole id or at least 7 digits that name exactly one commit; anything else is an error
|
|
1714
|
+
that lists the commits found, never a guess.
|
|
1715
|
+
- **Two profiles** sets each state's cell in one profile beside its cell in another (desktop against mobile, light against dark) in
|
|
1716
|
+
the report the viewer holds.
|
|
1717
|
+
- A layer or backend that could not be read is named, and what it held is unknown, never "unchanged": `diff` exits `1` for it.
|
|
1718
|
+
`--fail-on-change` also exits `1` for any difference, for a gate that must stay the same.
|
|
1719
|
+
- The filters (words, area, route, cohort, flag, surface, producer) narrow a comparison; coverage does not, because coverage is what is
|
|
1720
|
+
compared.
|
|
1721
|
+
|
|
1722
|
+
## A single file that needs no server
|
|
1723
|
+
|
|
1724
|
+
`atlas ui-catalog export --out catalog.html` writes the catalog as **one HTML file**: the pictures embedded as `data:` addresses, the
|
|
1725
|
+
manifest embedded as JSON (`<script type="application/json" id="ui-catalog">`), a search box and a coverage filter. Open it from a disk,
|
|
1726
|
+
attach it to a ticket or serve it as a file. It is the catalog at the moment it was made, and says so; it does not stream (for that,
|
|
1727
|
+
serve the store with `atlas serve` or build the site with `atlas client build`, which shows the same catalog).
|
|
1728
|
+
|
|
1729
|
+
- **Size.** Hosting platforms cap the size of one file. `--max-mb` (default 32) limits the embedded pictures; pictures past it are listed
|
|
1730
|
+
in the page as left out, with the reason, in the order the page shows them, and the manifest stays complete. `--images none` embeds none.
|
|
1731
|
+
`--manifest catalog.json` also writes the manifest as its own file.
|
|
1732
|
+
- **Safe to open.** The page is generated from data written by test runs, and treats it so: text is escaped, only PNG, JPEG, GIF and WebP
|
|
1733
|
+
bytes (by their first bytes, never SVG, never a layer's claimed type) are embedded, a picture given by address is linked only if it is
|
|
1734
|
+
`http` or `https`, and a Content-Security-Policy forbids every network request. Without scripts every state is simply shown.
|
|
1735
|
+
- It is a generated document, not the viewer: it carries its own small inline style and script because it must work with no build
|
|
1736
|
+
and no server, which [the viewer's UI conventions](ui.md) forbid inside the viewer.
|
|
1737
|
+
|
|
1648
1738
|
## Decisions
|
|
1649
1739
|
|
|
1650
1740
|
The questions the original proposal left open, and how they are answered here. Each is the simplest answer that stays inside the
|
|
@@ -1662,16 +1752,37 @@ The questions the original proposal left open, and how they are answered here. E
|
|
|
1662
1752
|
| What moves | Reading, composing, the viewer, the document and the API, the publish builders, a Playwright capture adapter. Staying with a product: its state declarations, its inventory, its fixtures and its runner. |
|
|
1663
1753
|
| Where it lives | `@crvouga/atlas/reports/ui-catalog` (model), `…/ui-catalog-publish` (builders), `…/ui-state` (convention); the viewer's `/catalog`; the server's `/api/reports/ui-catalog`; `@crvouga/atlas/playwright`'s `captureUiState`. |
|
|
1664
1754
|
| Exploration capabilities | Search, filters, profile comparison, coverage and surface coverage, failure diagnostics, deep links, manifest export. |
|
|
1665
|
-
| Static export | The catalog is computed from the layers a viewer holds, so
|
|
1755
|
+
| Static export | Two ways, neither needs a server. The catalog is computed from the layers a viewer holds, so the static site (`atlas client build`) shows it, without streaming. `atlas ui-catalog export` writes it as one self-contained HTML file with a size budget. |
|
|
1756
|
+
| Comparing | Two commits (from the layers recorded at each, because the report keeps only the newest) or two profiles; pictures by content hash, never by a pixel measure; one-sided states are not regressions. |
|
|
1757
|
+
| Command line | `atlas ui-catalog plan`, `publish`, `status`, `diff` and `export`, each with `--format json`. Running a collector is not one: that is the product's. |
|
|
1666
1758
|
|
|
1667
|
-
## What stays in your project, and what
|
|
1759
|
+
## What stays in your project, and what Atlas does not do
|
|
1668
1760
|
|
|
1669
|
-
|
|
1670
|
-
|
|
1761
|
+
A project that had its own catalog moves each role it had to Atlas, and keeps only what is specific to its product. The eight roles, and
|
|
1762
|
+
where each now is:
|
|
1671
1763
|
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1764
|
+
| # | Role | In Atlas | Stays in your project |
|
|
1765
|
+
| --- | --- | --- | --- |
|
|
1766
|
+
| 1 | Declaration of the states to capture, and the plan of what is expected | The plan format (`ui-plan` layers), `uiPlanLayer`, `atlas ui-catalog plan` | **The list itself**: which states and profiles your product has |
|
|
1767
|
+
| 2 | A capture helper, with readiness checks and diagnostics | An optional adapter, `captureUiState` in `@crvouga/atlas/playwright`; any other tool writes the same layer | **The readiness condition of each screen**, and the helper for a framework Atlas has no adapter for |
|
|
1768
|
+
| 3 | An evidence store: one atomic record per capture, images by content | Layers and the stores that hold them (`publishChecks`, a directory, S3, a server) | Nothing |
|
|
1769
|
+
| 4 | An inventory of the product's surfaces, and reconciliation against it | Reconciliation: `inventory` plan entries and `covers`, the surface coverage table | **The inventory**: the list of surfaces your product has |
|
|
1770
|
+
| 5 | A manifest and report builder | `uiCatalog`, the JSON manifest, Markdown, the single HTML file | Nothing |
|
|
1771
|
+
| 6 | A viewer: as a single file, as a site, and live | `atlas ui-catalog export`, `atlas client build`, and `/catalog` on `atlas serve` | Nothing |
|
|
1772
|
+
| 7 | A command line (list, run, report, publish, watch) | `atlas ui-catalog plan\|publish\|status\|diff\|export`; watching is the live `/catalog` and `atlas report stream` | **Run**: the runner that drives your product to each state |
|
|
1773
|
+
| 8 | A publish step to a hosting platform | Not in Atlas, see below | **The deploy step** of your platform |
|
|
1774
|
+
|
|
1775
|
+
What stays is, in one list: the states and profiles to capture, the inventory of surfaces, the fixtures and test data, the runner that
|
|
1776
|
+
drives the product to each state, the readiness condition of each screen, and the deploy step of your hosting platform. Nothing else is
|
|
1777
|
+
specific to your product, so a project that installs a release holds none of the reporting and exploring code, only that.
|
|
1778
|
+
|
|
1779
|
+
**A hosting publish step is not a command, on purpose.** Publishing to a platform needs that platform's credentials and API, which Atlas
|
|
1780
|
+
neither holds nor should. Hand the platform what Atlas produces: the `export` file (or a folder of them) for any host that serves
|
|
1781
|
+
files, the output of `atlas client build` for a static site, or run `atlas serve` for a live one. Keep the credentials in the CI of the
|
|
1782
|
+
project, where they already are.
|
|
1783
|
+
|
|
1784
|
+
**Not built:** reconciliation against an external inventory beyond `inventory` entries and `covers`; a comparison of pictures by pixels
|
|
1785
|
+
(only by content); a comparison fetched from the server (the viewer and the command line read the layers themselves).
|
|
1675
1786
|
</doc>
|
|
1676
1787
|
|
|
1677
1788
|
<doc path="docs/server.md">
|
|
@@ -2015,6 +2126,14 @@ edit, and the server's time. Nothing about the layer, its results or the report'
|
|
|
2015
2126
|
See [Tagging artifacts and demos](rich-evidence.md#tagging-artifacts-and-demos) for the tag rules. Reviewer tags are
|
|
2016
2127
|
shown in the viewer's evidence; the tests API (`artifactTag`) searches the producers' tags.
|
|
2017
2128
|
|
|
2129
|
+
## Reading recordings back
|
|
2130
|
+
|
|
2131
|
+
`POST /api/reports/recordings/verification` (publish, `Authorization: Bearer`) reads the stored videos of the newest layers
|
|
2132
|
+
back and checks them; `GET` (read) returns the newest result per layer without reading any blob, so the viewer can mark a
|
|
2133
|
+
run whose recording was stored and then lost, apart from its test results. The result is in memory only and layers
|
|
2134
|
+
that were never read back are absent (unknown, never "fine"). See
|
|
2135
|
+
[Is the recording still there?](rich-evidence.md#is-the-recording-still-there) for what is checked and what is not.
|
|
2136
|
+
|
|
2018
2137
|
## Review collections
|
|
2019
2138
|
|
|
2020
2139
|
A team can publish a named, curated review of a few behaviors: recordings from several explicit executions, notes on
|
|
@@ -2194,6 +2313,10 @@ curl "$ATLAS_SERVER_URL/api/projects/$ATLAS_PROJECT/reports/tests?format=markdow
|
|
|
2194
2313
|
| `GET /api/projects/{project}/reports/artifact-tags` | read | Reviewer tags of attachments: every recorded edit. |
|
|
2195
2314
|
| `POST /api/reports/artifact-tags` | publish | Tag or untag one attachment after upload. |
|
|
2196
2315
|
| `POST /api/projects/{project}/reports/artifact-tags` | publish | Tag or untag one attachment after upload. |
|
|
2316
|
+
| `GET /api/reports/recordings/verification` | read | Which stored recordings the server last read back, and which were gone or damaged. |
|
|
2317
|
+
| `GET /api/projects/{project}/reports/recordings/verification` | read | Which stored recordings the server last read back, and which were gone or damaged. |
|
|
2318
|
+
| `POST /api/reports/recordings/verification` | publish | Read stored recordings back and check them (publish token). |
|
|
2319
|
+
| `POST /api/projects/{project}/reports/recordings/verification` | publish | Read stored recordings back and check them (publish token). |
|
|
2197
2320
|
| `GET /api/reports/review-collections` | read | Review collections: curated sets of recordings, newest first. |
|
|
2198
2321
|
| `GET /api/projects/{project}/reports/review-collections` | read | Review collections: curated sets of recordings, newest first. |
|
|
2199
2322
|
| `POST /api/reports/review-collections` | publish | Publish an immutable review collection (or a new revision of one). |
|
|
@@ -4624,6 +4747,11 @@ it works without a server. Cards are Mantine `Card`s in a responsive `SimpleGrid
|
|
|
4624
4747
|
incomplete. Waiting follows the loading policy below, and layers still arriving are counted.
|
|
4625
4748
|
- Pictures are `loading="lazy"` and only the cards on screen are fetched. The grid is bounded with *Show more*.
|
|
4626
4749
|
- The open state shows every profile side by side with the layer, backend, producer, shard, commit and time of each picture.
|
|
4750
|
+
- **Compare** (`catalog/UiCatalogCompare.tsx`, `?compare=commit|profile&from&to`) sets two commits or two profiles against each other. Two
|
|
4751
|
+
commits need the layers a newer layer replaced, which the held report no longer has, so `catalog/history.ts` reads the layer list and
|
|
4752
|
+
the rows of the two commits only while the comparison is open (sharing the rows cache). Say what "changed" means (the stored bytes
|
|
4753
|
+
differ, not a pixel measure), never call a one-sided state a regression, and say a layer that could not be read is unknown. The
|
|
4754
|
+
coverage filter does not apply to a comparison.
|
|
4627
4755
|
|
|
4628
4756
|
## Reliability
|
|
4629
4757
|
|
|
@@ -4841,7 +4969,7 @@ The narrowly scoped exceptions are:
|
|
|
4841
4969
|
| Area | Screens/interactions | Mantine composition |
|
|
4842
4970
|
| --- | --- | --- |
|
|
4843
4971
|
| Shared shell | Project switching, spec navigation, run selection, connection status, diagnostics, mobile index | AppShell, Burger, NavLink, Menu, Popover, NativeSelect, Drawer |
|
|
4844
|
-
| UI catalog | Captured UI states per profile as cards with coverage badges, filters in the index column, surface coverage, an open state with its profiles side by side and where each picture came from, manifest download | AppShell navbar, SimpleGrid, Card, Image, MultiSelect, TextInput, Drawer, Accordion, Table, Badge, Alert |
|
|
4972
|
+
| UI catalog | Captured UI states per profile as cards with coverage badges, filters in the index column, surface coverage, an open state with its profiles side by side and where each picture came from, manifest download, a Compare of two commits or profiles (SegmentedControl, NativeSelect, Switch) | AppShell navbar, SimpleGrid, Card, Image, MultiSelect, TextInput, Drawer, Accordion, Table, Badge, Alert |
|
|
4845
4973
|
| Project home | Tests/runs/artifacts/compare/catalog health tabs, a two-run comparison with promise, outcome, recording and figure tabs per behavior, a run's Artifacts (files of its layers, shared recordings, direct links), Watch playlist of a filtered set, metrics, search, status/environment/domain/artifact-tag filters, run and artifact facets with saved views, grouping, sorting, show more | Container, Tabs, SimpleGrid, Paper, TextInput, MultiSelect, Popover, Button, Accordion, Modal, Grid, Switch |
|
|
4846
4974
|
| Test detail | Current outcomes, statistics, duration graph, product latency with budgets and baselines, history, artifacts, recording; the `layer` address parameter pins it to one run's result, labelled "This run" against "Latest combined evidence" | Drawer, Table, Badge, Alert, Stage |
|
|
4847
4975
|
| Specs | All six existing kinds, overview/index with title search and folder or declared-domain grouping, Gherkin rules/scenarios/examples with a coverage summary and Read / Watch / Inspect per behavior, Quint declarations/traces, DMN tables, source text | SpecHeader, Accordion, Tabs, Table, CodeHighlightTabs, ResultRow |
|
|
@@ -5217,7 +5345,7 @@ carries it. Upgrade (`bun update @crvouga/atlas --latest`) and remove your worka
|
|
|
5217
5345
|
|
|
5218
5346
|
> Generated from the usage text each command prints (`atlas <command> --help`) by `bun run docs`. Do not edit.
|
|
5219
5347
|
|
|
5220
|
-
Add `--format json` (alias `--json`) to `init`, `report publish`, `stream`, `merge`, `doctor` and `
|
|
5348
|
+
Add `--format json` (alias `--json`) to `init`, `report publish`, `stream`, `merge`, `doctor`, `status` and every `ui-catalog` command for a JSON document on standard output (schemas in `@crvouga/atlas/schemas`). Exit codes: `0` it worked, `1` it ran and the answer is no, `2` the command was wrong.
|
|
5221
5349
|
|
|
5222
5350
|
## atlas
|
|
5223
5351
|
|
|
@@ -5236,6 +5364,7 @@ atlas — executable statecharts
|
|
|
5236
5364
|
atlas dev [--port 5180] develop the Atlas server and client on one host
|
|
5237
5365
|
atlas init [--server <url>] [--write] integrate this project: detect its suites, print the plan (atlas init --help)
|
|
5238
5366
|
atlas report publish|stream|status|merge|doctor|policy … layered evidence for any kind of spec (atlas report --help)
|
|
5367
|
+
atlas ui-catalog plan|publish|status|diff|export … the UI catalog of captured states (atlas ui-catalog --help)
|
|
5239
5368
|
|
|
5240
5369
|
--workers path attempts that run at once (default: one per CPU, capped by the driver)
|
|
5241
5370
|
--seed only paths that start from this seed ("start" for paths setup starts); repeatable
|
|
@@ -5387,6 +5516,60 @@ atlas report — layered evidence for any kind of spec
|
|
|
5387
5516
|
|
|
5388
5517
|
Exit codes: 0 ok, 1 the report does not pass (or a check failed), 2 the command was wrong.
|
|
5389
5518
|
```
|
|
5519
|
+
|
|
5520
|
+
## atlas ui-catalog
|
|
5521
|
+
|
|
5522
|
+
```text
|
|
5523
|
+
atlas ui-catalog — a browsable inventory of captured UI states, from any collector
|
|
5524
|
+
|
|
5525
|
+
atlas ui-catalog plan --states <file.json> --producer <name> [--store <dir|s3://bucket/prefix|https://…>]
|
|
5526
|
+
[--environment <name>] [--param key=value]... [--shard <label>]
|
|
5527
|
+
[--branch <b>] [--sha <s>] [--run-url <u>] [--run-id <id>] [--run-title <t>] [--recorded-at <iso|ms>]
|
|
5528
|
+
atlas ui-catalog publish --captures <file.json> --producer <name> [the same flags as plan]
|
|
5529
|
+
[--attach-root <dir>]... [--max-picture-mb <n>]
|
|
5530
|
+
atlas ui-catalog status [--store <dir|s3://…|id=url>]... [--backends <module>] [filters] [--branch <name>]...
|
|
5531
|
+
[--ignore-modified] [--format text|json|markdown]
|
|
5532
|
+
atlas ui-catalog diff --from <commit> --to <commit> [--store …]... [--backends <module>] [filters]
|
|
5533
|
+
[--fail-on-change] [--format text|json|markdown]
|
|
5534
|
+
atlas ui-catalog export --out <file.html> [--store …]... [--backends <module>] [filters]
|
|
5535
|
+
[--images inline|none] [--max-mb <n>] [--manifest <file.json>] [--title <t>]
|
|
5536
|
+
|
|
5537
|
+
filters (status, diff, export): --q <words> --coverage a,b --profile <key|label>... --area a --route r --cohort c
|
|
5538
|
+
--flag f --surface s --producer p
|
|
5539
|
+
|
|
5540
|
+
plan Write one layer of kind ui-plan: the states (and with "inventory": true, the surfaces) that should exist under
|
|
5541
|
+
this profile. Every entry is not-run, so a plan never counts as a pass. The file is {"states":[{"id":…,
|
|
5542
|
+
"title"?,"route"?,"fixture"?,"cohort"?,"area"?,"flags"?,"covers"?,"inventory"?}]} or just that list.
|
|
5543
|
+
publish Write one layer of kind ui-state: the states one collector or shard captured under this profile. The file is
|
|
5544
|
+
{"states":[{"id":…,"title"?,"status"?:"passed|failed|running|not-run","detail"?,"route"?,"fixture"?,"cohort"?,
|
|
5545
|
+
"area"?,"flags"?,"covers"?,"labels"?,"tags"?,"durationMs"?,"screenshot"?:"file.png"|{"path"|"uri",
|
|
5546
|
+
"width"?,"height"?,"contentType"?}}]}. A picture file is read from beside the file and each --attach-root, never
|
|
5547
|
+
from a hidden file or a link out. A passed state whose picture cannot be read is published as failed, with the
|
|
5548
|
+
reason: a state without its picture is not shown as captured.
|
|
5549
|
+
--environment and each --param key=value are the profile (a viewport, a color scheme, a device): another
|
|
5550
|
+
profile is another result side by side. --shard only describes the layer; it never splits a result.
|
|
5551
|
+
--recorded-at defaults to the modification time of the file, so publishing the same file twice is one layer.
|
|
5552
|
+
status Read every store and print the catalog's summary. Exit 1 unless the catalog holds a state and there is nothing
|
|
5553
|
+
to attend to: a failed capture, a state a plan expects with nothing captured, a capture still in progress, a
|
|
5554
|
+
backend or layer that could not be read. Without a plan nothing is expected, so nothing is missing.
|
|
5555
|
+
--profile takes a profile's key or its label, as printed by status.
|
|
5556
|
+
diff Set the catalog recorded at one commit (--from) against another (--to): each state in each profile is paired
|
|
5557
|
+
with itself and is unchanged, changed in coverage, changed in picture (the stored bytes differ), unverified (a
|
|
5558
|
+
side has no content hash), only in --to (added) or only in --from (removed). A commit is the whole id or at
|
|
5559
|
+
least 7 digits of it. Exit 0 unless a store could not be read, or, with --fail-on-change, anything differs.
|
|
5560
|
+
export Write the catalog as one HTML file with its pictures embedded and its manifest in it: no server, no network.
|
|
5561
|
+
It is the catalog at the moment it was made. --images none leaves the pictures out. --max-mb (default 32) limits
|
|
5562
|
+
the embedded pictures; those past it are listed in the page as left out, and the manifest stays complete.
|
|
5563
|
+
--manifest writes the catalog's JSON manifest too.
|
|
5564
|
+
|
|
5565
|
+
--format json (alias --json) every subcommand prints one JSON document instead of prose
|
|
5566
|
+
(schemas: ui-catalog-publish-result, ui-catalog-status, ui-catalog-diff-result, ui-catalog-export-result).
|
|
5567
|
+
A command that is wrong is {"ok":false,"error":{"message":…,"code":"usage"}} on standard error.
|
|
5568
|
+
A store is a directory, s3://bucket/prefix or an Atlas server (https://…), exactly as for atlas report; select a project
|
|
5569
|
+
with --project <slug> or ATLAS_PROJECT. When no --store is given, ATLAS_STORE is used.
|
|
5570
|
+
|
|
5571
|
+
Exit codes: 0 ok, 1 the answer is no (see each command), 2 the command was wrong.
|
|
5572
|
+
```
|
|
5390
5573
|
</doc>
|
|
5391
5574
|
|
|
5392
5575
|
<doc path="docs/reference/http-api.md">
|
|
@@ -6086,6 +6269,58 @@ Scoped to one project. The same project may be selected on the unprefixed API us
|
|
|
6086
6269
|
|
|
6087
6270
|
Responses: `201` The recorded entry.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `403` The token is known but its role may not do this.; `413` Request too large.; `422` Not a tag edit: a bad target, an empty or over-long tag, or nothing to change.
|
|
6088
6271
|
|
|
6272
|
+
### Which stored recordings the server last read back, and which were gone or damaged
|
|
6273
|
+
|
|
6274
|
+
`GET /api/reports/recordings/verification` · role: read
|
|
6275
|
+
|
|
6276
|
+
The newest read-back the server did of stored videos, per layer: how many it checked, how many passed and the `gaps` (a blob that is gone, bytes of another size or hash than were published, or a file that does not begin like its container), each naming the check that holds the video. `run` is the key of the run the layer belongs to (a `RunSummary.key`), so a viewer can mark that run's recordings as stored-then-unavailable beside its test results.
|
|
6277
|
+
|
|
6278
|
+
This route never reads a blob: it returns what a publish token's `POST` found earlier. A layer that was never read back is absent, which means "not verified", not "fine"; the result is kept in the server's memory only, so a restart empties it. Only layers a store still holds are listed (one removed by garbage collection drops out). No status, slot or winner depends on it. It checks stored bytes, not browser playback. Narrow with `?run=` (a run key) and `?layer=` (an id prefix of at least 7 hex digits, repeatable).
|
|
6279
|
+
|
|
6280
|
+
- `run` (query): Only layers of this run (a key from `GET /api/reports/runs`).
|
|
6281
|
+
- `layer` (query): Only layers whose id starts with this prefix. Repeatable or comma-separated.
|
|
6282
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
6283
|
+
|
|
6284
|
+
Responses: `200` The held read-backs.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
|
|
6285
|
+
|
|
6286
|
+
### Which stored recordings the server last read back, and which were gone or damaged
|
|
6287
|
+
|
|
6288
|
+
`GET /api/projects/{project}/reports/recordings/verification` · role: read
|
|
6289
|
+
|
|
6290
|
+
The newest read-back the server did of stored videos, per layer: how many it checked, how many passed and the `gaps` (a blob that is gone, bytes of another size or hash than were published, or a file that does not begin like its container), each naming the check that holds the video. `run` is the key of the run the layer belongs to (a `RunSummary.key`), so a viewer can mark that run's recordings as stored-then-unavailable beside its test results.
|
|
6291
|
+
|
|
6292
|
+
This route never reads a blob: it returns what a publish token's `POST` found earlier. A layer that was never read back is absent, which means "not verified", not "fine"; the result is kept in the server's memory only, so a restart empties it. Only layers a store still holds are listed (one removed by garbage collection drops out). No status, slot or winner depends on it. It checks stored bytes, not browser playback. Narrow with `?run=` (a run key) and `?layer=` (an id prefix of at least 7 hex digits, repeatable).
|
|
6293
|
+
|
|
6294
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
6295
|
+
|
|
6296
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
6297
|
+
- `run` (query): Only layers of this run (a key from `GET /api/reports/runs`).
|
|
6298
|
+
- `layer` (query): Only layers whose id starts with this prefix. Repeatable or comma-separated.
|
|
6299
|
+
|
|
6300
|
+
Responses: `200` The held read-backs.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
|
|
6301
|
+
|
|
6302
|
+
### Read stored recordings back and check them (publish token)
|
|
6303
|
+
|
|
6304
|
+
`POST /api/reports/recordings/verification` · role: publish
|
|
6305
|
+
|
|
6306
|
+
Reads the videos of the newest layers (`limit`, default 20, at most 200; or the layers `layers` names) back from storage and checks that each is still stored, still has the size and SHA-256 published, and still begins like its media type's container. This reads blobs, so it needs a publish (or admin) token in a Bearer header; a reader-only token, a browser sign-in box and an anonymous reader are refused. One read-back runs at a time (`409` otherwise). It writes nothing to storage and changes no status. The answer is the same document `GET` returns, with `verified`: how many layers this pass read back.
|
|
6307
|
+
|
|
6308
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
6309
|
+
|
|
6310
|
+
Responses: `200` The read-backs now held.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `403` The token is known but its role may not do this.; `409` A read-back is already running.; `413` Request too large.; `422` Not a verification request.; `502` A store could not be read.; `503` The server is still reading its backends. Retry after the number of seconds in `Retry-After`.
|
|
6311
|
+
|
|
6312
|
+
### Read stored recordings back and check them (publish token)
|
|
6313
|
+
|
|
6314
|
+
`POST /api/projects/{project}/reports/recordings/verification` · role: publish
|
|
6315
|
+
|
|
6316
|
+
Reads the videos of the newest layers (`limit`, default 20, at most 200; or the layers `layers` names) back from storage and checks that each is still stored, still has the size and SHA-256 published, and still begins like its media type's container. This reads blobs, so it needs a publish (or admin) token in a Bearer header; a reader-only token, a browser sign-in box and an anonymous reader are refused. One read-back runs at a time (`409` otherwise). It writes nothing to storage and changes no status. The answer is the same document `GET` returns, with `verified`: how many layers this pass read back.
|
|
6317
|
+
|
|
6318
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
6319
|
+
|
|
6320
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
6321
|
+
|
|
6322
|
+
Responses: `200` The read-backs now held.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `403` The token is known but its role may not do this.; `409` A read-back is already running.; `413` Request too large.; `422` Not a verification request.; `502` A store could not be read.; `503` The server is still reading its backends. Retry after the number of seconds in `Retry-After`.
|
|
6323
|
+
|
|
6089
6324
|
### Review collections: curated sets of recordings, newest first
|
|
6090
6325
|
|
|
6091
6326
|
`GET /api/reports/review-collections` · role: read
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crvouga/atlas",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.21.0",
|
|
4
4
|
"description": "Atlas: specs of any kind, reported as layered evidence. Publish checks from any runner (JUnit, CTRF, a script), combine them across nodes, branches, environments and backends, gate CI on the result, and run statecharts against the real app.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|