tuffgal 0.2.0-alpha.3 → 0.2.0-alpha.4
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 +34 -20
- package/README.md +6 -6
- package/dist/cli.d.ts +5 -5
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +12 -5
- package/dist/cli.js.map +1 -1
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.js +6 -6
- package/dist/commands/supervise.d.ts +3 -3
- package/dist/commands/supervise.js +8 -4
- package/dist/commands/supervise.js.map +1 -1
- package/dist/config.d.ts +29 -13
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +5 -2
- package/dist/config.js.map +1 -1
- package/dist/coverage/screens.d.ts +10 -5
- package/dist/coverage/screens.d.ts.map +1 -1
- package/dist/coverage/screens.js +18 -8
- package/dist/coverage/screens.js.map +1 -1
- package/dist/reporter/assets/report.css +11 -11
- package/dist/reporter/assets/report.js +23 -23
- package/dist/reporter/template.js +48 -46
- package/dist/reporter/template.js.map +1 -1
- package/dist/runner/approve.d.ts +5 -5
- package/dist/runner/approve.js +5 -5
- package/dist/runner/approveFrom.d.ts +8 -8
- package/dist/runner/approveFrom.js +32 -31
- package/dist/runner/approveFrom.js.map +1 -1
- package/dist/runner/breakpointPasses.d.ts +16 -9
- package/dist/runner/breakpointPasses.d.ts.map +1 -1
- package/dist/runner/breakpointPasses.js +17 -9
- package/dist/runner/breakpointPasses.js.map +1 -1
- package/dist/runner/bridges/devServers.d.ts +10 -1
- package/dist/runner/bridges/devServers.d.ts.map +1 -1
- package/dist/runner/bridges/devServers.js +16 -8
- package/dist/runner/bridges/devServers.js.map +1 -1
- package/dist/runner/coverage.d.ts +3 -3
- package/dist/runner/coverage.js +5 -5
- package/dist/runner/coverage.js.map +1 -1
- package/dist/runner/exitCode.d.ts +7 -7
- package/dist/runner/exitCode.js +7 -7
- package/dist/runner/interpolate.js +1 -1
- package/dist/runner/interpolate.js.map +1 -1
- package/dist/runner/manifest.d.ts +16 -16
- package/dist/runner/manifest.js +12 -12
- package/dist/runner/mode.d.ts +2 -2
- package/dist/runner/mode.js +4 -4
- package/dist/runner/orphanScan.d.ts +3 -3
- package/dist/runner/orphanScan.js +5 -5
- package/dist/runner/orphanScan.js.map +1 -1
- package/dist/runner/resolveLocator.d.ts +5 -5
- package/dist/runner/resolveLocator.js +6 -6
- package/dist/runner/resolveLocator.js.map +1 -1
- package/dist/runner/run.d.ts +55 -18
- package/dist/runner/run.d.ts.map +1 -1
- package/dist/runner/run.js +118 -67
- package/dist/runner/run.js.map +1 -1
- package/dist/runner/runAction.d.ts +4 -4
- package/dist/runner/runAction.d.ts.map +1 -1
- package/dist/runner/runAction.js +72 -34
- package/dist/runner/runAction.js.map +1 -1
- package/dist/runner/runStory.d.ts +29 -18
- package/dist/runner/runStory.d.ts.map +1 -1
- package/dist/runner/runStory.js +38 -42
- package/dist/runner/runStory.js.map +1 -1
- package/dist/runner/scheduler.d.ts +11 -0
- package/dist/runner/scheduler.d.ts.map +1 -1
- package/dist/runner/scheduler.js +1 -1
- package/dist/runner/scheduler.js.map +1 -1
- package/dist/runner/steps/intercept.d.ts +6 -4
- package/dist/runner/steps/intercept.d.ts.map +1 -1
- package/dist/runner/steps/intercept.js.map +1 -1
- package/dist/runner/steps/navigate.d.ts +5 -2
- package/dist/runner/steps/navigate.d.ts.map +1 -1
- package/dist/runner/steps/navigate.js +17 -3
- package/dist/runner/steps/navigate.js.map +1 -1
- package/dist/runner/steps/read.d.ts +1 -1
- package/dist/runner/steps/read.js +1 -1
- package/dist/runner/steps/scroll.d.ts +1 -1
- package/dist/runner/steps/scroll.d.ts.map +1 -1
- package/dist/runner/steps/scroll.js +3 -2
- package/dist/runner/steps/scroll.js.map +1 -1
- package/dist/schema/action.d.ts +2 -2
- package/dist/schema/action.d.ts.map +1 -1
- package/dist/schema/action.js +58 -13
- package/dist/schema/action.js.map +1 -1
- package/dist/schema/load.js +1 -1
- package/dist/schema/load.js.map +1 -1
- package/dist/schema/result.d.ts +22 -22
- package/dist/schema/result.d.ts.map +1 -1
- package/dist/schema/result.js +1 -1
- package/dist/schema/story.d.ts +1 -1
- package/dist/schema/story.js +5 -5
- package/dist/screenshots/baselineStore.d.ts +44 -21
- package/dist/screenshots/baselineStore.d.ts.map +1 -1
- package/dist/screenshots/baselineStore.js +59 -28
- package/dist/screenshots/baselineStore.js.map +1 -1
- package/dist/screenshots/capture.d.ts +35 -4
- package/dist/screenshots/capture.d.ts.map +1 -1
- package/dist/screenshots/capture.js +61 -9
- package/dist/screenshots/capture.js.map +1 -1
- package/dist/screenshots/diff.d.ts +57 -8
- package/dist/screenshots/diff.d.ts.map +1 -1
- package/dist/screenshots/diff.js +78 -28
- package/dist/screenshots/diff.js.map +1 -1
- package/dist/util.d.ts +23 -2
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +42 -2
- package/dist/util.js.map +1 -1
- package/package.json +4 -8
package/dist/screenshots/diff.js
CHANGED
|
@@ -2,31 +2,34 @@ import pixelmatch from 'pixelmatch';
|
|
|
2
2
|
import { PNG } from 'pngjs';
|
|
3
3
|
import { ssim as computeSsim } from 'ssim.js';
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
* pixelmatch overlay (the visualisation). Both are returned so the
|
|
7
|
-
* runner can use SSIM for pass/changed decisions while the reporter
|
|
8
|
-
* still has a red-highlight diff image to show the human.
|
|
5
|
+
* Diffing is split into two phases so the common case stays cheap:
|
|
9
6
|
*
|
|
10
|
-
*
|
|
7
|
+
* 1. {@link scoreDiff}: the gate. Computes SSIM (the pass/changed
|
|
8
|
+
* decision) plus the pixel metrics reported on every outcome
|
|
9
|
+
* (`diffPixels`, `diffRatio`). It runs pixelmatch in count-only mode
|
|
10
|
+
* (no output buffer) and never encodes a diff image. It also returns the
|
|
11
|
+
* {@link DecodedPair} it read, so the changed branch can render its
|
|
12
|
+
* overlay without a second decode.
|
|
13
|
+
* 2. {@link renderDiffOverlay}: the visualisation. Takes that same decoded
|
|
14
|
+
* pair, runs pixelmatch with an output buffer, and deflate-encodes the
|
|
15
|
+
* red-highlight overlay PNG for the human-facing report.
|
|
16
|
+
*
|
|
17
|
+
* The overlay is only kept when a comparison FAILS; a passing comparison
|
|
18
|
+
* deletes it. Because passing is the common case in a healthy suite,
|
|
19
|
+
* encoding the overlay on every comparison was pure waste, so the caller
|
|
20
|
+
* runs {@link scoreDiff} unconditionally and reaches for
|
|
21
|
+
* {@link renderDiffOverlay} only on the changed branch, where the image is
|
|
22
|
+
* actually written. The decode is shared across both, so the changed branch
|
|
23
|
+
* pays for exactly one `PNG.sync.read` pair; the pass branch keeps its
|
|
24
|
+
* no-allocate, no-encode shape (the overlay is never filled on a pass).
|
|
11
25
|
*/
|
|
12
|
-
export function
|
|
13
|
-
const
|
|
14
|
-
const actualPng =
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
// SSIM and pixelmatch both assume tightly-packed RGBA (4 bytes/pixel). If a
|
|
20
|
-
// future pngjs option changed channel depth, the buffer view and the
|
|
21
|
-
// width/height would silently disagree and produce a garbage score rather
|
|
22
|
-
// than throwing. Fail loudly instead.
|
|
23
|
-
assertPackedRgba(baselinePng);
|
|
24
|
-
assertPackedRgba(actualPng);
|
|
25
|
-
const diffPng = new PNG({
|
|
26
|
-
width: baselinePng.width,
|
|
27
|
-
height: baselinePng.height,
|
|
28
|
-
});
|
|
29
|
-
const diffPixels = pixelmatch(baselinePng.data, actualPng.data, diffPng.data, baselinePng.width, baselinePng.height, { threshold: pixelThreshold });
|
|
26
|
+
export function scoreDiff(baseline, actual, pixelThreshold) {
|
|
27
|
+
const decoded = decodePair(baseline, actual);
|
|
28
|
+
const { baselinePng, actualPng } = decoded;
|
|
29
|
+
// Count-only: passing `undefined` as the output buffer makes pixelmatch
|
|
30
|
+
// tally differing pixels without allocating or filling an overlay. The
|
|
31
|
+
// metric feeds `diffPixels`/`diffRatio` reporting, not a written image.
|
|
32
|
+
const diffPixels = pixelmatch(baselinePng.data, actualPng.data, undefined, baselinePng.width, baselinePng.height, { threshold: pixelThreshold });
|
|
30
33
|
const totalPixels = baselinePng.width * baselinePng.height;
|
|
31
34
|
const ssimResult = computeSsim({
|
|
32
35
|
data: new Uint8ClampedArray(baselinePng.data.buffer, baselinePng.data.byteOffset, baselinePng.data.byteLength),
|
|
@@ -38,13 +41,60 @@ export function diffPngs(baseline, actual, pixelThreshold) {
|
|
|
38
41
|
height: actualPng.height,
|
|
39
42
|
}, { ssim: 'bezkrovny' });
|
|
40
43
|
return {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
score: {
|
|
45
|
+
diffPixels,
|
|
46
|
+
totalPixels,
|
|
47
|
+
diffRatio: diffPixels / totalPixels,
|
|
48
|
+
ssimScore: ssimResult.mssim,
|
|
49
|
+
},
|
|
50
|
+
decoded,
|
|
46
51
|
};
|
|
47
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Renders the red-highlight overlay PNG for the report from the already-decoded
|
|
55
|
+
* pair {@link scoreDiff} produced. This is the expensive half (pixelmatch
|
|
56
|
+
* fills an output buffer and `PNG.sync.write` deflate-encodes it) so it runs
|
|
57
|
+
* only on the changed/failed branch where the diff image is actually written to
|
|
58
|
+
* disk.
|
|
59
|
+
*
|
|
60
|
+
* Takes the {@link DecodedPair} rather than raw buffers so it reuses
|
|
61
|
+
* {@link scoreDiff}'s decode: the changed branch reads the image pair once, not
|
|
62
|
+
* twice. The dimensions/packing invariants were already enforced by
|
|
63
|
+
* {@link decodePair} when the pair was decoded, so no re-validation is needed
|
|
64
|
+
* here. pixelmatch's count is output-independent, so filling the overlay here
|
|
65
|
+
* cannot disturb the `diffPixels` {@link scoreDiff} already reported.
|
|
66
|
+
*/
|
|
67
|
+
export function renderDiffOverlay(decoded, pixelThreshold) {
|
|
68
|
+
const { baselinePng, actualPng } = decoded;
|
|
69
|
+
const diffPng = new PNG({
|
|
70
|
+
width: baselinePng.width,
|
|
71
|
+
height: baselinePng.height,
|
|
72
|
+
});
|
|
73
|
+
pixelmatch(baselinePng.data, actualPng.data, diffPng.data, baselinePng.width, baselinePng.height, { threshold: pixelThreshold });
|
|
74
|
+
return PNG.sync.write(diffPng);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Decodes both PNG buffers and enforces the invariants the diff phases
|
|
78
|
+
* share: dimensions must match and the pixel data must be tightly-packed
|
|
79
|
+
* RGBA. Dimension mismatch is a regression on its own. Fail loudly. Runs
|
|
80
|
+
* once per comparison inside {@link scoreDiff}; {@link renderDiffOverlay}
|
|
81
|
+
* reuses the result instead of decoding again.
|
|
82
|
+
*/
|
|
83
|
+
function decodePair(baseline, actual) {
|
|
84
|
+
const baselinePng = PNG.sync.read(baseline);
|
|
85
|
+
const actualPng = PNG.sync.read(actual);
|
|
86
|
+
if (baselinePng.width !== actualPng.width ||
|
|
87
|
+
baselinePng.height !== actualPng.height) {
|
|
88
|
+
throw new ScreenshotSizeMismatchError({ width: baselinePng.width, height: baselinePng.height }, { width: actualPng.width, height: actualPng.height });
|
|
89
|
+
}
|
|
90
|
+
// SSIM and pixelmatch both assume tightly-packed RGBA (4 bytes/pixel). If a
|
|
91
|
+
// future pngjs option changed channel depth, the buffer view and the
|
|
92
|
+
// width/height would silently disagree and produce a garbage score rather
|
|
93
|
+
// than throwing. Fail loudly instead.
|
|
94
|
+
assertPackedRgba(baselinePng);
|
|
95
|
+
assertPackedRgba(actualPng);
|
|
96
|
+
return { baselinePng, actualPng };
|
|
97
|
+
}
|
|
48
98
|
function assertPackedRgba(png) {
|
|
49
99
|
const expected = png.width * png.height * 4;
|
|
50
100
|
if (png.data.byteLength !== expected) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/screenshots/diff.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAC5B,OAAO,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/screenshots/diff.ts"],"names":[],"mappings":"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"}
|
package/dist/util.d.ts
CHANGED
|
@@ -9,8 +9,29 @@ export declare function parseHostPort(url: string): {
|
|
|
9
9
|
};
|
|
10
10
|
/**
|
|
11
11
|
* Resolves `true` if a TCP connection to `host:port` opens within `timeoutMs`,
|
|
12
|
-
* `false` on error or timeout.
|
|
13
|
-
*
|
|
12
|
+
* `false` on error or timeout. This is a cheap up/down LIVENESS check, not a
|
|
13
|
+
* readiness gate: `supervise.ts`'s `probeAllHealthchecks` polls it against dev
|
|
14
|
+
* servers that were already proven to be serving routes at startup (via
|
|
15
|
+
* {@link probeHttp}), so once a server is HTTP-readiness-verified a bare TCP
|
|
16
|
+
* accept is sufficient to confirm the process is still up. The false-ready
|
|
17
|
+
* caveat that makes a TCP accept too weak for a cold-booting dev server (see
|
|
18
|
+
* {@link probeHttp}) does not apply here. The server is past boot. Staying on
|
|
19
|
+
* TCP also keeps the liveness poll agnostic to self-signed HTTPS certs and
|
|
20
|
+
* non-2xx routes, which `fetch` (and thus `probeHttp`) would reject.
|
|
14
21
|
*/
|
|
15
22
|
export declare function probeTcp(host: string, port: number, timeoutMs: number): Promise<boolean>;
|
|
23
|
+
/**
|
|
24
|
+
* Resolves `true` if an HTTP `GET` to `url` returns any non-5xx status within
|
|
25
|
+
* `timeoutMs`, `false` on a 5xx status, connection refusal, TLS/DNS failure, or
|
|
26
|
+
* timeout. Unlike {@link probeTcp}, this proves the server is actually *serving*
|
|
27
|
+
* routes, a dev server (Vite/Next/webpack) binds its socket well before the
|
|
28
|
+
* bundle finishes compiling, so a bare TCP accept can succeed while requests
|
|
29
|
+
* still 503 or hang. Any received response (2xx/3xx/4xx) means it is up.
|
|
30
|
+
*
|
|
31
|
+
* Redirects are not followed (`redirect: 'manual'`): a 3xx already proves the
|
|
32
|
+
* server is serving, and chasing `Location` risks an external host or a slow
|
|
33
|
+
* login page. Note this does *not* accept self-signed HTTPS certs (fetch
|
|
34
|
+
* rejects them). An http health-check URL is expected.
|
|
35
|
+
*/
|
|
36
|
+
export declare function probeHttp(url: string, timeoutMs: number): Promise<boolean>;
|
|
16
37
|
//# sourceMappingURL=util.d.ts.map
|
package/dist/util.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAGA,wCAAwC;AACxC,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI/C;AAED,kEAAkE;AAClE,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO/D;AAED,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAQzE;AAED
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAGA,wCAAwC;AACxC,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI/C;AAED,kEAAkE;AAClE,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO/D;AAED,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAQzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAalB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAiBlB"}
|
package/dist/util.js
CHANGED
|
@@ -28,8 +28,15 @@ export function parseHostPort(url) {
|
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
30
|
* Resolves `true` if a TCP connection to `host:port` opens within `timeoutMs`,
|
|
31
|
-
* `false` on error or timeout.
|
|
32
|
-
*
|
|
31
|
+
* `false` on error or timeout. This is a cheap up/down LIVENESS check, not a
|
|
32
|
+
* readiness gate: `supervise.ts`'s `probeAllHealthchecks` polls it against dev
|
|
33
|
+
* servers that were already proven to be serving routes at startup (via
|
|
34
|
+
* {@link probeHttp}), so once a server is HTTP-readiness-verified a bare TCP
|
|
35
|
+
* accept is sufficient to confirm the process is still up. The false-ready
|
|
36
|
+
* caveat that makes a TCP accept too weak for a cold-booting dev server (see
|
|
37
|
+
* {@link probeHttp}) does not apply here. The server is past boot. Staying on
|
|
38
|
+
* TCP also keeps the liveness poll agnostic to self-signed HTTPS certs and
|
|
39
|
+
* non-2xx routes, which `fetch` (and thus `probeHttp`) would reject.
|
|
33
40
|
*/
|
|
34
41
|
export function probeTcp(host, port, timeoutMs) {
|
|
35
42
|
return new Promise((resolveProbe) => {
|
|
@@ -45,4 +52,37 @@ export function probeTcp(host, port, timeoutMs) {
|
|
|
45
52
|
socket.setTimeout(timeoutMs);
|
|
46
53
|
});
|
|
47
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Resolves `true` if an HTTP `GET` to `url` returns any non-5xx status within
|
|
57
|
+
* `timeoutMs`, `false` on a 5xx status, connection refusal, TLS/DNS failure, or
|
|
58
|
+
* timeout. Unlike {@link probeTcp}, this proves the server is actually *serving*
|
|
59
|
+
* routes, a dev server (Vite/Next/webpack) binds its socket well before the
|
|
60
|
+
* bundle finishes compiling, so a bare TCP accept can succeed while requests
|
|
61
|
+
* still 503 or hang. Any received response (2xx/3xx/4xx) means it is up.
|
|
62
|
+
*
|
|
63
|
+
* Redirects are not followed (`redirect: 'manual'`): a 3xx already proves the
|
|
64
|
+
* server is serving, and chasing `Location` risks an external host or a slow
|
|
65
|
+
* login page. Note this does *not* accept self-signed HTTPS certs (fetch
|
|
66
|
+
* rejects them). An http health-check URL is expected.
|
|
67
|
+
*/
|
|
68
|
+
export async function probeHttp(url, timeoutMs) {
|
|
69
|
+
const controller = new AbortController();
|
|
70
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
71
|
+
try {
|
|
72
|
+
const response = await fetch(url, {
|
|
73
|
+
method: 'GET',
|
|
74
|
+
redirect: 'manual',
|
|
75
|
+
signal: controller.signal,
|
|
76
|
+
});
|
|
77
|
+
// Drain the body so the socket doesn't linger in undici's connection pool.
|
|
78
|
+
await response.body?.cancel();
|
|
79
|
+
return response.status < 500;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
clearTimeout(timer);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
48
88
|
//# sourceMappingURL=util.js.map
|
package/dist/util.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5C,wCAAwC;AACxC,MAAM,UAAU,KAAK,CAAC,EAAU;IAC9B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,kEAAkE;AAClE,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAY;IAC3C,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI;QACtB,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;QACrB,CAAC,CAAC,MAAM,CAAC,QAAQ,KAAK,QAAQ;YAC5B,CAAC,CAAC,GAAG;YACL,CAAC,CAAC,EAAE,CAAC;IACT,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;AACzC,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5C,wCAAwC;AACxC,MAAM,UAAU,KAAK,CAAC,EAAU;IAC9B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,kEAAkE;AAClE,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAY;IAC3C,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI;QACtB,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;QACrB,CAAC,CAAC,MAAM,CAAC,QAAQ,KAAK,QAAQ;YAC5B,CAAC,CAAC,GAAG;YACL,CAAC,CAAC,EAAE,CAAC;IACT,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;AACzC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,QAAQ,CACtB,IAAY,EACZ,IAAY,EACZ,SAAiB;IAEjB,OAAO,IAAI,OAAO,CAAC,CAAC,YAAY,EAAE,EAAE;QAClC,MAAM,MAAM,GAAG,gBAAgB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,MAAM,OAAO,GAAG,CAAC,MAAe,EAAQ,EAAE;YACxC,MAAM,CAAC,kBAAkB,EAAE,CAAC;YAC5B,MAAM,CAAC,OAAO,EAAE,CAAC;YACjB,YAAY,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC,CAAC;QACF,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,GAAW,EACX,SAAiB;IAEjB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;IAC9D,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM,EAAE,KAAK;YACb,QAAQ,EAAE,QAAQ;YAClB,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QACH,2EAA2E;QAC3E,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QAC9B,OAAO,QAAQ,CAAC,MAAM,GAAG,GAAG,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tuffgal",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.4",
|
|
4
4
|
"description": "JSON-driven visual regression for web apps.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Nick Schneble",
|
|
@@ -13,10 +13,11 @@
|
|
|
13
13
|
"build": "rm -rf dist && tsc -p tsconfig.build.json && mkdir -p dist/reporter/assets && cp src/reporter/assets/report.css src/reporter/assets/report.js dist/reporter/assets/",
|
|
14
14
|
"format": "prettier --write \"**/*.{ts,tsx,json,md}\"",
|
|
15
15
|
"install:browsers": "playwright install chromium",
|
|
16
|
-
"lint": "eslint \"src/**/*.ts\" --max-warnings=0",
|
|
16
|
+
"lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\" --max-warnings=0",
|
|
17
17
|
"preview": "node --import tsx scripts/preview.ts",
|
|
18
|
-
"prepublishOnly": "npm run lint && npm run typecheck && npm run build",
|
|
18
|
+
"prepublishOnly": "npm run lint && npm run typecheck && npm test && npm run build",
|
|
19
19
|
"test": "node --import tsx --test \"src/**/*.test.ts\"",
|
|
20
|
+
"test:dom": "node --import tsx --test \"test/dom/**/*.test.ts\"",
|
|
20
21
|
"typecheck": "tsc --noEmit"
|
|
21
22
|
},
|
|
22
23
|
"bin": {
|
|
@@ -71,10 +72,5 @@
|
|
|
71
72
|
"tsx": "^4.22.4",
|
|
72
73
|
"typescript": "~5.9.3",
|
|
73
74
|
"typescript-eslint": "^8.49.0"
|
|
74
|
-
},
|
|
75
|
-
"allowScripts": {
|
|
76
|
-
"esbuild@0.28.1": true,
|
|
77
|
-
"fsevents@2.3.2": true,
|
|
78
|
-
"fsevents@2.3.3": true
|
|
79
75
|
}
|
|
80
76
|
}
|