@recursica/adapter-tester 1.1.0 → 2.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 CHANGED
@@ -8,38 +8,47 @@ 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, pixel-by-pixel regression checks for all stories.
11
+ 1. **Automated Visual Tests:** Headless, pixel-by-pixel 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.
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 library** (`import ... from "@recursica/adapter-tester"`) so any adapter repo — including ones that never checked out this monorepo — can run the same comparison against its own local Storybook. See [Using this package in another adapter repo](#using-this-package-in-another-adapter-repo).
13
+ 3. **An installable devDependency**, currently wired into `@recursica/mui-adapter` (not `@recursica/mantine-adapter` — Mantine is itself the source of truth, so it has nothing to diff against). 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
- Inside this monorepo, it runs its bundled config comparing `@recursica/mantine-adapter` (source of truth) against `@recursica/mui-adapter`, both launched as sibling workspace packages see `adapter-tester.config.ts`.
15
+ **Default mode** (used by `@recursica/mui-adapter`, and any external adapter repo installing this package): compares this project's own Storybook — the one already defined by its `storybook` npm script — against a throwaway harness that installs the _published_ `@recursica/mantine-adapter` from npm. No monorepo checkout, no manual config, in most cases no config file at all.
16
+
17
+ **Non-standard mode**: this monorepo also runs adapter-tester against itself — Mantine and MUI both as local sibling workspace packages — to catch regressions in _uncommitted_ code before it's published. See `adapter-tester.config.json` in this package for that config; it's the same CLI, just pointed at `sourceOfTruth.type: "url"` instead of the default Mantine harness.
16
18
 
17
19
  ---
18
20
 
19
- ## Prerequisites
21
+ ## npm scripts
22
+
23
+ Installing `@recursica/adapter-tester` as a devDependency (see [below](#using-this-package-in-another-adapter-repo)) wires up two scripts:
20
24
 
21
- Before running the tester or dev mode, ensure that both adapter Storybooks are running locally on their assigned odd ports to prevent clashing:
25
+ ```json
26
+ {
27
+ "scripts": {
28
+ "adapter-tester": "adapter-tester --serve",
29
+ "adapter-tester:automated": "adapter-tester"
30
+ }
31
+ }
32
+ ```
22
33
 
23
- - **Mantine Adapter (Source of Truth)**: `http://localhost:6011`
24
- - **MUI Adapter (Target)**: `http://localhost:6012`
34
+ - `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 Playwright pixel-diff suite; see [Automated Visual Tests](#automated-visual-tests) below.
25
36
 
26
- _(Launch these from their respective package directories using `npm run storybook`)_
37
+ Both boot Storybooks themselves nothing needs to be running beforehand.
27
38
 
28
39
  ---
29
40
 
30
41
  ## Interactive Dev Mode
31
42
 
32
- The **Dev Mode** is a powerful visual auditing tool that syncs the Mantine and MUI Storybooks in real-time. When you interact with controls (like toggling 'disabled' or changing 'size') in the Mantine pane, the Dev Mode instantly updates the MUI pane to match that exact state.
43
+ The **Dev Mode** is a powerful visual auditing tool that syncs the source-of-truth and target Storybooks in real-time. When you interact with controls (like toggling 'disabled' or changing 'size') in the left pane, Dev Mode instantly updates the right pane to match that exact state.
33
44
 
34
45
  ### How to Start
35
46
 
36
- 1. Ensure the Storybooks are running on `6011` and `6012`.
37
- 2. Run the Dev Mode server:
38
- ```bash
39
- cd packages/adapter-tester
40
- npm run dev
41
- ```
42
- 3. Open your browser to [http://localhost:6010](http://localhost:6010).
47
+ ```bash
48
+ npm run adapter-tester
49
+ ```
50
+
51
+ This boots both Storybooks (reusing them if already running) and opens [http://localhost:6010](http://localhost:6010) automatically.
43
52
 
44
53
  ### Taking Component Notes
45
54
 
@@ -70,95 +79,76 @@ The Dev Mode server fetches this file dynamically, so any changes you make to `r
70
79
  To execute a full headless visual regression scan across all components:
71
80
 
72
81
  ```bash
73
- cd packages/adapter-tester
74
- npm run test:visual
82
+ npm run adapter-tester:automated # runs the `adapter-tester` CLI
75
83
  ```
76
84
 
85
+ `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.
86
+
87
+ Pass `--dry-run` to print the resolved config and generated files without booting anything — useful for checking what a config resolves to.
88
+
77
89
  ### What happens during execution?
78
90
 
79
- 1. **Automatic Storybook Bootup**: The testing engine checks ports `6011` and `6012`. If they are inactive, it automatically starts the Mantine and MUI Storybooks in the background and cleans them up upon exit. If they are already active, it instantly reuses them.
80
- 2. **Story Discovery**: The test suite fetches the source of truth's Storybook index (`http://localhost:6011/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/*`).
81
- 3. **Headless Snapshots**: It launches headless Chrome in the background, navigates to the isolated iframe views for both adapters, and takes side-by-side snapshots.
82
- 4. **Pixel Diffing**: It diffs the images using `pixelmatch` against our global mismatch threshold.
91
+ 1. **Automatic Storybook Bootup**: `adapter-tester` boots both sides of the comparison this project's own Storybook, and the source-of-truth Storybook (a throwaway Mantine harness by default) reusing them if already running.
92
+ 2. **Story Discovery**: The test suite fetches the source of truth's 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/*`).
93
+ 3. **Headless Snapshots**: It launches headless Chrome in the background, navigates to the isolated iframe views for both targets, and takes side-by-side snapshots.
94
+ 4. **Pixel Diffing**: It diffs the images using `pixelmatch` against the configured mismatch threshold.
83
95
  5. **Native Report Generation**: All raw snapshots, highlighted pixel diff overlays, and extracted computed CSS DOM trees are embedded directly as test attachments.
84
96
 
85
97
  ### Output & Reports
86
98
 
87
99
  All test outcomes and visual outputs are compiled into the standard, git-ignored Playwright reports folder:
88
100
 
89
- - **Interactive HTML Dashboard**: View the full side-by-side browser layout, visual difference overlays, and style audits by opening:
90
- `packages/adapter-tester/playwright-report/index.html`
101
+ - **Interactive HTML Dashboard**: View the full side-by-side browser layout, visual difference overlays, and style audits by opening `playwright-report/index.html`.
91
102
  - **Review in Browser**: Open the interactive dashboard directly from your terminal by running:
92
103
  ```bash
93
104
  npx playwright show-report
94
105
  ```
95
- - **Raw Screenshot Assets**: Individual screenshot buffers and visual diff outputs are retained in the standard `packages/adapter-tester/test-results/` folder for reference.
106
+ - **Raw Screenshot Assets**: Individual screenshot buffers and visual diff outputs are retained in the standard `test-results/` folder for reference.
96
107
 
97
108
  ---
98
109
 
99
- ## Using this package in another adapter repo
100
-
101
- `@recursica/adapter-tester` is a real, installable devDependency — a standalone adapter repo (not checked out inside this monorepo) can use it to diff its own Storybook against Mantine, Recursica's source-of-truth adapter, without cloning this monorepo at all.
102
-
103
- ```bash
104
- npm install --save-dev @recursica/adapter-tester
105
- ```
110
+ ## Configuring `adapter-tester.config.json`
106
111
 
107
- Add a config listing your adapter's already-running local Storybook alongside a Mantine source-of-truth target:
112
+ 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.
108
113
 
109
- ```ts
110
- // adapter-tester.config.ts
111
- import { defineAdapterTesterConfig } from "@recursica/adapter-tester";
114
+ Every `adapter-tester.config.json` is validated against [`src/adapter-tester.schema.json`](./src/adapter-tester.schema.json) before a run — unknown fields, wrong types, and invalid `sourceOfTruth` shapes fail fast with a specific error instead of silently doing the wrong thing. Point your editor at it for autocomplete/inline docs:
112
115
 
113
- export default defineAdapterTesterConfig({
114
- targets: [
115
- { name: "Mantine", url: "http://localhost:6011", sourceOfTruth: true },
116
- { name: "MyAdapter", url: "http://localhost:6006" },
117
- ],
118
- diffThresholdPixels: 3500,
119
- });
116
+ ```json
117
+ {
118
+ "$schema": "./node_modules/@recursica/adapter-tester/src/adapter-tester.schema.json",
119
+ "name": "MyAdapter",
120
+ "storybook": { "port": 6006, "command": "npm run storybook" },
121
+ "sourceOfTruth": { "type": "mantine-harness" },
122
+ "diffThresholdPixels": 3500,
123
+ "relaxedThresholdStoryIds": ["ui-kit-slider"],
124
+ "relaxedThresholdPixels": 15000,
125
+ "excludeTitlePrefixes": ["Theme", "Tokens", "Introduction"]
126
+ }
120
127
  ```
121
128
 
122
- Wire the Mantine side up as a `playwright.config.ts` `webServer` entry with `mantineSourceOfTruthWebServer()` it scaffolds a small throwaway project that installs the real, published `@recursica/mantine-adapter` package and boots a real Storybook from it, so you never need this monorepo checked out:
123
-
124
- ```ts
125
- // playwright.config.ts
126
- import { defineConfig } from "@playwright/test";
127
- import { mantineSourceOfTruthWebServer } from "@recursica/adapter-tester";
128
- import config from "./adapter-tester.config";
129
-
130
- export default defineConfig({
131
- testDir: "./tests",
132
- webServer: [
133
- mantineSourceOfTruthWebServer({
134
- dir: "./.adapter-tester/mantine-harness", // add to .gitignore
135
- port: 6011,
136
- }),
137
- {
138
- command: "npm run storybook", // your own adapter's Storybook
139
- port: 6006,
140
- reuseExistingServer: !process.env.CI,
141
- },
142
- ],
143
- });
144
- ```
129
+ - `name` — label for this project's own target. Defaults to the unscoped `package.json` name.
130
+ - `storybook.port` — defaults to whatever `-p`/`--port` is set on this project's own `storybook` script; falls back to Storybook's default of `6006`.
131
+ - `storybook.command`/`storybook.cwd` — default to `npm run storybook` in the current directory.
132
+ - `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 (and `@recursica/mui-adapter`) uses.
133
+ - `sourceOfTruth.type: "url"` the **non-standard** mode: points at an already-addressable Storybook via `command`/`port`/`cwd` instead of the harness. Used inside this monorepo to compare local, uncommitted `mantine-adapter`/`mui-adapter` workspace packages against each other — see `adapter-tester.config.json` in this package.
134
+ - `diffThresholdPixels`/`relaxedThresholdStoryIds`/`relaxedThresholdPixels`/`excludeTitlePrefixes` same meaning as before; see `src/adapter-tester.schema.json` for full docs.
145
135
 
146
- Then define the test suite itself in a spec file — it diffs every non-source-of-truth target against the source of truth, story by story:
136
+ ---
147
137
 
148
- ```ts
149
- // tests/visual-regression.spec.ts
150
- import { runVisualRegression } from "@recursica/adapter-tester/testing";
151
- import config from "../adapter-tester.config";
138
+ ## Using this package in another adapter repo
152
139
 
153
- await runVisualRegression(config);
154
- ```
140
+ `@recursica/adapter-tester` is a real, installable devDependency — a standalone adapter repo (not checked out inside this monorepo) can use it to diff its own Storybook against Mantine, Recursica's source-of-truth adapter, without cloning this monorepo at all.
155
141
 
156
142
  ```bash
157
- npx playwright test
143
+ npm install --save-dev @recursica/adapter-tester @playwright/test
144
+ npx playwright install chromium
158
145
  ```
159
146
 
160
- Notes:
147
+ If your repo already has a `storybook` npm script with a port set (`storybook dev -p 6006`), no config file is required. Add the two scripts from [npm scripts](#npm-scripts) above to your `package.json`, then:
148
+
149
+ ```bash
150
+ npm run adapter-tester # Interactive Dev Mode
151
+ npm run adapter-tester:automated # headless Playwright suite
152
+ ```
161
153
 
162
- - `mantineSourceOfTruthWebServer()` regenerates its harness directory on every run commit `.adapter-tester/` to your `.gitignore` rather than checking it in.
163
- - Pass `mantineAdapterVersion`/`storybookTemplateVersion` to pin the harness to a specific published release instead of tracking `latest`.
164
- - `defineAdapterTesterConfig` requires exactly one target marked `sourceOfTruth: true`; it throws otherwise.
154
+ 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.
@@ -0,0 +1,116 @@
1
+ declare const _default: {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://github.com/borderux/recursica/tree/main/packages/adapter-tester/src/adapter-tester.schema.json",
4
+ "title": "adapter-tester.config.json",
5
+ "description": "Configuration for @recursica/adapter-tester. All fields are optional — an adapter repo with a normal `storybook` npm script needs no config file at all.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "$schema": {
10
+ "type": "string",
11
+ "description": "Optional pointer to this schema for editor autocomplete, e.g. \"./node_modules/@recursica/adapter-tester/src/adapter-tester.schema.json\"."
12
+ },
13
+ "name": {
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/mui-adapter\" -> \"mui-adapter\")."
16
+ },
17
+ "storybook": {
18
+ "type": "object",
19
+ "additionalProperties": false,
20
+ "description": "This project's own Storybook target.",
21
+ "properties": {
22
+ "port": {
23
+ "type": "integer",
24
+ "minimum": 1,
25
+ "maximum": 65535,
26
+ "description": "Port the target's Storybook is served on. Auto-detected from this project's own `scripts.storybook` (a `-p <port>`/`--port <port>` flag) when omitted, falling back to Storybook's own default of 6006."
27
+ },
28
+ "command": {
29
+ "type": "string",
30
+ "description": "Command that boots the target's Storybook. Defaults to `npm run storybook`."
31
+ },
32
+ "cwd": {
33
+ "type": "string",
34
+ "description": "Directory the command runs in, relative to the config file. Defaults to \".\"."
35
+ }
36
+ }
37
+ },
38
+ "sourceOfTruth": {
39
+ "description": "The comparison target. Defaults to `{ \"type\": \"mantine-harness\" }`.",
40
+ "oneOf": [
41
+ {
42
+ "type": "object",
43
+ "additionalProperties": false,
44
+ "description": "Default mode: boots a throwaway harness that installs the published @recursica/mantine-adapter from npm — no monorepo checkout required.",
45
+ "properties": {
46
+ "type": { "const": "mantine-harness" },
47
+ "port": {
48
+ "type": "integer",
49
+ "minimum": 1,
50
+ "maximum": 65535,
51
+ "description": "Port the throwaway harness's Storybook is served on. Defaults to 6011."
52
+ },
53
+ "mantineAdapterVersion": {
54
+ "type": "string",
55
+ "description": "npm version/tag of @recursica/mantine-adapter to install in the harness. Defaults to `latest`."
56
+ },
57
+ "storybookTemplateVersion": {
58
+ "type": "string",
59
+ "description": "npm version/tag of @recursica/storybook-template to install in the harness. Defaults to `latest`."
60
+ }
61
+ }
62
+ },
63
+ {
64
+ "type": "object",
65
+ "additionalProperties": false,
66
+ "description": "Non-standard mode: points at an already-addressable Storybook — e.g. a sibling workspace package's own Storybook inside this monorepo.",
67
+ "required": ["type", "port"],
68
+ "properties": {
69
+ "type": { "const": "url" },
70
+ "name": {
71
+ "type": "string",
72
+ "description": "Label for the source-of-truth target. Defaults to \"Mantine\"."
73
+ },
74
+ "port": {
75
+ "type": "integer",
76
+ "minimum": 1,
77
+ "maximum": 65535,
78
+ "description": "Port the source-of-truth Storybook is served on."
79
+ },
80
+ "command": {
81
+ "type": "string",
82
+ "description": "Command that boots the source-of-truth Storybook. Defaults to `npm run storybook`."
83
+ },
84
+ "cwd": {
85
+ "type": "string",
86
+ "description": "Directory the command runs in, relative to the config file. Defaults to \".\"."
87
+ }
88
+ }
89
+ }
90
+ ]
91
+ },
92
+ "diffThresholdPixels": {
93
+ "type": "number",
94
+ "minimum": 0,
95
+ "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
+ },
97
+ "relaxedThresholdStoryIds": {
98
+ "type": "array",
99
+ "items": { "type": "string" },
100
+ "description": "Story id prefixes that use `relaxedThresholdPixels` instead of the global `diffThresholdPixels`."
101
+ },
102
+ "relaxedThresholdPixels": {
103
+ "type": "number",
104
+ "minimum": 0,
105
+ "description": "Diff threshold applied to stories matching `relaxedThresholdStoryIds`."
106
+ },
107
+ "excludeTitlePrefixes": {
108
+ "type": "array",
109
+ "items": { "type": "string" },
110
+ "description": "Storybook title prefixes to exclude from comparison, in addition to the built-in denylist (`Theme/*`, `Tokens/*`, `Introduction`)."
111
+ }
112
+ }
113
+ }
114
+ ;
115
+
116
+ export default _default;