Skip to content

Commit

Permalink
fix(snapshot): allow inline snapshot calls on same location with same…
Browse files Browse the repository at this point in the history
… snapshot (#7464)

Co-authored-by: Hiroshi Ogawa <[email protected]>
  • Loading branch information
jycouet and hi-ogawa authored Feb 27, 2025
1 parent 4b5ed90 commit d5cb821
Show file tree
Hide file tree
Showing 9 changed files with 453 additions and 50 deletions.
33 changes: 26 additions & 7 deletions packages/snapshot/src/port/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,20 @@ interface SaveStatus {
saved: boolean
}

type ParsedStackPosition = Pick<ParsedStack, 'file' | 'line' | 'column'>

function isSameStackPosition(x: ParsedStackPosition, y: ParsedStackPosition) {
return x.file === y.file && x.column === y.column && x.line === y.line
}

export default class SnapshotState {
private _counters = new CounterMap<string>()
private _dirty: boolean
private _updateSnapshot: SnapshotUpdateState
private _snapshotData: SnapshotData
private _initialData: SnapshotData
private _inlineSnapshots: Array<InlineSnapshot>
private _inlineSnapshotStacks: Array<ParsedStack & { testId: string }>
private _inlineSnapshotStacks: Array<ParsedStack & { testId: string; snapshot: string }>
private _testIdToKeys = new DefaultMap<string, string[]>(() => [])
private _rawSnapshots: Array<RawSnapshot>
private _uncheckedKeys: Set<string>
Expand Down Expand Up @@ -343,13 +349,26 @@ export default class SnapshotState {
// https://github.com/vitejs/vite/issues/8657
stack.column--

// reject multiple inline snapshots at the same location
if (this._inlineSnapshotStacks.some(s => s.file === stack!.file && s.line === stack!.line && s.column === stack!.column)) {
// remove already succeeded snapshot
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.')
// reject multiple inline snapshots at the same location if snapshot is different
const snapshotsWithSameStack = this._inlineSnapshotStacks.filter(s => isSameStackPosition(s, stack!))
if (snapshotsWithSameStack.length > 0) {
// ensure only one snapshot will be written at the same location
this._inlineSnapshots = this._inlineSnapshots.filter(s => !isSameStackPosition(s, stack!))

const differentSnapshot = snapshotsWithSameStack.find(s => s.snapshot !== receivedSerialized)
if (differentSnapshot) {
throw Object.assign(
new Error(
'toMatchInlineSnapshot with different snapshots cannot be called at the same location',
),
{
actual: receivedSerialized,
expected: differentSnapshot.snapshot,
},
)
}
}
this._inlineSnapshotStacks.push({ ...stack, testId })
this._inlineSnapshotStacks.push({ ...stack, testId, snapshot: receivedSerialized })
}

// These are the conditions on when to write snapshots:
Expand Down
31 changes: 0 additions & 31 deletions test/cli/fixtures/fails/inline-snapshop-inside-loop.test.ts

This file was deleted.

8 changes: 0 additions & 8 deletions test/cli/test/__snapshots__/fails.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,6 @@ Error: InlineSnapshot cannot be used inside of test.each or describe.each
Error: InlineSnapshot cannot be used inside of test.each or describe.each"
`;
exports[`should fail inline-snapshop-inside-loop.test.ts 1`] = `
"Error: toMatchInlineSnapshot cannot be called multiple times at the same location.
Error: toMatchInlineSnapshot cannot be called multiple times at the same location.
Error: toMatchInlineSnapshot cannot be called multiple times at the same location.
Error: toMatchInlineSnapshot cannot be called multiple times at the same location.
Error: toMatchInlineSnapshot cannot be called multiple times at the same location."
`;
exports[`should fail mock-import-proxy-module.test.ts 1`] = `"Error: There are some problems in resolving the mocks API."`;
exports[`should fail nested-suite.test.ts 1`] = `"AssertionError: expected true to be false // Object.is equality"`;
Expand Down
5 changes: 1 addition & 4 deletions test/cli/test/fails.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ const root = resolve(__dirname, '../fixtures/fails')
const files = await glob(['**/*.test.ts'], { cwd: root, dot: true, expandDirectories: false })

it.each(files)('should fail %s', async (file) => {
const { stderr } = await runVitest({
root,
update: file === 'inline-snapshop-inside-loop.test.ts' ? true : undefined,
}, [file])
const { stderr } = await runVitest({ root }, [file])

expect(stderr).toBeTruthy()
const msg = String(stderr)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { expect, test } from 'vitest'

test('single', () => {
for (const value of ["test1", "test2"]) {
expect(value).toMatchInlineSnapshot()
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { expect, test } from 'vitest'

test('a', () => {
snap('test1')
})

test('b', () => {
snap('test2')
})

function snap(value: unknown) {
expect(value).toMatchInlineSnapshot()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { expect, test } from 'vitest'

test('single', () => {
for (const value of ["test1", "test1"]) {
expect(value).toMatchInlineSnapshot(`"test1"`)
}
})
13 changes: 13 additions & 0 deletions test/snapshots/test/fixtures/inline-multiple-calls/same2.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { expect, test } from 'vitest'

test('a', () => {
snap('test1')
})

test('b', () => {
snap('test1')
})

function snap(value: unknown) {
expect(value).toMatchInlineSnapshot(`"test1"`)
}
Loading

0 comments on commit d5cb821

Please sign in to comment.