diff --git a/packages/snapshot/src/port/state.ts b/packages/snapshot/src/port/state.ts index 61d1ed81a47f..be480185ad11 100644 --- a/packages/snapshot/src/port/state.ts +++ b/packages/snapshot/src/port/state.ts @@ -62,12 +62,23 @@ export default class SnapshotState { private _snapshotFormat: PrettyFormatOptions private _environment: SnapshotEnvironment private _fileExists: boolean - private added = new CounterMap() - private matched = new CounterMap() - private unmatched = new CounterMap() - private updated = new CounterMap() expand: boolean + // getter/setter for jest-image-snapshot compat + // https://github.com/vitest-dev/vitest/issues/7322 + private _added = new CounterMap() + private _matched = new CounterMap() + private _unmatched = new CounterMap() + private _updated = new CounterMap() + get added(): CounterMap { return this._added } + set added(value: number) { this._added._total = value } + get matched(): CounterMap { return this._matched } + set matched(value: number) { this._matched._total = value } + get unmatched(): CounterMap { return this._unmatched } + set unmatched(value: number) { this._unmatched._total = value } + get updated(): CounterMap { return this._updated } + set updated(value: number) { this._updated._total = value } + private constructor( public testFilePath: string, public snapshotPath: string, diff --git a/packages/snapshot/src/port/utils.ts b/packages/snapshot/src/port/utils.ts index 64902bdef1da..5d4696b8d5a0 100644 --- a/packages/snapshot/src/port/utils.ts +++ b/packages/snapshot/src/port/utils.ts @@ -287,11 +287,28 @@ export class CounterMap extends DefaultMap { super(() => 0) } + // compat for jest-image-snapshot https://github.com/vitest-dev/vitest/issues/7322 + // `valueOf` and `Snapshot.added` setter allows + // snapshotState.added = snapshotState.added + 1 + // to function as + // snapshotState.added.total_ = snapshotState.added.total() + 1 + _total: number | undefined + + valueOf(): number { + return this._total = this.total() + } + increment(key: K): void { + if (typeof this._total !== 'undefined') { + this._total++ + } this.set(key, this.get(key) + 1) } total(): number { + if (typeof this._total !== 'undefined') { + return this._total + } let total = 0 for (const x of this.values()) { total += x diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7f08982d4b09..88c0a484b521 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1351,6 +1351,10 @@ importers: vitest: specifier: workspace:* version: link:../../packages/vitest + devDependencies: + jest-image-snapshot: + specifier: ^6.4.0 + version: 6.4.0 test/test-utils: devDependencies: @@ -6183,6 +6187,10 @@ packages: resolution: {integrity: sha512-mDHFgApoQd+azgMdwylJrv2DX47ywGq1i5VFJE7fZ0dttNq3iQMfsU4IvEgBHojA3KqEudyu7Vq+oN8kNaNkWw==} engines: {node: '>=16'} + get-stdin@5.0.1: + resolution: {integrity: sha512-jZV7n6jGE3Gt7fgSTJoz91Ak5MuTLwMwkoYdjxuJ/AmjIsE1UC03y/IWkZCQGEvVNS9qoRNwy5BCqxImv0FVeA==} + engines: {node: '>=0.12.0'} + get-stream@5.2.0: resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} engines: {node: '>=8'} @@ -6277,6 +6285,9 @@ packages: globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + glur@1.1.2: + resolution: {integrity: sha512-l+8esYHTKOx2G/Aao4lEQ0bnHWg4fWtJbVoZZT9Knxi01pB8C80BR85nONLFwkkQoFRCmXY+BUcGZN3yZ2QsRA==} + google-auth-library@9.2.0: resolution: {integrity: sha512-1oV3p0JhNEhVbj26eF3FAJcv9MXXQt4S0wcvKZaDbl4oHq5V3UJoSbsGZGQNcjoCdhW4kDSwOs11wLlHog3fgQ==} engines: {node: '>=14'} @@ -6792,6 +6803,15 @@ packages: resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-image-snapshot@6.4.0: + resolution: {integrity: sha512-IWGtSOnelwaVPd09STbJuLmnAwlBC/roJtTLGLb8M3TA0vfku3MRNEXmljTa1EMXqdRbA0oIWiqHFB1ttTGazQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + jest: '>=20 <=29' + peerDependenciesMeta: + jest: + optional: true + jest-matcher-utils@29.7.0: resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -7801,6 +7821,10 @@ packages: resolution: {integrity: sha512-uhIfMj5TVp+WynVASaVEJFTncTUe4dHBq6CWplu/vBgvGHhvBvQfxz+vcOrnnBQdORH3izaGEurLfNlq3YxdFQ==} hasBin: true + pixelmatch@5.3.0: + resolution: {integrity: sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q==} + hasBin: true + pkg-types@1.2.1: resolution: {integrity: sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==} @@ -7831,6 +7855,14 @@ packages: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} + pngjs@3.4.0: + resolution: {integrity: sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==} + engines: {node: '>=4.0.0'} + + pngjs@6.0.0: + resolution: {integrity: sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==} + engines: {node: '>=12.13.0'} + possible-typed-array-names@1.0.0: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} @@ -8544,6 +8576,9 @@ packages: peerDependencies: vue: ^3.2.0 + ssim.js@3.5.0: + resolution: {integrity: sha512-Aj6Jl2z6oDmgYFFbQqK7fght19bXdOxY7Tj03nF+03M9gCBAjeIiO8/PlEGMfKDwYpw4q6iBqVq2YuREorGg/g==} + stable-hash@0.0.4: resolution: {integrity: sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==} @@ -15322,6 +15357,8 @@ snapshots: get-port@7.0.0: {} + get-stdin@5.0.1: {} + get-stream@5.2.0: dependencies: pump: 3.0.0 @@ -15443,6 +15480,8 @@ snapshots: globrex@0.1.2: {} + glur@1.1.2: {} + google-auth-library@9.2.0: dependencies: base64-js: 1.5.1 @@ -15996,6 +16035,17 @@ snapshots: jest-get-type@29.6.3: optional: true + jest-image-snapshot@6.4.0: + dependencies: + chalk: 4.1.2 + get-stdin: 5.0.1 + glur: 1.1.2 + lodash: 4.17.21 + pixelmatch: 5.3.0 + pngjs: 3.4.0 + rimraf: 2.7.1 + ssim.js: 3.5.0 + jest-matcher-utils@29.7.0: dependencies: chalk: 4.1.2 @@ -17194,6 +17244,10 @@ snapshots: sonic-boom: 3.8.1 thread-stream: 2.1.0 + pixelmatch@5.3.0: + dependencies: + pngjs: 6.0.0 + pkg-types@1.2.1: dependencies: confbox: 0.1.8 @@ -17224,6 +17278,10 @@ snapshots: pluralize@8.0.0: {} + pngjs@3.4.0: {} + + pngjs@6.0.0: {} + possible-typed-array-names@1.0.0: {} postcss-selector-parser@6.0.16: @@ -18084,6 +18142,8 @@ snapshots: dependencies: vue: 3.5.12(typescript@5.7.3) + ssim.js@3.5.0: {} + stable-hash@0.0.4: {} stack-utils@2.0.6: diff --git a/test/snapshots/package.json b/test/snapshots/package.json index 0e54f05c0690..b9b11b131b71 100644 --- a/test/snapshots/package.json +++ b/test/snapshots/package.json @@ -14,5 +14,8 @@ }, "dependencies": { "vitest": "workspace:*" + }, + "devDependencies": { + "jest-image-snapshot": "^6.4.0" } } diff --git a/test/snapshots/test/fixtures/jest-image-snapshot/__image_snapshots__/basic-test-ts-to-match-image-snapshot-1-snap.png b/test/snapshots/test/fixtures/jest-image-snapshot/__image_snapshots__/basic-test-ts-to-match-image-snapshot-1-snap.png new file mode 100644 index 000000000000..dd9a8e1466dd Binary files /dev/null and b/test/snapshots/test/fixtures/jest-image-snapshot/__image_snapshots__/basic-test-ts-to-match-image-snapshot-1-snap.png differ diff --git a/test/snapshots/test/fixtures/jest-image-snapshot/basic.test.ts b/test/snapshots/test/fixtures/jest-image-snapshot/basic.test.ts new file mode 100644 index 000000000000..671a0ac64091 --- /dev/null +++ b/test/snapshots/test/fixtures/jest-image-snapshot/basic.test.ts @@ -0,0 +1,19 @@ +import { expect, it } from "vitest"; +import fs from "fs"; + +// @ts-expect-error no type +import { toMatchImageSnapshot } from "jest-image-snapshot"; +expect.extend({ toMatchImageSnapshot }); + +declare module 'vitest' { + interface Assertion { + toMatchImageSnapshot(): void + } +} + +// pnpm -C test/snapshots test:fixtures --root test/fixtures/jest-image-snapshot + +it("toMatchImageSnapshot", async () => { + const file = new URL("./test.png", import.meta.url) + expect(fs.readFileSync(file)).toMatchImageSnapshot(); +}); diff --git a/test/snapshots/test/fixtures/jest-image-snapshot/test.png b/test/snapshots/test/fixtures/jest-image-snapshot/test.png new file mode 100644 index 000000000000..dd9a8e1466dd Binary files /dev/null and b/test/snapshots/test/fixtures/jest-image-snapshot/test.png differ diff --git a/test/snapshots/test/jest-image-snapshot.test.ts b/test/snapshots/test/jest-image-snapshot.test.ts new file mode 100644 index 000000000000..7c7f1689e5fe --- /dev/null +++ b/test/snapshots/test/jest-image-snapshot.test.ts @@ -0,0 +1,62 @@ +import fs from 'node:fs' +import { join } from 'node:path' +import { expect, test } from 'vitest' +import { runVitest } from '../../test-utils' + +test('jest-image-sapshot', async () => { + // cleanup snapshot + const root = join(import.meta.dirname, 'fixtures/jest-image-snapshot') + fs.rmSync(join(root, '__image_snapshots__'), { recursive: true, force: true }) + + // write snapshot + let vitest = await runVitest({ + root, + update: true, + }) + expect(vitest.stderr).toBe('') + expect(vitest.ctx?.snapshot.summary).toMatchInlineSnapshot(` + Object { + "added": 1, + "didUpdate": true, + "failure": false, + "filesAdded": 1, + "filesRemoved": 0, + "filesRemovedList": Array [], + "filesUnmatched": 0, + "filesUpdated": 0, + "matched": 0, + "total": 1, + "unchecked": 0, + "uncheckedKeysByFile": Array [], + "unmatched": 0, + "updated": 0, + } + `) + expect(fs.existsSync(join(root, '__image_snapshots__/basic-test-ts-to-match-image-snapshot-1-snap.png'))).toBe(true) + + // match existing snapshot + vitest = await runVitest({ + root, + update: false, + }) + expect(vitest.stderr).toBe('') + expect(vitest.ctx?.snapshot.summary).toMatchInlineSnapshot(` + Object { + "added": 0, + "didUpdate": false, + "failure": false, + "filesAdded": 0, + "filesRemoved": 0, + "filesRemovedList": Array [], + "filesUnmatched": 0, + "filesUpdated": 0, + "matched": 1, + "total": 1, + "unchecked": 0, + "uncheckedKeysByFile": Array [], + "unmatched": 0, + "updated": 0, + } + `) + expect(fs.existsSync(join(root, '__image_snapshots__/basic-test-ts-to-match-image-snapshot-1-snap.png'))).toBe(true) +})