Skip to content

Commit d5cb821

Browse files
jycouethi-ogawa
andauthored
fix(snapshot): allow inline snapshot calls on same location with same snapshot (#7464)
Co-authored-by: Hiroshi Ogawa <hi.ogawa.zz@gmail.com>
1 parent 4b5ed90 commit d5cb821

File tree

9 files changed

+453
-50
lines changed

9 files changed

+453
-50
lines changed

packages/snapshot/src/port/state.ts

+26-7
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,20 @@ interface SaveStatus {
4848
saved: boolean
4949
}
5050

51+
type ParsedStackPosition = Pick<ParsedStack, 'file' | 'line' | 'column'>
52+
53+
function isSameStackPosition(x: ParsedStackPosition, y: ParsedStackPosition) {
54+
return x.file === y.file && x.column === y.column && x.line === y.line
55+
}
56+
5157
export default class SnapshotState {
5258
private _counters = new CounterMap<string>()
5359
private _dirty: boolean
5460
private _updateSnapshot: SnapshotUpdateState
5561
private _snapshotData: SnapshotData
5662
private _initialData: SnapshotData
5763
private _inlineSnapshots: Array<InlineSnapshot>
58-
private _inlineSnapshotStacks: Array<ParsedStack & { testId: string }>
64+
private _inlineSnapshotStacks: Array<ParsedStack & { testId: string; snapshot: string }>
5965
private _testIdToKeys = new DefaultMap<string, string[]>(() => [])
6066
private _rawSnapshots: Array<RawSnapshot>
6167
private _uncheckedKeys: Set<string>
@@ -343,13 +349,26 @@ export default class SnapshotState {
343349
// https://github.com/vitejs/vite/issues/8657
344350
stack.column--
345351

346-
// reject multiple inline snapshots at the same location
347-
if (this._inlineSnapshotStacks.some(s => s.file === stack!.file && s.line === stack!.line && s.column === stack!.column)) {
348-
// remove already succeeded snapshot
349-
this._inlineSnapshots = this._inlineSnapshots.filter(s => !(s.file === stack!.file && s.line === stack!.line && s.column === stack!.column))
350-
throw new Error('toMatchInlineSnapshot cannot be called multiple times at the same location.')
352+
// reject multiple inline snapshots at the same location if snapshot is different
353+
const snapshotsWithSameStack = this._inlineSnapshotStacks.filter(s => isSameStackPosition(s, stack!))
354+
if (snapshotsWithSameStack.length > 0) {
355+
// ensure only one snapshot will be written at the same location
356+
this._inlineSnapshots = this._inlineSnapshots.filter(s => !isSameStackPosition(s, stack!))
357+
358+
const differentSnapshot = snapshotsWithSameStack.find(s => s.snapshot !== receivedSerialized)
359+
if (differentSnapshot) {
360+
throw Object.assign(
361+
new Error(
362+
'toMatchInlineSnapshot with different snapshots cannot be called at the same location',
363+
),
364+
{
365+
actual: receivedSerialized,
366+
expected: differentSnapshot.snapshot,
367+
},
368+
)
369+
}
351370
}
352-
this._inlineSnapshotStacks.push({ ...stack, testId })
371+
this._inlineSnapshotStacks.push({ ...stack, testId, snapshot: receivedSerialized })
353372
}
354373

355374
// These are the conditions on when to write snapshots:

test/cli/fixtures/fails/inline-snapshop-inside-loop.test.ts

-31
This file was deleted.

test/cli/test/__snapshots__/fails.test.ts.snap

-8
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,6 @@ Error: InlineSnapshot cannot be used inside of test.each or describe.each
5050
Error: InlineSnapshot cannot be used inside of test.each or describe.each"
5151
`;
5252
53-
exports[`should fail inline-snapshop-inside-loop.test.ts 1`] = `
54-
"Error: toMatchInlineSnapshot cannot be called multiple times at the same location.
55-
Error: toMatchInlineSnapshot cannot be called multiple times at the same location.
56-
Error: toMatchInlineSnapshot cannot be called multiple times at the same location.
57-
Error: toMatchInlineSnapshot cannot be called multiple times at the same location.
58-
Error: toMatchInlineSnapshot cannot be called multiple times at the same location."
59-
`;
60-
6153
exports[`should fail mock-import-proxy-module.test.ts 1`] = `"Error: There are some problems in resolving the mocks API."`;
6254
6355
exports[`should fail nested-suite.test.ts 1`] = `"AssertionError: expected true to be false // Object.is equality"`;

test/cli/test/fails.test.ts

+1-4
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,7 @@ const root = resolve(__dirname, '../fixtures/fails')
99
const files = await glob(['**/*.test.ts'], { cwd: root, dot: true, expandDirectories: false })
1010

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

1714
expect(stderr).toBeTruthy()
1815
const msg = String(stderr)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { expect, test } from 'vitest'
2+
3+
test('single', () => {
4+
for (const value of ["test1", "test2"]) {
5+
expect(value).toMatchInlineSnapshot()
6+
}
7+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { expect, test } from 'vitest'
2+
3+
test('a', () => {
4+
snap('test1')
5+
})
6+
7+
test('b', () => {
8+
snap('test2')
9+
})
10+
11+
function snap(value: unknown) {
12+
expect(value).toMatchInlineSnapshot()
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { expect, test } from 'vitest'
2+
3+
test('single', () => {
4+
for (const value of ["test1", "test1"]) {
5+
expect(value).toMatchInlineSnapshot(`"test1"`)
6+
}
7+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { expect, test } from 'vitest'
2+
3+
test('a', () => {
4+
snap('test1')
5+
})
6+
7+
test('b', () => {
8+
snap('test1')
9+
})
10+
11+
function snap(value: unknown) {
12+
expect(value).toMatchInlineSnapshot(`"test1"`)
13+
}

0 commit comments

Comments
 (0)