From c5e45272e660d7e6bee5ec6d464992fb0a250dd3 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Wed, 30 Oct 2024 19:27:09 +0900 Subject: [PATCH] wip: _testIdToKeys state --- packages/snapshot/src/client.ts | 12 +++-- packages/snapshot/src/port/inlineSnapshot.ts | 2 +- packages/snapshot/src/port/state.ts | 53 +++++++++++-------- packages/snapshot/src/types/index.ts | 1 + .../vitest/src/integrations/snapshot/chai.ts | 1 + packages/vitest/src/runtime/runners/test.ts | 8 ++- 6 files changed, 43 insertions(+), 34 deletions(-) diff --git a/packages/snapshot/src/client.ts b/packages/snapshot/src/client.ts index 755c93da53cf..f4b9bb83c2e2 100644 --- a/packages/snapshot/src/client.ts +++ b/packages/snapshot/src/client.ts @@ -36,6 +36,7 @@ interface AssertOptions { received: unknown filepath: string name: string + testId: string message?: string isInline?: boolean properties?: object @@ -74,15 +75,14 @@ export class SnapshotClient { return result } - skipTest(filepath: string, name: string): void { + skipTest(filepath: string, testId: string): void { const state = this.getSnapshotState(filepath) - state.markSnapshotsAsCheckedForTest(name) + state.markSnapshotsAsCheckedForTest(testId) } - // TODO: use test.id to handle multiple tests with same name - clearTest(filepath: string, name: string): void { + clearTest(filepath: string, testId: string): void { const state = this.getSnapshotState(filepath) - state.clearTest(name) + state.clearTest(testId) } getSnapshotState(filepath: string): SnapshotState { @@ -97,6 +97,7 @@ export class SnapshotClient { const { filepath, name, + testId, message, isInline = false, properties, @@ -144,6 +145,7 @@ export class SnapshotClient { const testName = [name, ...(message ? [message] : [])].join(' > ') const { actual, expected, key, pass } = snapshotState.match({ + testId, testName, received, isInline, diff --git a/packages/snapshot/src/port/inlineSnapshot.ts b/packages/snapshot/src/port/inlineSnapshot.ts index c8474448b4ee..09f059661655 100644 --- a/packages/snapshot/src/port/inlineSnapshot.ts +++ b/packages/snapshot/src/port/inlineSnapshot.ts @@ -9,8 +9,8 @@ import { export interface InlineSnapshot { snapshot: string + testId: string file: string - testName: string line: number column: number } diff --git a/packages/snapshot/src/port/state.ts b/packages/snapshot/src/port/state.ts index 8c3c4323474a..864acfc9868e 100644 --- a/packages/snapshot/src/port/state.ts +++ b/packages/snapshot/src/port/state.ts @@ -50,11 +50,11 @@ export default class SnapshotState { private _counters: Map private _dirty: boolean private _updateSnapshot: SnapshotUpdateState - // TODO: key by test id. how to match with `initialData`? private _snapshotData: SnapshotData private _initialData: SnapshotData private _inlineSnapshots: Array - private _inlineSnapshotStacks: Array + private _inlineSnapshotStacks: Array + private _testIdToKeys = new Map() private _rawSnapshots: Array private _uncheckedKeys: Set private _snapshotFormat: PrettyFormatOptions @@ -111,30 +111,34 @@ export default class SnapshotState { return this._environment } - markSnapshotsAsCheckedForTest(testName: string): void { - this._uncheckedKeys.forEach((uncheckedKey) => { - if (keyToTestName(uncheckedKey) === testName) { - this._uncheckedKeys.delete(uncheckedKey) - } - }) + markSnapshotsAsCheckedForTest(testId: string): void { + for (const key of this._testIdToKeys.get(testId) ?? []) { + this._uncheckedKeys.delete(key) + } } - clearTest(testName: string): void { - // TODO: key by test.id (handle multiple tests with same title) - // TODO: reset this.added, matched, etc.. + clearTest(testId: string): void { + // TODO: reset stats: added, matched, etc.. + + this._inlineSnapshots = this._inlineSnapshots.filter(s => s.testId !== testId) + this._inlineSnapshotStacks = this._inlineSnapshotStacks.filter(s => s.testId !== testId) - this._inlineSnapshots = this._inlineSnapshots.filter(s => s.testName !== testName) - this._inlineSnapshotStacks = this._inlineSnapshotStacks.filter(s => s.testName !== testName) - if (this._counters.has(testName)) { - const counter = this._counters.get(testName)! - for (let i = 1; i <= counter; i++) { - const key = testNameToKey(testName, counter) + for (const key of this._testIdToKeys.get(testId) ?? []) { + const name = keyToTestName(key) + const counter = this._counters.get(name) + if (typeof counter !== 'undefined') { if (key in this._snapshotData || key in this._initialData) { this._snapshotData[key] = this._initialData[key] } + if (counter > 0) { + this._counters.set(name, counter - 1) + } + else { + this._counters.delete(name) + } } - this._counters.delete(testName) } + this._testIdToKeys.delete(testId) } protected _inferInlineSnapshotStack(stacks: ParsedStack[]): ParsedStack | null { @@ -157,13 +161,13 @@ export default class SnapshotState { private _addSnapshot( key: string, receivedSerialized: string, - options: { rawSnapshot?: RawSnapshotInfo; stack?: ParsedStack; testName: string }, + options: { rawSnapshot?: RawSnapshotInfo; stack?: ParsedStack; testId: string }, ): void { this._dirty = true if (options.stack) { this._inlineSnapshots.push({ snapshot: receivedSerialized, - testName: options.testName, + testId: options.testId, ...options.stack, }) } @@ -237,6 +241,7 @@ export default class SnapshotState { } match({ + testId, testName, received, key, @@ -251,6 +256,8 @@ export default class SnapshotState { if (!key) { key = testNameToKey(testName, count) } + this._testIdToKeys.set(testId, (this._testIdToKeys.get(key) ?? [])) + this._testIdToKeys.get(testId)?.push(key) // Do not mark the snapshot as "checked" if the snapshot is inline and // there's an external snapshot. This way the external snapshot can be @@ -329,7 +336,7 @@ export default class SnapshotState { this._inlineSnapshots = this._inlineSnapshots.filter(s => !(s.file === stack!.file && s.line === stack!.line && s.column === stack!.column)) throw new Error('toMatchInlineSnapshot cannot be called multiple times at the same location.') } - this._inlineSnapshotStacks.push({ ...stack, testName }) + this._inlineSnapshotStacks.push({ ...stack, testId }) } // These are the conditions on when to write snapshots: @@ -355,7 +362,7 @@ export default class SnapshotState { this._addSnapshot(key, receivedSerialized, { stack, - testName, + testId, rawSnapshot, }) } @@ -366,7 +373,7 @@ export default class SnapshotState { else { this._addSnapshot(key, receivedSerialized, { stack, - testName, + testId, rawSnapshot, }) this.added++ diff --git a/packages/snapshot/src/types/index.ts b/packages/snapshot/src/types/index.ts index d1bf8af4fac8..a106f9a24741 100644 --- a/packages/snapshot/src/types/index.ts +++ b/packages/snapshot/src/types/index.ts @@ -24,6 +24,7 @@ export interface SnapshotStateOptions { } export interface SnapshotMatchOptions { + testId: string testName: string received: unknown key?: string diff --git a/packages/vitest/src/integrations/snapshot/chai.ts b/packages/vitest/src/integrations/snapshot/chai.ts index b7e89077bb69..9cd96fc2ba1b 100644 --- a/packages/vitest/src/integrations/snapshot/chai.ts +++ b/packages/vitest/src/integrations/snapshot/chai.ts @@ -48,6 +48,7 @@ function getTestNames(test: Test) { return { filepath: test.file.filepath, name: getNames(test).slice(1).join(' > '), + testId: test.id, } } diff --git a/packages/vitest/src/runtime/runners/test.ts b/packages/vitest/src/runtime/runners/test.ts index d9a96d6cea53..e55df4b6be75 100644 --- a/packages/vitest/src/runtime/runners/test.ts +++ b/packages/vitest/src/runtime/runners/test.ts @@ -14,7 +14,7 @@ import type { import type { SerializedConfig } from '../config' import type { VitestExecutor } from '../execute' import { getState, GLOBAL_EXPECT, setState } from '@vitest/expect' -import { getNames, getTestName, getTests } from '@vitest/runner/utils' +import { getTestName, getTests } from '@vitest/runner/utils' import { createExpect } from '../../integrations/chai/index' import { getSnapshotClient } from '../../integrations/snapshot/chai' import { vi } from '../../integrations/vi' @@ -58,9 +58,7 @@ export class VitestTestRunner implements VitestRunner { // mark snapshots in skipped tests as not obsolete for (const test of getTests(suite)) { if (test.mode === 'skip') { - const name = getNames(test).slice(1).join(' > ') - // TODO: skip by test.id - this.snapshotClient.skipTest(suite.file.filepath, name) + this.snapshotClient.skipTest(suite.file.filepath, test.id) } } @@ -114,7 +112,7 @@ export class VitestTestRunner implements VitestRunner { } onBeforeTryTask(test: Task) { - this.snapshotClient.clearTest(test.file.filepath, test.name) + this.snapshotClient.clearTest(test.file.filepath, test.id) setState( { assertionCalls: 0,