快照
透過 Vue School 的影片學習快照功能快照測試是一個非常有用的工具,當您想確保函式的輸出不會意外改變時,它能派上用場。
使用快照時,Vitest 會為給定值建立快照,然後將其與儲存在測試檔案旁的參考快照檔案進行比較。如果兩個快照不匹配,測試將會失敗:這表示變更可能是意外的,或者參考快照需要更新到新版本的結果。
使用快照
要擷取值的快照,您可以使用 expect() API 中的 toMatchSnapshot():
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchSnapshot();
});首次執行此測試時,Vitest 會建立一個快照檔案,其內容如下:
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports['toUpperCase 1'] = '"FOOBAR"';快照檔案應與程式碼變更一併提交,並作為程式碼審查過程的一部分進行審查。在後續的測試執行中,Vitest 會將渲染的輸出與先前的快照進行比較。如果兩者匹配,測試將會通過。如果兩者不匹配,則表示測試執行器在您的程式碼中發現了一個應該修復的錯誤,或者實作已更改,快照需要更新。
WARNING
當快照與非同步並行測試一起使用時,必須使用來自本地 測試環境 (Test Context) 的 expect,以確保檢測到正確的測試。
行內快照
同樣地,您可以使用 toMatchInlineSnapshot() 將快照直接儲存在測試檔案中。
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchInlineSnapshot();
});Vitest 不會建立快照檔案,而是直接修改測試檔案,將快照更新為字串:
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchInlineSnapshot('"FOOBAR"');
});這讓您可以直接看到預期的輸出,而無需跳轉到不同檔案。
WARNING
當快照與非同步並行測試一起使用時,必須使用來自本地 測試環境 (Test Context) 的 expect,以確保檢測到正確的測試。
更新快照
當接收到的值與快照不匹配時,測試會失敗並顯示它們之間的差異。當快照變更是預期的時,您可能希望從目前狀態更新快照。
在監視模式下,您可以在終端中按下 u 鍵直接更新失敗的快照。
或者您可以在 CLI 中使用 --update 或 -u 旗標,讓 Vitest 更新快照。
vitest -u檔案快照
呼叫 toMatchSnapshot() 時,我們會將所有快照儲存在格式化的快照檔案中。這表示我們需要對快照字串中的某些字元(即雙引號 " 和反引號 `)進行跳脫。同時,您可能會失去快照內容的語法高亮顯示(如果內容是某種語言)。
因此,我們引入了 toMatchFileSnapshot() 來明確地與檔案進行匹配。這允許您為快照檔案指定任何副檔名,並提高其可讀性。
import { expect, it } from 'vitest';
it('render basic', async () => {
const result = renderHTML(h('div', { class: 'foo' }));
await expect(result).toMatchFileSnapshot('./test/basic.output.html');
});它將與 ./test/basic.output.html 的內容進行比較,並且可以使用 --update 旗標寫回。
圖片快照
也可以使用 jest-image-snapshot 擷取圖片快照。
npm i -D jest-image-snapshottest('image snapshot', () => {
expect(readFileSync('./test/stubs/input-image.png')).toMatchImageSnapshot();
});自訂序列化器
您可以添加自己的邏輯來更改快照的序列化方式。與 Jest 類似,Vitest 為內建的 JavaScript 型別、HTML 元素、ImmutableJS 和 React 元素提供了預設的序列化器。
您可以透過使用 expect.addSnapshotSerializer API 明確地添加自訂序列化器。
expect.addSnapshotSerializer({
serialize(val, config, indentation, depth, refs, printer) {
// `printer` 是一個使用現有外掛程式序列化值的函式。
return `Pretty foo: ${printer(val.foo, config, indentation, depth, refs)}`;
},
test(val) {
return val && Object.prototype.hasOwnProperty.call(val, 'foo');
},
});我們也支援 snapshotSerializers 選項來自動添加自訂序列化器。
import { SnapshotSerializer } from 'vitest';
export default {
serialize(val, config, indentation, depth, refs, printer) {
// `printer` 是一個使用現有外掛程式序列化值的函式。
return `Pretty foo: ${printer(val.foo, config, indentation, depth, refs)}`;
},
test(val) {
return val && Object.prototype.hasOwnProperty.call(val, 'foo');
},
} satisfies SnapshotSerializer;import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
snapshotSerializers: ['path/to/custom-serializer.ts'],
},
});添加如下測試後:
test('foo snapshot test', () => {
const bar = {
foo: {
x: 1,
y: 2,
},
};
expect(bar).toMatchSnapshot();
});您將得到以下快照:
Pretty foo: Object {
"x": 1,
"y": 2,
}我們採用 Jest 的 pretty-format 來序列化快照。您可以在這裡閱讀更多相關資訊:pretty-format。
與 Jest 的差異
Vitest 提供了與 Jest 幾乎相容的快照功能,但有幾個例外:
1. 快照檔案中的註解標頭不同 {#_1-comment-header-in-the-snapshot-file-is-different}
- // Jest Snapshot v1, https://goo.gl/fbAQLP
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html這實際上不會影響功能,但從 Jest 遷移時可能會影響您的提交差異。
2. printBasicPrototype 預設為 false {#_2-printbasicprototype-is-default-to-false}
Jest 和 Vitest 的快照都由 pretty-format 提供支援。在 Vitest 中,我們將 printBasicPrototype 預設為 false 以提供更簡潔的快照輸出,而在 Jest <29.0.0 中,它預設為 true。
import { expect, test } from 'vitest';
test('snapshot', () => {
const bar = [
{
foo: 'bar',
},
];
// 在 Jest 中
expect(bar).toMatchInlineSnapshot(`
Array [
Object {
"foo": "bar",
},
]
`);
// 在 Vitest 中
expect(bar).toMatchInlineSnapshot(`
[
{
"foo": "bar",
},
]
`);
});我們認為這對於可讀性和整體開發體驗來說是一個更合理的預設值。如果您仍然喜歡 Jest 的行為,您可以更改您的設定:
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
snapshotFormat: {
printBasicPrototype: true,
},
},
});3. 自訂訊息使用大於符號 > 作為分隔符號,而不是冒號 : {#_3-chevron-is-used-as-a-separator-instead-of-colon-for-custom-messages}
當在建立快照檔案時傳遞自訂訊息時,Vitest 使用大於符號 > 作為分隔符號而不是冒號 :,以提高可讀性。
對於以下測試程式碼範例:
test('toThrowErrorMatchingSnapshot', () => {
expect(() => {
throw new Error('error');
}).toThrowErrorMatchingSnapshot('hint');
});在 Jest 中,快照將是:
exports[`toThrowErrorMatchingSnapshot: hint 1`] = `"error"`;在 Vitest 中,等效的快照將是:
exports[`toThrowErrorMatchingSnapshot > hint 1`] = `[Error: error]`;4. toThrowErrorMatchingSnapshot 和 toThrowErrorMatchingInlineSnapshot 的預設 Error 快照不同 {#_4-default-error-snapshot-is-different-for-tothrowerrormatchingsnapshot-and-tothrowerrormatchinginlinesnapshot}
import { expect, test } from 'vitest'
test('snapshot', () => {
// 在 Jest 和 Vitest 中
expect(new Error('error')).toMatchInlineSnapshot(`[Error: error]`)
// Jest 會對 `Error` 實體 的 `Error.message` 進行快照
// Vitest 會列印與 toMatchInlineSnapshot 相同的值
expect(() => {
throw new Error('error')
}).toThrowErrorMatchingInlineSnapshot(`"error"`)
}).toThrowErrorMatchingInlineSnapshot(`[Error: error]`)
})