@recursica/adapter-tester 2.2.0 → 4.0.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/README.md +69 -23
- package/dist/adapter-tester.schema.json.d.ts +24 -11
- package/dist/cli.cjs +32 -23
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +296 -4853
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +57 -6
- package/dist/config.d.ts.map +1 -1
- package/dist/fileConfig.d.ts +21 -5
- package/dist/fileConfig.d.ts.map +1 -1
- package/dist/golden/diffPng.d.ts +13 -0
- package/dist/golden/diffPng.d.ts.map +1 -0
- package/dist/golden/manifest.schema.json.d.ts +27 -0
- package/dist/golden/manifestStore.d.ts +33 -0
- package/dist/golden/manifestStore.d.ts.map +1 -0
- package/dist/golden/resolveSourceOfTruthGolden.d.ts +29 -0
- package/dist/golden/resolveSourceOfTruthGolden.d.ts.map +1 -0
- package/dist/golden/validateManifest.d.ts +7 -0
- package/dist/golden/validateManifest.d.ts.map +1 -0
- package/dist/index-C6uYPRmx.cjs +9 -0
- package/dist/index-C6uYPRmx.cjs.map +1 -0
- package/dist/index-DqQzFSAH.js +4667 -0
- package/dist/index-DqQzFSAH.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +21 -6
- package/dist/index.js.map +1 -1
- package/dist/testing/runVisualRegression.d.ts +48 -6
- package/dist/testing/runVisualRegression.d.ts.map +1 -1
- package/dist/testing.cjs +4 -1
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +311 -155
- package/dist/testing.js.map +1 -1
- package/package.json +4 -7
- package/src/adapter-tester.schema.json +24 -11
- package/src/golden/manifest.schema.json +24 -0
- package/dist/config-B0Eop8Az.cjs +0 -2
- package/dist/config-B0Eop8Az.cjs.map +0 -1
- package/dist/config-CDxTeSAY.js +0 -21
- package/dist/config-CDxTeSAY.js.map +0 -1
package/README.md
CHANGED
|
@@ -8,13 +8,13 @@ The `@recursica/adapter-tester` ensures that a Recursica adapter's components vi
|
|
|
8
8
|
|
|
9
9
|
This package provides three primary utilities:
|
|
10
10
|
|
|
11
|
-
1. **Automated Visual Tests:** Headless,
|
|
11
|
+
1. **Automated Visual Tests:** Headless, golden-image regression checks for all stories, run as a single CLI command (`adapter-tester`) reading a small JSON config — no Playwright config or spec files to author. See [Golden Images](#golden-images) below for the model.
|
|
12
12
|
2. **Interactive Dev Mode:** A side-by-side synchronized browser environment with built-in note taking for auditing components and feeding fixes directly to an AI agent.
|
|
13
|
-
3. **An installable devDependency**,
|
|
13
|
+
3. **An installable devDependency**, wired into `@recursica/mantine-adapter` — the source-of-truth adapter, run in `isSourceOfTruthAdapter` mode (own-drift check only, since it has nothing above it to diverge from). Any other adapter repo — including one that never checked out this monorepo — can install it the same way. See [Using this package in another adapter repo](#using-this-package-in-another-adapter-repo).
|
|
14
14
|
|
|
15
|
-
**Default mode** (used by
|
|
15
|
+
**Default mode** (used by any adapter repo installing this package): checks this project's own Storybook — the one already defined by its `storybook` npm script — against its own committed golden images. No monorepo checkout, no manual config, in most cases no config file at all. Divergence from the source-of-truth adapter's (`@recursica/mantine-adapter`) own golden images is a separate, opt-in check — see [`--divergence-only`](#automated-visual-tests).
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
`@recursica/adapter-tester` itself has no default mode and no `adapter-tester.config.json` of its own — it's purely a tool other adapters install and configure. `mantine-adapter` and `mui-adapter` are the ones that run it, each with their own config.
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
@@ -26,13 +26,15 @@ Installing `@recursica/adapter-tester` as a devDependency (see [below](#using-th
|
|
|
26
26
|
{
|
|
27
27
|
"scripts": {
|
|
28
28
|
"adapter-tester": "adapter-tester --serve",
|
|
29
|
-
"adapter-tester:automated": "adapter-tester"
|
|
29
|
+
"adapter-tester:automated": "adapter-tester",
|
|
30
|
+
"adapter-tester:source-of-truth": "adapter-tester --divergence-only"
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
```
|
|
33
34
|
|
|
34
35
|
- `npm run adapter-tester` — Interactive Dev Mode: boots both Storybooks (reusing them if already running) and opens the synced side-by-side comparison browser.
|
|
35
|
-
- `npm run adapter-tester:automated` — the headless
|
|
36
|
+
- `npm run adapter-tester:automated` — the headless own-drift check against this project's own committed goldens; see [Automated Visual Tests](#automated-visual-tests) below. This is the one to run normally — fast, no network calls.
|
|
37
|
+
- `npm run adapter-tester:source-of-truth` — the separate, opt-in divergence check against the source-of-truth adapter's published goldens. Not wired up for `@recursica/mantine-adapter` itself — it _is_ the source of truth, so it has nothing to diverge from.
|
|
36
38
|
|
|
37
39
|
Both boot Storybooks themselves — nothing needs to be running beforehand.
|
|
38
40
|
|
|
@@ -76,10 +78,11 @@ The Dev Mode server fetches this file dynamically, so any changes you make to `r
|
|
|
76
78
|
|
|
77
79
|
## Automated Visual Tests
|
|
78
80
|
|
|
79
|
-
|
|
81
|
+
Two independent checks, gated by `--divergence-only` — the normal, everyday one and a separate opt-in one:
|
|
80
82
|
|
|
81
83
|
```bash
|
|
82
|
-
npm run adapter-tester:automated
|
|
84
|
+
npm run adapter-tester:automated # own-drift check only — the normal one to run
|
|
85
|
+
npm run adapter-tester:source-of-truth # divergence check only — opt-in, against Mantine
|
|
83
86
|
```
|
|
84
87
|
|
|
85
88
|
`adapter-tester` reads `adapter-tester.config.json` from the current directory (or falls back to defaults if the file doesn't exist), generates a throwaway Playwright config + spec under `.adapter-tester/run/` (git-ignore this directory), and runs it. There's no Playwright config or spec file to hand-author.
|
|
@@ -92,13 +95,22 @@ Any other args are forwarded to `playwright test`, so you can scope a run to spe
|
|
|
92
95
|
npm run adapter-tester:automated -- --grep "Toast"
|
|
93
96
|
```
|
|
94
97
|
|
|
98
|
+
Pin the source-of-truth adapter's version for the divergence check (instead of resolving `@recursica/mantine-adapter`'s `latest` on npm) with `--source-of-truth-version`:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
npm run adapter-tester:source-of-truth -- --source-of-truth-version 0.53.0
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Only meaningful with the default `sourceOfTruth.type: "mantine-harness"` mode — throws if combined with `sourceOfTruth.type: "url"` (that mode reads a sibling package's local checkout directly, there's no version to pin) or with `isSourceOfTruthAdapter: true` (nothing to pin a version for).
|
|
105
|
+
|
|
95
106
|
### What happens during execution?
|
|
96
107
|
|
|
97
|
-
1. **Automatic Storybook Bootup**: `adapter-tester` boots
|
|
98
|
-
2. **Story Discovery**: The test suite fetches
|
|
99
|
-
3. **Headless
|
|
100
|
-
4. **
|
|
101
|
-
5. **
|
|
108
|
+
1. **Automatic Storybook Bootup**: `adapter-tester` boots only this project's own Storybook — the divergence check reads the source-of-truth adapter's stored golden files, never a live Storybook, so nothing else needs to boot.
|
|
109
|
+
2. **Story Discovery**: The test suite fetches this project's own Storybook index (`/index.json`) to dynamically discover and parameterize tests for every component story, excluding `@recursica/storybook-template`'s own default token/theme demo stories (`Theme/*`, `Tokens/*`) and each adapter's own onboarding stories (`Introduction/*`).
|
|
110
|
+
3. **Headless Snapshot**: It launches headless Chrome, navigates to the isolated iframe view, and takes a screenshot. A missing golden is captured from this screenshot regardless of which check is running.
|
|
111
|
+
4. **Own-Drift Check** (`adapter-tester:automated`): Diffs the screenshot against this project's own `test/golden/<story-id>.png` using `pixelmatch`, against the configured mismatch threshold. No golden yet for a story is not a failure — one is captured from this run.
|
|
112
|
+
5. **Divergence Check** (`adapter-tester:source-of-truth`): Diffs this project's own golden against the source-of-truth adapter's golden (skipped for the source-of-truth adapter's own config). Different and not yet reviewed via `--approve-divergence`? Flagged as a report annotation — never a failure on its own.
|
|
113
|
+
6. **Native Report Generation**: Screenshots, diff overlays, and divergence flags are embedded directly as test attachments/annotations.
|
|
102
114
|
|
|
103
115
|
### Output & Reports
|
|
104
116
|
|
|
@@ -113,6 +125,36 @@ All test outcomes and visual outputs are compiled into the standard, git-ignored
|
|
|
113
125
|
|
|
114
126
|
---
|
|
115
127
|
|
|
128
|
+
## Golden Images
|
|
129
|
+
|
|
130
|
+
Each adapter's `test/golden/` directory — committed to git, alongside a `manifest.json` tracking when each was captured — is its own baseline:
|
|
131
|
+
|
|
132
|
+
- **Own-drift check (hard fail):** this run's live render vs this project's own golden. Catches unintended CSS regressions.
|
|
133
|
+
- **Divergence check (soft flag, never fails a run):** this project's own golden vs the source-of-truth adapter's golden — different underlying UI libraries can legitimately render a component differently, so a divergence isn't automatically wrong, just unreviewed.
|
|
134
|
+
|
|
135
|
+
These are explicit, developer-run workflows — not run in CI, and not scoped down automatically; use `--grep` to target specific stories.
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
# Capture/refresh this project's own goldens for stories matching "Toast",
|
|
139
|
+
# from the current live render. Use after an intentional styling change.
|
|
140
|
+
npm run adapter-tester:automated -- --grep "Toast" --update-golden
|
|
141
|
+
|
|
142
|
+
# Review a flagged divergence from the source of truth, and accept it as
|
|
143
|
+
# intentional. Only valid alongside --divergence-only — there's nothing to
|
|
144
|
+
# approve without the divergence check running.
|
|
145
|
+
npm run adapter-tester:source-of-truth -- --grep "Toast" --approve-divergence
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
`--approve-divergence` records the source-of-truth adapter's own `manifest.json` `createdAt` for that story at review time. If the source of truth's golden is recaptured later, the divergence flags again for re-review — approval isn't a permanent exemption.
|
|
149
|
+
|
|
150
|
+
A story with no golden yet (new story, or one never captured) is not a failure in either mode — one is captured from the current run automatically.
|
|
151
|
+
|
|
152
|
+
Renamed/removed stories just leave an orphaned `test/golden/<story-id>.png`/manifest entry behind; nothing prunes these automatically.
|
|
153
|
+
|
|
154
|
+
`manifest.json` is validated against [`src/golden/manifest.schema.json`](./src/golden/manifest.schema.json) on every read/write — don't hand-edit it.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
116
158
|
## Configuring `adapter-tester.config.json`
|
|
117
159
|
|
|
118
160
|
All fields are optional — an adapter repo with a normal `storybook` npm script (e.g. `storybook dev -p 6012`) needs no config file at all.
|
|
@@ -121,13 +163,15 @@ Every `adapter-tester.config.json` is validated against [`src/adapter-tester.sch
|
|
|
121
163
|
|
|
122
164
|
```json
|
|
123
165
|
{
|
|
124
|
-
"$schema": "
|
|
166
|
+
"$schema": "https://raw.githubusercontent.com/borderux/recursica/main/packages/adapter-tester/src/adapter-tester.schema.json",
|
|
125
167
|
"name": "MyAdapter",
|
|
126
168
|
"storybook": { "port": 6006, "command": "npm run storybook" },
|
|
127
169
|
"sourceOfTruth": { "type": "mantine-harness" },
|
|
128
170
|
"diffThresholdPixels": 3500,
|
|
129
|
-
"
|
|
130
|
-
|
|
171
|
+
"stories": {
|
|
172
|
+
"ui-kit-slider": { "threshold": 15000 },
|
|
173
|
+
"ui-kit-slider--range-mode-with-icons-and-inputs": { "exclude": true }
|
|
174
|
+
},
|
|
131
175
|
"excludeTitlePrefixes": ["Theme", "Tokens", "Introduction"]
|
|
132
176
|
}
|
|
133
177
|
```
|
|
@@ -135,9 +179,10 @@ Every `adapter-tester.config.json` is validated against [`src/adapter-tester.sch
|
|
|
135
179
|
- `name` — label for this project's own target. Defaults to the unscoped `package.json` name.
|
|
136
180
|
- `storybook.port` — defaults to whatever `-p`/`--port` is set on this project's own `storybook` script; falls back to Storybook's default of `6006`.
|
|
137
181
|
- `storybook.command`/`storybook.cwd` — default to `npm run storybook` in the current directory.
|
|
138
|
-
- `sourceOfTruth` — defaults to `{ "type": "mantine-harness" }`: a throwaway harness that installs the _published_ `@recursica/mantine-adapter` from npm, so you never need this monorepo checked out. This is the standard mode every external adapter repo (
|
|
139
|
-
- `sourceOfTruth.type: "url"` — the **non-standard** mode: points at an already-addressable Storybook via `command`/`port`/`cwd` instead of the harness
|
|
140
|
-
- `
|
|
182
|
+
- `sourceOfTruth` — defaults to `{ "type": "mantine-harness" }`: a throwaway harness that installs the _published_ `@recursica/mantine-adapter` from npm, so you never need this monorepo checked out. This is the standard mode every external adapter repo uses. `sourceOfTruth.mantineAdapterVersion` pins the version installed/fetched (defaults to `latest`) — or override it per-run with `--source-of-truth-version` instead of hardcoding it in the config.
|
|
183
|
+
- `sourceOfTruth.type: "url"` — the **non-standard** mode: points at an already-addressable Storybook via `command`/`port`/`cwd` instead of the harness, and reads that sibling package's `test/golden/` directly from disk for the divergence check (including uncommitted local changes) instead of resolving a published npm version. For comparing two locally checked-out sibling adapters instead of a published one.
|
|
184
|
+
- `isSourceOfTruthAdapter` — set `true` only in the source-of-truth adapter's own config (`@recursica/mantine-adapter`). Skips `sourceOfTruth`/the divergence check entirely; runs the own-drift check standalone. Also disables Dev Mode (`--serve`) — there's nothing to sync against.
|
|
185
|
+
- `diffThresholdPixels`/`stories`/`excludeTitlePrefixes` — same meaning as before; see `src/adapter-tester.schema.json` for full docs.
|
|
141
186
|
|
|
142
187
|
---
|
|
143
188
|
|
|
@@ -150,11 +195,12 @@ npm install --save-dev @recursica/adapter-tester @playwright/test
|
|
|
150
195
|
npx playwright install chromium
|
|
151
196
|
```
|
|
152
197
|
|
|
153
|
-
If your repo already has a `storybook` npm script with a port set (`storybook dev -p 6006`), no config file is required. Add the
|
|
198
|
+
If your repo already has a `storybook` npm script with a port set (`storybook dev -p 6006`), no config file is required. Add the scripts from [npm scripts](#npm-scripts) above to your `package.json`, then:
|
|
154
199
|
|
|
155
200
|
```bash
|
|
156
|
-
npm run adapter-tester
|
|
157
|
-
npm run adapter-tester:automated
|
|
201
|
+
npm run adapter-tester # Interactive Dev Mode
|
|
202
|
+
npm run adapter-tester:automated # own-drift check — run this normally
|
|
203
|
+
npm run adapter-tester:source-of-truth # divergence check — opt-in, against Mantine
|
|
158
204
|
```
|
|
159
205
|
|
|
160
206
|
Any extra args after `adapter-tester:automated` are passed straight through to `playwright test`, so you can scope a run instead of executing the full suite:
|
|
@@ -163,4 +209,4 @@ Any extra args after `adapter-tester:automated` are passed straight through to `
|
|
|
163
209
|
npm run adapter-tester:automated -- --grep "Toast"
|
|
164
210
|
```
|
|
165
211
|
|
|
166
|
-
Add `adapter-tester.config.json` only to override defaults (see [Configuring `adapter-tester.config.json`](#configuring-adapter-testerconfigjson) above), e.g. to raise the diff threshold or relax specific stories. Add `.adapter-tester/` to your `.gitignore` — it's regenerated on every run.
|
|
212
|
+
Add `adapter-tester.config.json` only to override defaults (see [Configuring `adapter-tester.config.json`](#configuring-adapter-testerconfigjson) above), e.g. to raise the diff threshold or relax specific stories. Add `.adapter-tester/` to your `.gitignore` — it's regenerated on every run. Commit `test/golden/` — that's your project's actual baseline, not a build artifact.
|
|
@@ -8,11 +8,11 @@ declare const _default: {
|
|
|
8
8
|
"properties": {
|
|
9
9
|
"$schema": {
|
|
10
10
|
"type": "string",
|
|
11
|
-
"description": "Optional pointer to this schema for editor autocomplete, e.g. \"
|
|
11
|
+
"description": "Optional pointer to this schema for editor autocomplete, e.g. \"https://raw.githubusercontent.com/borderux/recursica/main/packages/adapter-tester/src/adapter-tester.schema.json\"."
|
|
12
12
|
},
|
|
13
13
|
"name": {
|
|
14
14
|
"type": "string",
|
|
15
|
-
"description": "Label for this project's own target. Defaults to the unscoped name in this project's package.json (e.g. \"@recursica/
|
|
15
|
+
"description": "Label for this project's own target. Defaults to the unscoped name in this project's package.json (e.g. \"@recursica/some-adapter\" -> \"some-adapter\")."
|
|
16
16
|
},
|
|
17
17
|
"storybook": {
|
|
18
18
|
"type": "object",
|
|
@@ -89,20 +89,33 @@ declare const _default: {
|
|
|
89
89
|
}
|
|
90
90
|
]
|
|
91
91
|
},
|
|
92
|
+
"isSourceOfTruthAdapter": {
|
|
93
|
+
"type": "boolean",
|
|
94
|
+
"description": "True only for the source-of-truth adapter's own config (mantine-adapter). Skips `sourceOfTruth` entirely — there's nothing above it to diverge from — and runs the own-drift golden check standalone, against just this project's own Storybook. Defaults to false."
|
|
95
|
+
},
|
|
92
96
|
"diffThresholdPixels": {
|
|
93
97
|
"type": "number",
|
|
94
98
|
"minimum": 0,
|
|
95
99
|
"description": "Global visual diff threshold, in mismatched pixels, before a story is considered a failure. Defaults to 3500. AI agents must not modify this field — see AGENT.md."
|
|
96
100
|
},
|
|
97
|
-
"
|
|
98
|
-
"type": "
|
|
99
|
-
"
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
101
|
+
"stories": {
|
|
102
|
+
"type": "object",
|
|
103
|
+
"additionalProperties": {
|
|
104
|
+
"type": "object",
|
|
105
|
+
"additionalProperties": false,
|
|
106
|
+
"properties": {
|
|
107
|
+
"threshold": {
|
|
108
|
+
"type": "number",
|
|
109
|
+
"minimum": 0,
|
|
110
|
+
"description": "Diff threshold override for matching stories, in mismatched pixels. Overrides `diffThresholdPixels`."
|
|
111
|
+
},
|
|
112
|
+
"exclude": {
|
|
113
|
+
"type": "boolean",
|
|
114
|
+
"description": "Skip matching stories entirely — no own-drift check, no divergence check, no golden captured. For stories that don't have a cross-adapter counterpart; use `excludeTitlePrefixes` to drop a whole title instead."
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
"description": "Per-story overrides, keyed by story id prefix (a story matches if its id equals the key or starts with it). When more than one key matches a story, the longest (most specific) key wins."
|
|
106
119
|
},
|
|
107
120
|
"excludeTitlePrefixes": {
|
|
108
121
|
"type": "array",
|