vitest-screenshot 1.0.1 → 3.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 +32 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/update-policy.d.ts +3 -0
- package/dist/update-policy.d.ts.map +1 -0
- package/dist/update-policy.js +11 -0
- package/dist/update-policy.js.map +1 -0
- package/package.json +9 -10
- package/src/index.ts +15 -5
- package/src/update-policy.ts +23 -0
- package/CHANGELOG.md +0 -7
package/README.md
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
# vitest-screenshot
|
|
2
2
|
|
|
3
|
+
[![npm version][npm-badge]][npm-url]
|
|
4
|
+
[![npm downloads][downloads-badge]][npm-url]
|
|
5
|
+
[![Tests][tests-badge]][tests-url]
|
|
6
|
+
[![Discord][discord-badge]][discord-url]
|
|
7
|
+
|
|
3
8
|
`await expect(image).toMatchScreenshot(reference)`: compare an image against a baseline committed next to your
|
|
4
|
-
tests, with the same options as Vitest browser mode's `toMatchScreenshot`.
|
|
9
|
+
tests, with the same options as Vitest browser mode's `toMatchScreenshot`. Pair it with a native GPU
|
|
10
|
+
environment and tests run up to 2.4x faster than in a browser — see the
|
|
11
|
+
[blog post](https://ben3d.ca/blog/native-gpu-testing-for-vitest-and-jest) for details.
|
|
12
|
+
Backend-agnostic: feed it a canvas from
|
|
5
13
|
[`vitest-environment-webgl-node`](../vitest-environment-webgl-node) or
|
|
6
14
|
[`vitest-environment-webgpu-node`](../vitest-environment-webgpu-node), an `ImageData`, a WebGPU texture
|
|
7
15
|
readback, or pixels from a real browser.
|
|
@@ -12,6 +20,8 @@ readback, or pixels from a real browser.
|
|
|
12
20
|
pnpm add -D vitest vitest-screenshot
|
|
13
21
|
```
|
|
14
22
|
|
|
23
|
+
Requires Vitest 4 or 5. Vitest 3 is not supported.
|
|
24
|
+
|
|
15
25
|
## Usage
|
|
16
26
|
|
|
17
27
|
```ts
|
|
@@ -45,8 +55,11 @@ relative to `baselineDir` unless absolute.
|
|
|
45
55
|
- Any format sharp reads and writes works: png, jpg, gif, webp, avif, tiff. **We recommend png**: it is lossless,
|
|
46
56
|
so a baseline written on the first run matches exactly. jpg and webp are re-encoded lossily on write and gif is
|
|
47
57
|
limited to 256 colours, so loosen the comparator if you use them.
|
|
48
|
-
-
|
|
49
|
-
|
|
58
|
+
- Screenshot baselines follow Vitest's snapshot update mode: missing baselines are created locally, fail in CI,
|
|
59
|
+
and `vitest -u` creates or overwrites them.
|
|
60
|
+
- `UPDATE_SCREENSHOTS=1 vitest` remains an alias for updating all screenshot baselines.
|
|
61
|
+
- Per assertion, `update: true` creates or overwrites a baseline and `update: false` prevents both overwriting and
|
|
62
|
+
creating one. This explicit option takes precedence over Vitest's mode and `UPDATE_SCREENSHOTS`.
|
|
50
63
|
- `.not.toMatchScreenshot()` is unsupported and fails without reading pixels or writing baseline files.
|
|
51
64
|
- On failure `<name>.actual.png` and `<name>.diff.png` are written to `baselineDir` (named after the test when the
|
|
52
65
|
reference is in memory). Gitignore them.
|
|
@@ -147,3 +160,19 @@ await expect(image).toMatchScreenshot('baseline.png', {
|
|
|
147
160
|
```
|
|
148
161
|
|
|
149
162
|
See [`demo/test/screenshots`](../../demo/test/screenshots) for every source, format and comparator combination.
|
|
163
|
+
|
|
164
|
+
## Author
|
|
165
|
+
|
|
166
|
+
Created by [Ben Houston](https://ben3d.ca) and sponsored by [Land of Assets](https://landofassets.com).
|
|
167
|
+
|
|
168
|
+
## License
|
|
169
|
+
|
|
170
|
+
MIT
|
|
171
|
+
|
|
172
|
+
[npm-badge]: https://img.shields.io/npm/v/vitest-screenshot.svg
|
|
173
|
+
[npm-url]: https://www.npmjs.com/package/vitest-screenshot
|
|
174
|
+
[downloads-badge]: https://img.shields.io/npm/dm/vitest-screenshot.svg
|
|
175
|
+
[tests-badge]: https://github.com/bhouston/vitest-gpu/actions/workflows/ci.yml/badge.svg
|
|
176
|
+
[tests-url]: https://github.com/bhouston/vitest-gpu/actions/workflows/ci.yml
|
|
177
|
+
[discord-badge]: https://img.shields.io/badge/Discord-Join%20Chat-5865F2?logo=discord&logoColor=white
|
|
178
|
+
[discord-url]: https://discord.gg/fwupDN493R
|
package/dist/index.d.ts
CHANGED
|
@@ -57,7 +57,7 @@ export type ComparatorSelection = {
|
|
|
57
57
|
export type ScreenshotOptions = ComparatorSelection & {
|
|
58
58
|
/** Directory relative reference paths and diff images live in. Default: `__screenshots__` beside the test file. */
|
|
59
59
|
baselineDir?: string;
|
|
60
|
-
/**
|
|
60
|
+
/** Override Vitest's snapshot update mode. `true` creates/overwrites; `false` prevents both. */
|
|
61
61
|
update?: boolean;
|
|
62
62
|
};
|
|
63
63
|
/** Defaults for every assertion plus custom comparators, like `test.browser.expect.toMatchScreenshot` in Vitest config. */
|
|
@@ -67,7 +67,7 @@ export type ScreenshotConfig = ComparatorSelection & {
|
|
|
67
67
|
};
|
|
68
68
|
};
|
|
69
69
|
declare module 'vitest' {
|
|
70
|
-
interface Assertion {
|
|
70
|
+
interface Assertion<R extends void | Promise<void> = void, T = unknown> {
|
|
71
71
|
toMatchScreenshot(reference: Reference, options?: ScreenshotOptions): Promise<void>;
|
|
72
72
|
}
|
|
73
73
|
}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,UAAU,MAAM,YAAY,CAAC;AAGpC,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import pixelmatch from 'pixelmatch';
|
|
|
4
4
|
import sharp from 'sharp';
|
|
5
5
|
import { expect } from 'vitest';
|
|
6
6
|
import { metricsComparator } from './metrics.js';
|
|
7
|
+
import { resolveScreenshotUpdateState } from './update-policy.js';
|
|
7
8
|
const result = (pass, message) => ({ pass, message: () => message });
|
|
8
9
|
const raw = ({ width, height, data }) => sharp(data, { raw: { width, height, channels: 4 } });
|
|
9
10
|
/** Decodes any format sharp reads (png, jpg, gif, webp, ...) into RGBA8. */
|
|
@@ -64,13 +65,14 @@ export function extendMatchers(config = {}) {
|
|
|
64
65
|
if (!extname(reference))
|
|
65
66
|
throw new Error(`reference "${reference}" needs an image extension, e.g. "${reference}.png"`);
|
|
66
67
|
file = isAbsolute(reference) ? reference : join(dir, reference);
|
|
67
|
-
const
|
|
68
|
-
|
|
68
|
+
const exists = existsSync(file);
|
|
69
|
+
const update = resolveScreenshotUpdateState(this.snapshotState, options.update, Boolean(process.env.UPDATE_SCREENSHOTS), Boolean(process.env.CI));
|
|
70
|
+
if (update === 'all' || (update === 'new' && !exists)) {
|
|
69
71
|
await writeImage(file, actual);
|
|
70
72
|
return result(true, `wrote baseline ${file}`);
|
|
71
73
|
}
|
|
72
|
-
if (!
|
|
73
|
-
return result(false, `missing baseline ${file}; run with UPDATE_SCREENSHOTS=1`);
|
|
74
|
+
if (!exists)
|
|
75
|
+
return result(false, `missing baseline ${file}; run with UPDATE_SCREENSHOTS=1 or vitest -u`);
|
|
74
76
|
baseline = await readImage(file);
|
|
75
77
|
}
|
|
76
78
|
else {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACzE,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,KAA0B,MAAM,OAAO,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,iBAAiB,EAAuB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export type ScreenshotUpdateState = 'all' | 'new' | 'none';
|
|
2
|
+
export declare const resolveScreenshotUpdateState: (snapshotState: unknown, explicitUpdate: boolean | undefined, environmentUpdate: boolean, isCi: boolean) => ScreenshotUpdateState;
|
|
3
|
+
//# sourceMappingURL=update-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-policy.d.ts","sourceRoot":"","sources":["../src/update-policy.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,qBAAqB,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;AAW3D,eAAO,MAAM,4BAA4B,kBACxB,OAAO,kBACN,OAAO,GAAG,SAAS,qBAChB,OAAO,QACpB,OAAO,KACZ,qBAMF,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const isUpdateState = (value) => value === 'all' || value === 'new' || value === 'none';
|
|
2
|
+
export const resolveScreenshotUpdateState = (snapshotState, explicitUpdate, environmentUpdate, isCi) => {
|
|
3
|
+
if (explicitUpdate !== undefined)
|
|
4
|
+
return explicitUpdate ? 'all' : 'none';
|
|
5
|
+
if (environmentUpdate)
|
|
6
|
+
return 'all';
|
|
7
|
+
const compatible = snapshotState;
|
|
8
|
+
const state = compatible?.snapshotUpdateState ?? compatible?._updateSnapshot;
|
|
9
|
+
return isUpdateState(state) ? state : isCi ? 'none' : 'new';
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=update-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-policy.js","sourceRoot":"","sources":["../src/update-policy.ts"],"names":[],"mappings":"AAQA,MAAM,aAAa,GAAG,CAAC,KAAc,EAAkC,EAAE,CACvE,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,MAAM,CAAC;AAEzD,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAC1C,aAAsB,EACtB,cAAmC,EACnC,iBAA0B,EAC1B,IAAa,EACU,EAAE;IACzB,IAAI,cAAc,KAAK,SAAS;QAAE,OAAO,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IACzE,IAAI,iBAAiB;QAAE,OAAO,KAAK,CAAC;IACpC,MAAM,UAAU,GAAG,aAAoD,CAAC;IACxE,MAAM,KAAK,GAAG,UAAU,EAAE,mBAAmB,IAAI,UAAU,EAAE,eAAe,CAAC;IAC7E,OAAO,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;AAC9D,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vitest-screenshot",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "toMatchScreenshot(): pixel-diff a canvas, Image or ImageData against a committed png/jpg/gif/webp baseline in Vitest",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"matcher",
|
|
@@ -28,8 +28,7 @@
|
|
|
28
28
|
"dist/**/*.d.ts",
|
|
29
29
|
"dist/**/*.d.ts.map",
|
|
30
30
|
"src/**/*.ts",
|
|
31
|
-
"!src/**/*.test.ts"
|
|
32
|
-
"CHANGELOG.md"
|
|
31
|
+
"!src/**/*.test.ts"
|
|
33
32
|
],
|
|
34
33
|
"type": "module",
|
|
35
34
|
"main": "./dist/index.js",
|
|
@@ -43,18 +42,18 @@
|
|
|
43
42
|
"publishConfig": {
|
|
44
43
|
"access": "public"
|
|
45
44
|
},
|
|
46
|
-
"scripts": {
|
|
47
|
-
"build": "tsc",
|
|
48
|
-
"tsc": "tsc && tsc -p tsconfig.type-tests.json"
|
|
49
|
-
},
|
|
50
45
|
"dependencies": {
|
|
51
46
|
"pixelmatch": "^7.1.0",
|
|
52
47
|
"sharp": "^0.35.4"
|
|
53
48
|
},
|
|
54
49
|
"peerDependencies": {
|
|
55
|
-
"vitest": ">=
|
|
50
|
+
"vitest": ">=4 <6"
|
|
56
51
|
},
|
|
57
52
|
"engines": {
|
|
58
|
-
"node": ">=
|
|
53
|
+
"node": ">=22"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build": "tsc",
|
|
57
|
+
"tsc": "tsc && tsc -p tsconfig.type-tests.json"
|
|
59
58
|
}
|
|
60
|
-
}
|
|
59
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ import pixelmatch from 'pixelmatch';
|
|
|
4
4
|
import sharp, { type FormatEnum } from 'sharp';
|
|
5
5
|
import { expect } from 'vitest';
|
|
6
6
|
import { metricsComparator, type MetricsOptions } from './metrics.js';
|
|
7
|
+
import { resolveScreenshotUpdateState } from './update-policy.js';
|
|
7
8
|
|
|
8
9
|
export type { Metric, MetricsOptions } from './metrics.js';
|
|
9
10
|
|
|
@@ -63,7 +64,7 @@ export type ComparatorSelection =
|
|
|
63
64
|
export type ScreenshotOptions = ComparatorSelection & {
|
|
64
65
|
/** Directory relative reference paths and diff images live in. Default: `__screenshots__` beside the test file. */
|
|
65
66
|
baselineDir?: string;
|
|
66
|
-
/**
|
|
67
|
+
/** Override Vitest's snapshot update mode. `true` creates/overwrites; `false` prevents both. */
|
|
67
68
|
update?: boolean;
|
|
68
69
|
};
|
|
69
70
|
|
|
@@ -73,7 +74,10 @@ export type ScreenshotConfig = ComparatorSelection & {
|
|
|
73
74
|
};
|
|
74
75
|
|
|
75
76
|
declare module 'vitest' {
|
|
76
|
-
|
|
77
|
+
// Vitest 5's `Assertion` gained a second type parameter (`R`); this augmentation must declare
|
|
78
|
+
// the same arity TypeScript sees for the installed Vitest major, or the two `interface`
|
|
79
|
+
// declarations fail to merge. Vitest 4/3 ignore the extra defaulted parameter.
|
|
80
|
+
interface Assertion<R extends void | Promise<void> = void, T = unknown> {
|
|
77
81
|
toMatchScreenshot(reference: Reference, options?: ScreenshotOptions): Promise<void>;
|
|
78
82
|
}
|
|
79
83
|
}
|
|
@@ -143,12 +147,18 @@ export function extendMatchers(config: ScreenshotConfig = {}): void {
|
|
|
143
147
|
if (!extname(reference))
|
|
144
148
|
throw new Error(`reference "${reference}" needs an image extension, e.g. "${reference}.png"`);
|
|
145
149
|
file = isAbsolute(reference) ? reference : join(dir, reference);
|
|
146
|
-
const
|
|
147
|
-
|
|
150
|
+
const exists = existsSync(file);
|
|
151
|
+
const update = resolveScreenshotUpdateState(
|
|
152
|
+
this.snapshotState,
|
|
153
|
+
options.update,
|
|
154
|
+
Boolean(process.env.UPDATE_SCREENSHOTS),
|
|
155
|
+
Boolean(process.env.CI),
|
|
156
|
+
);
|
|
157
|
+
if (update === 'all' || (update === 'new' && !exists)) {
|
|
148
158
|
await writeImage(file, actual);
|
|
149
159
|
return result(true, `wrote baseline ${file}`);
|
|
150
160
|
}
|
|
151
|
-
if (!
|
|
161
|
+
if (!exists) return result(false, `missing baseline ${file}; run with UPDATE_SCREENSHOTS=1 or vitest -u`);
|
|
152
162
|
baseline = await readImage(file);
|
|
153
163
|
} else {
|
|
154
164
|
baseline = await toRgba(reference);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type ScreenshotUpdateState = 'all' | 'new' | 'none';
|
|
2
|
+
|
|
3
|
+
type CompatibleSnapshotState = {
|
|
4
|
+
readonly snapshotUpdateState?: unknown;
|
|
5
|
+
/** Vitest 3 compatibility; remove when the peer range no longer includes Vitest 3. */
|
|
6
|
+
readonly _updateSnapshot?: unknown;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const isUpdateState = (value: unknown): value is ScreenshotUpdateState =>
|
|
10
|
+
value === 'all' || value === 'new' || value === 'none';
|
|
11
|
+
|
|
12
|
+
export const resolveScreenshotUpdateState = (
|
|
13
|
+
snapshotState: unknown,
|
|
14
|
+
explicitUpdate: boolean | undefined,
|
|
15
|
+
environmentUpdate: boolean,
|
|
16
|
+
isCi: boolean,
|
|
17
|
+
): ScreenshotUpdateState => {
|
|
18
|
+
if (explicitUpdate !== undefined) return explicitUpdate ? 'all' : 'none';
|
|
19
|
+
if (environmentUpdate) return 'all';
|
|
20
|
+
const compatible = snapshotState as CompatibleSnapshotState | undefined;
|
|
21
|
+
const state = compatible?.snapshotUpdateState ?? compatible?._updateSnapshot;
|
|
22
|
+
return isUpdateState(state) ? state : isCi ? 'none' : 'new';
|
|
23
|
+
};
|
package/CHANGELOG.md
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
## [vitest-screenshot-v1.0.1](https://github.com/bhouston/vitest-gpu/compare/vitest-screenshot-v1.0.0...vitest-screenshot-v1.0.1) (2026-09-18)
|
|
2
|
-
|
|
3
|
-
### Bug Fixes
|
|
4
|
-
|
|
5
|
-
* **screenshot:** enforce comparator option types ([1af7d9c](https://github.com/bhouston/vitest-gpu/commit/1af7d9cefe5531e0d5ed160455aa02418de39491)), closes [#28](https://github.com/bhouston/vitest-gpu/issues/28)
|
|
6
|
-
* **screenshot:** reject negated assertions ([0753f31](https://github.com/bhouston/vitest-gpu/commit/0753f317972e73d9e50d7e594d1ed22db6359c4a)), closes [#22](https://github.com/bhouston/vitest-gpu/issues/22)
|
|
7
|
-
* ship sources referenced by package maps ([8db482e](https://github.com/bhouston/vitest-gpu/commit/8db482ed56714f375b53d9a30df3f080a86fb81d)), closes [#23](https://github.com/bhouston/vitest-gpu/issues/23)
|