Skip to content

Commit 1606f34

Browse files
authored
fix(snapshot): reject multiple toMatchInlineSnapshot updates at the same location (#6332)
1 parent 153ff01 commit 1606f34

File tree

5 files changed

+50
-1
lines changed

5 files changed

+50
-1
lines changed

packages/snapshot/src/port/state.ts

+7
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,13 @@ export default class SnapshotState {
158158
// location for js files, but `column-1` points to the same in both js/ts
159159
// https://github.com/vitejs/vite/issues/8657
160160
stack.column--
161+
// reject multiple inline snapshots at the same location
162+
const duplicateIndex = this._inlineSnapshots.findIndex(s => s.file === stack.file && s.line === stack.line && s.column === stack.column)
163+
if (duplicateIndex >= 0) {
164+
// remove the first one to avoid updating an inline snapshot
165+
this._inlineSnapshots.splice(duplicateIndex, 1)
166+
throw new Error('toMatchInlineSnapshot cannot be called multiple times at the same location.')
167+
}
161168
this._inlineSnapshots.push({
162169
snapshot: receivedSerialized,
163170
...stack,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import {test, expect} from "vitest";
2+
3+
test("ok", () => {
4+
expect("ok").toMatchInlineSnapshot(`"ok"`);
5+
});
6+
7+
test("fail 1", () => {
8+
for (const str of ["foo", "bar"]) {
9+
expect(str).toMatchInlineSnapshot();
10+
}
11+
});
12+
13+
test("fail 3", () => {
14+
for (const str of ["ok", "ok"]) {
15+
expect(str).toMatchInlineSnapshot();
16+
}
17+
});
18+
19+
test("somehow ok", () => {
20+
for (const str of ["ok", "ok"]) {
21+
expect(str).toMatchInlineSnapshot(`"ok"`);
22+
}
23+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import {test, expect} from "vitest";
2+
3+
// this test causes infinite re-run when --watch and --update
4+
// since snapshot update switches between "foo" and "bar" forever.
5+
test("fail 2", () => {
6+
for (const str of ["foo", "bar"]) {
7+
expect(str).toMatchInlineSnapshot(`"bar"`);
8+
}
9+
});

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

+7
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ Error: InlineSnapshot cannot be used inside of test.each or describe.each
3131
Error: InlineSnapshot cannot be used inside of test.each or describe.each"
3232
`;
3333
34+
exports[`should fail inline-snapshop-inside-loop-update-all.test.ts > inline-snapshop-inside-loop-update-all.test.ts 1`] = `
35+
"Error: toMatchInlineSnapshot cannot be called multiple times at the same location.
36+
Error: toMatchInlineSnapshot cannot be called multiple times at the same location."
37+
`;
38+
39+
exports[`should fail inline-snapshop-inside-loop-update-none.test.ts > inline-snapshop-inside-loop-update-none.test.ts 1`] = `"Error: Snapshot \`fail 2 1\` mismatched"`;
40+
3441
exports[`should fail mock-import-proxy-module.test.ts > mock-import-proxy-module.test.ts 1`] = `"Error: There are some problems in resolving the mocks API."`;
3542
3643
exports[`should fail nested-suite.test.ts > nested-suite.test.ts 1`] = `"AssertionError: expected true to be false // Object.is equality"`;

test/cli/test/fails.test.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ const root = resolve(__dirname, '../fixtures/fails')
88
const files = await fg('**/*.test.ts', { cwd: root, dot: true })
99

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

1316
expect(stderr).toBeTruthy()
1417
const msg = String(stderr)

0 commit comments

Comments
 (0)