@recursica/adapter-tester 1.1.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 +164 -0
- package/dist/config-B0Eop8Az.cjs +2 -0
- package/dist/config-B0Eop8Az.cjs.map +1 -0
- package/dist/config-CKgyDyNF.js +23 -0
- package/dist/config-CKgyDyNF.js.map +1 -0
- package/dist/config.d.ts +37 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/extractDomNode.d.ts +11 -0
- package/dist/extractDomNode.d.ts.map +1 -0
- package/dist/harness/mantineSourceOfTruth.d.ts +42 -0
- package/dist/harness/mantineSourceOfTruth.d.ts.map +1 -0
- package/dist/index.cjs +54 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.html +461 -0
- package/dist/index.js +120 -0
- package/dist/index.js.map +1 -0
- package/dist/testing/runVisualRegression.d.ts +10 -0
- package/dist/testing/runVisualRegression.d.ts.map +1 -0
- package/dist/testing.cjs +2 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.ts +2 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +143 -0
- package/dist/testing.js.map +1 -0
- package/package.json +70 -0
package/dist/testing.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { test as M, expect as J } from "@playwright/test";
|
|
2
|
+
import _ from "pixelmatch";
|
|
3
|
+
import { PNG as h } from "pngjs";
|
|
4
|
+
import g from "node:fs";
|
|
5
|
+
import { g as U } from "./config-CKgyDyNF.js";
|
|
6
|
+
const z = ["Theme", "Tokens", "Introduction"], j = [
|
|
7
|
+
"color",
|
|
8
|
+
"background-color",
|
|
9
|
+
"padding-top",
|
|
10
|
+
"padding-right",
|
|
11
|
+
"padding-bottom",
|
|
12
|
+
"padding-left",
|
|
13
|
+
"margin-top",
|
|
14
|
+
"margin-right",
|
|
15
|
+
"margin-bottom",
|
|
16
|
+
"margin-left",
|
|
17
|
+
"border-top-left-radius",
|
|
18
|
+
"border-top-right-radius",
|
|
19
|
+
"border-bottom-left-radius",
|
|
20
|
+
"border-bottom-right-radius",
|
|
21
|
+
"font-size",
|
|
22
|
+
"font-weight",
|
|
23
|
+
"display",
|
|
24
|
+
"flex-direction",
|
|
25
|
+
"gap",
|
|
26
|
+
"height"
|
|
27
|
+
];
|
|
28
|
+
function v(t) {
|
|
29
|
+
return t.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
30
|
+
}
|
|
31
|
+
async function R(t, r) {
|
|
32
|
+
let c;
|
|
33
|
+
try {
|
|
34
|
+
const i = await fetch(`${t.url}/index.json`);
|
|
35
|
+
if (!i.ok)
|
|
36
|
+
throw new Error(`Failed to fetch Storybook index: ${i.statusText}`);
|
|
37
|
+
const m = (await i.json()).entries || {};
|
|
38
|
+
c = Object.values(m).filter(
|
|
39
|
+
(a) => a.type === "story" && !r.some(
|
|
40
|
+
(e) => a.title === e || a.title.startsWith(`${e}/`)
|
|
41
|
+
)
|
|
42
|
+
), c.sort((a, e) => a.id.localeCompare(e.id));
|
|
43
|
+
} catch (i) {
|
|
44
|
+
throw console.error(
|
|
45
|
+
"Failed to load Storybook index from",
|
|
46
|
+
`${t.url}/index.json`,
|
|
47
|
+
i
|
|
48
|
+
), new Error(
|
|
49
|
+
`Storybook source of truth "${t.name}" is not responsive or index.json is missing. Please ensure its Storybook is running.`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
return c;
|
|
53
|
+
}
|
|
54
|
+
async function G(t) {
|
|
55
|
+
const r = U(t), c = t.targets.filter((e) => !e.sourceOfTruth), i = t.excludeTitlePrefixes ?? z, $ = t.relaxedThresholdStoryIds ?? [], m = t.relaxedThresholdPixels, a = await R(r, i);
|
|
56
|
+
for (const e of c)
|
|
57
|
+
M.describe(
|
|
58
|
+
`${r.name} vs ${e.name} — Dynamic Visual Regression Suite`,
|
|
59
|
+
() => {
|
|
60
|
+
for (const o of a)
|
|
61
|
+
M(`Visual regression for: ${o.title} - ${o.name} (${o.id})`, async ({ browser: b }, l) => {
|
|
62
|
+
const s = await b.newPage(), n = await b.newPage();
|
|
63
|
+
await s.setViewportSize({ width: 800, height: 600 }), await n.setViewportSize({ width: 800, height: 600 }), await Promise.all([
|
|
64
|
+
s.goto(
|
|
65
|
+
`${r.url}/iframe.html?id=${o.id}&viewMode=story`,
|
|
66
|
+
{ waitUntil: "networkidle" }
|
|
67
|
+
),
|
|
68
|
+
n.goto(
|
|
69
|
+
`${e.url}/iframe.html?id=${o.id}&viewMode=story`,
|
|
70
|
+
{ waitUntil: "networkidle" }
|
|
71
|
+
)
|
|
72
|
+
]), await Promise.all([
|
|
73
|
+
s.waitForSelector("#storybook-root"),
|
|
74
|
+
n.waitForSelector("#storybook-root")
|
|
75
|
+
]), await Promise.all([
|
|
76
|
+
s.waitForTimeout(300),
|
|
77
|
+
n.waitForTimeout(300)
|
|
78
|
+
]);
|
|
79
|
+
const x = (y) => {
|
|
80
|
+
function D(S) {
|
|
81
|
+
const T = {
|
|
82
|
+
tag: S.tagName.toLowerCase(),
|
|
83
|
+
styles: {},
|
|
84
|
+
children: []
|
|
85
|
+
}, V = window.getComputedStyle(S);
|
|
86
|
+
for (const u of y)
|
|
87
|
+
T.styles[u] = V.getPropertyValue(u);
|
|
88
|
+
for (const u of Array.from(S.children))
|
|
89
|
+
T.children.push(D(u));
|
|
90
|
+
return T;
|
|
91
|
+
}
|
|
92
|
+
const E = document.querySelector("#storybook-root");
|
|
93
|
+
return E ? D(E) : null;
|
|
94
|
+
}, O = await s.evaluate(
|
|
95
|
+
x,
|
|
96
|
+
j
|
|
97
|
+
), P = await n.evaluate(
|
|
98
|
+
x,
|
|
99
|
+
j
|
|
100
|
+
);
|
|
101
|
+
await l.attach(`${r.name} DOM Tree JSON`, {
|
|
102
|
+
body: JSON.stringify(O, null, 2),
|
|
103
|
+
contentType: "application/json"
|
|
104
|
+
}), await l.attach(`${e.name} DOM Tree JSON`, {
|
|
105
|
+
body: JSON.stringify(P, null, 2),
|
|
106
|
+
contentType: "application/json"
|
|
107
|
+
});
|
|
108
|
+
const F = v(r.name), k = v(e.name);
|
|
109
|
+
g.writeFileSync(
|
|
110
|
+
`/tmp/${o.id}-${F}DOM.json`,
|
|
111
|
+
JSON.stringify(O, null, 2)
|
|
112
|
+
), g.writeFileSync(
|
|
113
|
+
`/tmp/${o.id}-${k}DOM.json`,
|
|
114
|
+
JSON.stringify(P, null, 2)
|
|
115
|
+
);
|
|
116
|
+
const w = await s.screenshot(), f = await n.screenshot(), d = h.sync.read(w), N = h.sync.read(f), p = new h({ width: d.width, height: d.height }), C = _(
|
|
117
|
+
d.data,
|
|
118
|
+
N.data,
|
|
119
|
+
p.data,
|
|
120
|
+
d.width,
|
|
121
|
+
d.height,
|
|
122
|
+
{ threshold: 0.1 }
|
|
123
|
+
);
|
|
124
|
+
g.writeFileSync(`/tmp/${o.id}-diff.png`, h.sync.write(p)), g.writeFileSync(`/tmp/${o.id}-${F}.png`, w), g.writeFileSync(`/tmp/${o.id}-${k}.png`, f), await l.attach("Visual Diff Overlay", {
|
|
125
|
+
body: h.sync.write(p),
|
|
126
|
+
contentType: "image/png"
|
|
127
|
+
}), await l.attach(`${r.name} Screenshot (Source of Truth)`, {
|
|
128
|
+
body: w,
|
|
129
|
+
contentType: "image/png"
|
|
130
|
+
}), await l.attach(`${e.name} Screenshot (Target)`, {
|
|
131
|
+
body: f,
|
|
132
|
+
contentType: "image/png"
|
|
133
|
+
});
|
|
134
|
+
const L = m !== void 0 && $.some((y) => o.id.startsWith(y)) ? m : t.diffThresholdPixels;
|
|
135
|
+
J.soft(C).toBeLessThan(L);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
export {
|
|
141
|
+
G as runVisualRegression
|
|
142
|
+
};
|
|
143
|
+
//# sourceMappingURL=testing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.js","sources":["../src/testing/runVisualRegression.ts"],"sourcesContent":["import { test, expect } from \"@playwright/test\";\nimport pixelmatch from \"pixelmatch\";\nimport { PNG } from \"pngjs\";\nimport fs from \"node:fs\";\nimport type { AdapterTarget, AdapterTesterConfig } from \"../config.js\";\nimport { getSourceOfTruth } from \"../config.js\";\n\nconst DEFAULT_EXCLUDE_TITLE_PREFIXES = [\"Theme\", \"Tokens\", \"Introduction\"];\n\nconst COMMON_STYLES_TO_CAPTURE = [\n \"color\",\n \"background-color\",\n \"padding-top\",\n \"padding-right\",\n \"padding-bottom\",\n \"padding-left\",\n \"margin-top\",\n \"margin-right\",\n \"margin-bottom\",\n \"margin-left\",\n \"border-top-left-radius\",\n \"border-top-right-radius\",\n \"border-bottom-left-radius\",\n \"border-bottom-right-radius\",\n \"font-size\",\n \"font-weight\",\n \"display\",\n \"flex-direction\",\n \"gap\",\n \"height\",\n];\n\ninterface StorybookEntry {\n type: string;\n id: string;\n name: string;\n title: string;\n}\n\nfunction slug(name: string): string {\n return name.toLowerCase().replace(/[^a-z0-9]+/g, \"-\");\n}\n\nasync function fetchStories(\n sourceOfTruth: AdapterTarget,\n excludeTitlePrefixes: string[],\n): Promise<StorybookEntry[]> {\n let stories: StorybookEntry[];\n try {\n const response = await fetch(`${sourceOfTruth.url}/index.json`);\n if (!response.ok) {\n throw new Error(`Failed to fetch Storybook index: ${response.statusText}`);\n }\n const data = (await response.json()) as any;\n const entries = data.entries || {};\n stories = Object.values(entries).filter(\n (entry: any) =>\n entry.type === \"story\" &&\n !excludeTitlePrefixes.some(\n (prefix) =>\n entry.title === prefix || entry.title.startsWith(`${prefix}/`),\n ),\n ) as StorybookEntry[];\n stories.sort((a, b) => a.id.localeCompare(b.id));\n } catch (error) {\n console.error(\n \"Failed to load Storybook index from\",\n `${sourceOfTruth.url}/index.json`,\n error,\n );\n throw new Error(\n `Storybook source of truth \"${sourceOfTruth.name}\" is not responsive or index.json is missing. Please ensure its Storybook is running.`,\n );\n }\n return stories;\n}\n\n/**\n * Defines a Playwright suite that diffs every target in `config.targets`\n * against `config.targets`' single `sourceOfTruth` entry, story by story.\n * Call this with a top-level `await` from a Playwright `*.spec.ts` file — it\n * calls `test.describe` at module scope, so it must run inside Playwright's\n * test runner during test-graph compilation.\n */\nexport async function runVisualRegression(\n config: AdapterTesterConfig,\n): Promise<void> {\n const sourceOfTruth = getSourceOfTruth(config);\n const targets = config.targets.filter((target) => !target.sourceOfTruth);\n const excludeTitlePrefixes =\n config.excludeTitlePrefixes ?? DEFAULT_EXCLUDE_TITLE_PREFIXES;\n const relaxedThresholdStoryIds = config.relaxedThresholdStoryIds ?? [];\n const relaxedThresholdPixels = config.relaxedThresholdPixels;\n\n // Fetched once at test-graph compilation time and shared by every target's\n // describe block below.\n const stories = await fetchStories(sourceOfTruth, excludeTitlePrefixes);\n\n for (const target of targets) {\n test.describe(\n `${sourceOfTruth.name} vs ${target.name} — Dynamic Visual Regression Suite`,\n () => {\n for (const story of stories) {\n test(`Visual regression for: ${story.title} - ${story.name} (${story.id})`, async (\n { browser },\n testInfo,\n ) => {\n const sourcePage = await browser.newPage();\n const targetPage = await browser.newPage();\n\n await sourcePage.setViewportSize({ width: 800, height: 600 });\n await targetPage.setViewportSize({ width: 800, height: 600 });\n\n await Promise.all([\n sourcePage.goto(\n `${sourceOfTruth.url}/iframe.html?id=${story.id}&viewMode=story`,\n { waitUntil: \"networkidle\" },\n ),\n targetPage.goto(\n `${target.url}/iframe.html?id=${story.id}&viewMode=story`,\n { waitUntil: \"networkidle\" },\n ),\n ]);\n\n await Promise.all([\n sourcePage.waitForSelector(\"#storybook-root\"),\n targetPage.waitForSelector(\"#storybook-root\"),\n ]);\n\n await Promise.all([\n sourcePage.waitForTimeout(300),\n targetPage.waitForTimeout(300),\n ]);\n\n // 1. EXTRACT DOM STRUCTURE AND STYLES\n const extractFn = (stylesToCapture: string[]) => {\n function crawl(el: Element): any {\n const data: any = {\n tag: el.tagName.toLowerCase(),\n styles: {},\n children: [],\n };\n const computed = window.getComputedStyle(el);\n for (const prop of stylesToCapture) {\n data.styles[prop] = computed.getPropertyValue(prop);\n }\n for (const child of Array.from(el.children)) {\n data.children.push(crawl(child));\n }\n return data;\n }\n const root = document.querySelector(\"#storybook-root\");\n return root ? crawl(root) : null;\n };\n\n const sourceDOM = await sourcePage.evaluate(\n extractFn,\n COMMON_STYLES_TO_CAPTURE,\n );\n const targetDOM = await targetPage.evaluate(\n extractFn,\n COMMON_STYLES_TO_CAPTURE,\n );\n\n await testInfo.attach(`${sourceOfTruth.name} DOM Tree JSON`, {\n body: JSON.stringify(sourceDOM, null, 2),\n contentType: \"application/json\",\n });\n await testInfo.attach(`${target.name} DOM Tree JSON`, {\n body: JSON.stringify(targetDOM, null, 2),\n contentType: \"application/json\",\n });\n\n const sourceSlug = slug(sourceOfTruth.name);\n const targetSlug = slug(target.name);\n fs.writeFileSync(\n `/tmp/${story.id}-${sourceSlug}DOM.json`,\n JSON.stringify(sourceDOM, null, 2),\n );\n fs.writeFileSync(\n `/tmp/${story.id}-${targetSlug}DOM.json`,\n JSON.stringify(targetDOM, null, 2),\n );\n\n // 2. CAPTURE Headless Viewport Screenshots\n const sourceBuffer = await sourcePage.screenshot();\n const targetBuffer = await targetPage.screenshot();\n\n // 3. PIXEL-BY-PIXEL COMPARISON\n const img1 = PNG.sync.read(sourceBuffer);\n const img2 = PNG.sync.read(targetBuffer);\n const diff = new PNG({ width: img1.width, height: img1.height });\n\n const diffPixels = pixelmatch(\n img1.data,\n img2.data,\n diff.data,\n img1.width,\n img1.height,\n { threshold: 0.1 },\n );\n\n fs.writeFileSync(`/tmp/${story.id}-diff.png`, PNG.sync.write(diff));\n fs.writeFileSync(`/tmp/${story.id}-${sourceSlug}.png`, sourceBuffer);\n fs.writeFileSync(`/tmp/${story.id}-${targetSlug}.png`, targetBuffer);\n\n await testInfo.attach(\"Visual Diff Overlay\", {\n body: PNG.sync.write(diff),\n contentType: \"image/png\",\n });\n await testInfo.attach(`${sourceOfTruth.name} Screenshot (Source of Truth)`, {\n body: sourceBuffer,\n contentType: \"image/png\",\n });\n await testInfo.attach(`${target.name} Screenshot (Target)`, {\n body: targetBuffer,\n contentType: \"image/png\",\n });\n\n const threshold =\n relaxedThresholdPixels !== undefined &&\n relaxedThresholdStoryIds.some((id) => story.id.startsWith(id))\n ? relaxedThresholdPixels\n : config.diffThresholdPixels;\n\n // Perform soft assertions so failures are logged but other stories continue\n expect.soft(diffPixels).toBeLessThan(threshold);\n });\n }\n },\n );\n }\n}\n"],"names":["DEFAULT_EXCLUDE_TITLE_PREFIXES","COMMON_STYLES_TO_CAPTURE","slug","name","fetchStories","sourceOfTruth","excludeTitlePrefixes","stories","response","entries","entry","prefix","b","error","runVisualRegression","config","getSourceOfTruth","targets","target","relaxedThresholdStoryIds","relaxedThresholdPixels","test","story","browser","testInfo","sourcePage","targetPage","extractFn","stylesToCapture","crawl","el","data","computed","prop","child","root","sourceDOM","targetDOM","sourceSlug","targetSlug","fs","sourceBuffer","targetBuffer","img1","PNG","img2","diff","diffPixels","pixelmatch","threshold","id","expect"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@recursica/adapter-tester",
|
|
3
|
+
"description": "Visual regression tester between Recursica adapters — usable inside the Recursica monorepo, or installed standalone as a devDependency in any adapter repo to diff its Storybook against Mantine as the source of truth.",
|
|
4
|
+
"private": false,
|
|
5
|
+
"homepage": "https://github.com/borderux/recursica/tree/main/packages/adapter-tester",
|
|
6
|
+
"author": "hi@borderux.com",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"bugs": {
|
|
9
|
+
"url": "https://github.com/borderux/recursica/issues"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/borderux/recursica.git",
|
|
14
|
+
"directory": "packages/adapter-tester"
|
|
15
|
+
},
|
|
16
|
+
"version": "1.1.0",
|
|
17
|
+
"type": "module",
|
|
18
|
+
"main": "./dist/index.cjs",
|
|
19
|
+
"module": "./dist/index.js",
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"import": "./dist/index.js",
|
|
25
|
+
"require": "./dist/index.cjs"
|
|
26
|
+
},
|
|
27
|
+
"./testing": {
|
|
28
|
+
"types": "./dist/testing.d.ts",
|
|
29
|
+
"import": "./dist/testing.js",
|
|
30
|
+
"require": "./dist/testing.cjs"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist"
|
|
35
|
+
],
|
|
36
|
+
"keywords": [
|
|
37
|
+
"recursica",
|
|
38
|
+
"storybook",
|
|
39
|
+
"visual-regression",
|
|
40
|
+
"testing",
|
|
41
|
+
"playwright"
|
|
42
|
+
],
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "vite build --mode library",
|
|
45
|
+
"test:visual": "playwright test",
|
|
46
|
+
"dev": "ts-node src/dev.ts"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"pixelmatch": "^7.2.0",
|
|
50
|
+
"pngjs": "^7.0.0"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"@playwright/test": ">=1.40.0"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@playwright/test": "^1.60.0",
|
|
57
|
+
"@repo/typescript-config": "*",
|
|
58
|
+
"@types/node": "^25.9.1",
|
|
59
|
+
"@types/pixelmatch": "^5.2.6",
|
|
60
|
+
"@types/pngjs": "^6.0.5",
|
|
61
|
+
"express": "^5.2.1",
|
|
62
|
+
"http-proxy-middleware": "^4.0.0",
|
|
63
|
+
"playwright": "^1.60.0",
|
|
64
|
+
"ts-node": "^10.9.2",
|
|
65
|
+
"tsx": "^4.22.3",
|
|
66
|
+
"typescript": "~5.8.3",
|
|
67
|
+
"vite": "^6.3.5",
|
|
68
|
+
"vite-plugin-dts": "^4.5.4"
|
|
69
|
+
}
|
|
70
|
+
}
|