Skip to content
Vitest 3
Main Navigation 指南 & API配置瀏覽器模式進階 API
3.2.0
2.1.9
1.6.1
0.34.6

繁體中文

English
简体中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
한국어
Italiano
Polski
Türkçe
čeština
magyar

繁體中文

English
简体中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
한국어
Italiano
Polski
Türkçe
čeština
magyar

外觀

Sidebar Navigation

簡介

為何選擇 Vitest

快速入門

功能特色

配置參考

API

測試 API 參考

模擬函式

Vi

expect

expectTypeOf

assert

assertType

指南

命令列介面

測試篩選

測試專案

報告器

程式碼覆蓋率

快照

模擬(Mocking)

平行化

型別測試

Vitest UI

內聯測試

測試上下文

測試註解

測試環境

擴展匹配器

IDE 整合

偵錯

常見錯誤

遷移指南

遷移到 Vitest 3.0

從 Jest 遷移

效能

測試效能分析

提升效能

瀏覽器模式

進階 API

與其他測試執行器的比較

本頁導覽

遷移指南 ​

升級至 Vitest 3.0 ​

測試選項作為第三個參數 ​

如果您將物件作為第三個參數傳遞給 test 或 describe 函數,Vitest 3.0 會發出警告:

ts
test('validation works', () => {
  // ...
}, { retry: 3 }); 

test('validation works', { retry: 3 }, () => { 
  // ...
});

如果第三個參數是物件,下一個主要版本將會拋出錯誤。請注意,逾時時間並未棄用:

ts
test('validation works', () => {
  // ...
}, 1000); // Ok ✅

browser.name 和 browser.providerOptions 已棄用 ​

browser.name 和 browser.providerOptions 都將在 Vitest 4 中移除。請改用新的 browser.instances 選項:

ts
export default defineConfig({
  test: {
    browser: {
      name: 'chromium', 
      providerOptions: { 
        launch: { devtools: true }, 
      }, 
      instances: [ 
        { 
          browser: 'chromium', 
          launch: { devtools: true }, 
        }, 
      ], 
    },
  },
})

透過新的 browser.instances 欄位,您還可以指定多個瀏覽器配置。

spy.mockReset 現在會還原原始實作 ​

以前,沒有好的方法可以在不重新套用 spy 的情況下將 spy 重置為原始實作。現在,spy.mockReset 會將實作函數重置為原始函數,而不是一個假的 noop。

ts
const foo = {
  bar: () => 'Hello, world!',
};

vi.spyOn(foo, 'bar').mockImplementation(() => 'Hello, mock!');

foo.bar(); // 'Hello, mock!'

foo.bar.mockReset();

foo.bar(); // undefined
foo.bar(); // 'Hello, world!'

vi.spyOn 如果方法已被模擬,則會重複使用模擬 ​

以前,Vitest 在監控物件時總是會分配一個新的 spy。這導致 mockRestore 出錯,因為它會將 spy 還原到先前的 spy,而不是原始函數:

ts
vi.spyOn(fooService, 'foo').mockImplementation(() => 'bar');
vi.spyOn(fooService, 'foo').mockImplementation(() => 'bar');
vi.restoreAllMocks();
vi.isMockFunction(fooService.foo); // true
vi.isMockFunction(fooService.foo); // false

假計時器預設值 ​

Vitest 不再提供預設的 fakeTimers.toFake 選項。現在,Vitest 會模擬任何可用的計時器相關 API(除了 nextTick)。具體來說,當呼叫 vi.useFakeTimers 時,performance.now() 現在會被模擬。

ts
vi.useFakeTimers();

performance.now(); // original
performance.now(); // fake

您可以透過在呼叫 vi.useFakeTimers 時或在配置中全域指定計時器來恢復先前的行為:

ts
export default defineConfig({
  test: {
    fakeTimers: {
      toFake: [ 
        'setTimeout', 
        'clearTimeout', 
        'setInterval', 
        'clearInterval', 
        'setImmediate', 
        'clearImmediate', 
        'Date', 
      ] 
    },
  },
})

更嚴格的錯誤相等性 ​

Vitest 現在在透過 toEqual 或 toThrowError 比較錯誤時會檢查更多屬性。Vitest 現在會比較 name、message、cause 和 AggregateError.errors。對於 Error.cause,比較是以非對稱方式進行的:

ts
expect(new Error('hi', { cause: 'x' })).toEqual(new Error('hi')); // ✅
expect(new Error('hi')).toEqual(new Error('hi', { cause: 'x' })); // ❌

除了檢查更多屬性之外,Vitest 現在還會比較錯誤原型。例如,如果拋出 TypeError,相等性檢查應該參考 TypeError,而不是 Error:

ts
expect(() => {
  throw new TypeError('type error');
})
  .toThrowError(new Error('type error')) 
  .toThrowError(new TypeError('type error')); 

有關更多詳細資訊,請參閱 PR:#5876。

Vite 6 預設不解析 module 條件匯出 ​

Vite 6 允許更靈活的 resolve.conditions 選項,Vitest 預設將其配置為排除 module 條件匯出。 有關 Vite 端變更的詳細資訊,請參閱 Vite 6 遷移指南。

Custom 類型已棄用 API ​

Custom 類型現在是 Test 類型的別名。請注意,Vitest 在 2.1 中更新了公開類型,並將匯出名稱更改為 RunnerCustomCase 和 RunnerTestCase:

ts
import {
  RunnerCustomCase, 
  RunnerTestCase, 
} from 'vitest';

如果您正在使用 getCurrentSuite().custom(),則返回任務的 type 現在等於 'test'。Custom 類型將在 Vitest 4 中移除。

WorkspaceSpec 類型不再使用 API ​

在公開 API 中,此類型以前用於自訂 sequencers。請改為遷移到 TestSpecification。

onTestFinished 和 onTestFailed 現在接收上下文 ​

onTestFinished 和 onTestFailed 鉤子以前接收測試結果作為第一個參數。現在,它們接收測試上下文,就像 beforeEach 和 afterEach 一樣。

快照 API 的變更 API ​

@vitest/snapshot 中的公開快照 API 已更改,以支援單次執行中的多個狀態。有關更多詳細資訊,請參閱 PR:#6817

請注意,此變更僅影響直接使用快照 API 的開發人員。.toMatchSnapshot API 沒有任何變更。

resolveConfig 類型簽章的變更 API ​

resolveConfig 現在更有用。它不再接受已解析的 Vite 配置,而是接受使用者配置並返回已解析的配置。

此函數未在內部使用,僅作為公開 API 公開。

清理 vitest/reporters 類型 API ​

vitest/reporters 入口點現在只匯出報告器實作和選項類型。如果您需要存取 TestCase/TestSuite 和其他任務相關類型,請從 vitest/node 額外匯入它們。

即使覆寫 coverage.excludes,覆蓋率也會忽略測試檔案。 ​

現在無法透過覆寫 coverage.excludes 將測試檔案包含在覆蓋率報告中。測試檔案現在總是會被排除。

遷移至 Vitest 2.0 ​

預設池為 forks ​

Vitest 2.0 將 pool 的預設配置更改為 'forks',以獲得更好的穩定性。您可以在 PR 中閱讀完整的動機。

如果您在未指定 pool 的情況下使用了 poolOptions,您可能需要更新配置:

ts
export default defineConfig({
  test: {
    poolOptions: {
      threads: { 
        singleThread: true, 
      }, 
      forks: { 
        singleFork: true, 
      }, 
    }
  }
})

鉤子以堆疊方式執行 ​

在 Vitest 2.0 之前,所有鉤子都平行執行。在 2.0 中,所有鉤子都依序執行。此外,afterAll/afterEach 鉤子以相反順序執行。

要恢復鉤子的平行執行,請將 sequence.hooks 更改為 'parallel':

ts
export default defineConfig({
  test: {
    sequence: { 
      hooks: 'parallel', 
    }, 
  },
})

suite.concurrent 平行執行所有測試 ​

以前,在套件上指定 concurrent 會按套件分組平行測試,並依序執行。現在,遵循 Jest 的行為,所有測試都平行執行(受 maxConcurrency 限制)。

V8 覆蓋率的 coverage.ignoreEmptyLines 預設啟用 ​

coverage.ignoreEmptyLines 的預設值現在為 true。此重大變更可能會影響程式碼覆蓋率報告,需要為某些專案調整覆蓋率閾值。此調整僅影響當 coverage.provider 為 'v8' 時的預設設定。

移除 watchExclude 選項 ​

Vitest 使用 Vite 的監控器。透過將檔案或目錄新增到 server.watch.ignored 來排除它們:

ts
export default defineConfig({
  server: { 
    watch: { 
      ignored: ['!node_modules/examplejs'] 
    } 
  } 
})

--segfault-retry 已移除 ​

隨著預設池的變更,此選項不再需要。如果您遇到 segfault 錯誤,請嘗試切換到 'forks' 池。如果問題仍然存在,請開啟一個新問題並提供重現步驟。

套件任務中的空任務已移除 ​

這是對進階 任務 API 的變更。以前,遍歷 .suite 最終會導致使用空內部套件,而不是檔案任務。

這使得 .suite 成為可選;如果任務定義在頂層,它將沒有套件。您可以回退到現在所有任務(包括檔案任務本身,因此請注意不要陷入無限遞迴)都存在的 .file 屬性。

此變更還從 expect.getState().currentTestName 中移除了檔案,並使 expect.getState().testPath 成為必需。

task.meta 已新增至 JSON 報告器 ​

JSON 報告器現在會為每個斷言結果列印 task.meta。

模擬函數的簡化泛型類型(例如 vi.fn<T>、Mock<T>) ​

以前 vi.fn<TArgs, TReturn> 分別接受兩個泛型類型用於參數和返回值。這已更改為直接接受函數類型 vi.fn<T>,以簡化使用。

ts
import { vi } from 'vitest';
import type { Mock } from 'vitest';

const add = (x: number, y: number): number => x + y;

// using vi.fn<T>
const mockAdd = vi.fn<Parameters<typeof add>, ReturnType<typeof add>>(); 
const mockAdd = vi.fn<typeof add>(); 

// using Mock<T>
const mockAdd: Mock<Parameters<typeof add>, ReturnType<typeof add>> = vi.fn(); 
const mockAdd: Mock<typeof add> = vi.fn(); 

存取已解析的 mock.results ​

以前,如果函數返回 Promise,Vitest 會解析 mock.results 值。現在有一個單獨的 mock.settledResults 屬性,只有當返回的 Promise 被解析或拒絕時才會填充。

ts
const fn = vi.fn().mockResolvedValueOnce('result');
await fn();

const result = fn.mock.results[0]; // 'result'
const result = fn.mock.results[0]; // 'Promise<result>'

const settledResult = fn.mock.settledResults[0]; // 'result'

隨著此變更,我們還引入了新的 toHaveResolved* 匹配器,類似於 toHaveReturned,以便在您以前使用 toHaveReturned 時更容易遷移:

ts
const fn = vi.fn().mockResolvedValueOnce('result');
await fn();

expect(fn).toHaveReturned('result'); 
expect(fn).toHaveResolved('result'); 

瀏覽器模式 ​

Vitest 瀏覽器模式在 Beta 週期中發生了許多變更。您可以在 GitHub 討論頁面 上閱讀我們關於瀏覽器模式的理念。

大多數變更都是新增的,但也有一些小的破壞性變更:

  • none 供應商已重新命名為 preview #5842
  • preview 供應商現在是預設值 #5842
  • indexScripts 已重新命名為 orchestratorScripts #5842

已移除的棄用選項 ​

一些棄用選項已移除:

  • vitest typecheck 命令 - 請改用 vitest --typecheck
  • VITEST_JUNIT_CLASSNAME 和 VITEST_JUNIT_SUITE_NAME 環境變數(請改用報告器選項)
  • 檢查 c8 覆蓋率(請改用 coverage-v8)
  • 從 vitest 匯出 SnapshotEnvironment - 請改從 vitest/snapshot 匯入
  • SpyInstance 已移除,改用 MockInstance

遷移至 Vitest 1.0 ​

最低要求 ​

Vitest 1.0 需要 Vite 5.0 和 Node.js 18 或更高版本。

所有 @vitest/* 子套件都需要 Vitest 1.0 版。

快照更新 #3961 ​

快照中的引號不再逸出,所有快照都使用反引號 (`),即使字串只有一行。

  1. 引號不再逸出:
diff
expect({ foo: 'bar' }).toMatchInlineSnapshot(`
  Object {
-    \\"foo\\": \\"bar\\",
+    "foo": "bar",
  }
`)
  1. 單行快照現在使用 "`" 引號而不是 ':':
diff
- expect('some string').toMatchInlineSnapshot('"some string"')
+ expect('some string').toMatchInlineSnapshot(`"some string"`)

@vitest/snapshot 套件也有 變更。如果您沒有直接使用它,則無需更改任何內容。

  • 您不再需要僅為了覆寫 equalityCheck 方法而擴展 SnapshotClient:只需在實例化時將其作為 isEqual 傳遞即可
  • client.setTest 已重新命名為 client.startCurrentRun
  • client.resetCurrent 已重新命名為 client.finishCurrentRun

池已標準化 #4172 ​

我們移除了許多配置選項,以便更容易根據您的需求配置執行器。如果您依賴 --threads 或其他相關旗標,請查看遷移範例。

  • --threads 現在是 --pool=threads
  • --no-threads 現在是 --pool=forks
  • --single-thread 現在是 --poolOptions.threads.singleThread
  • --experimental-vm-threads 現在是 --pool=vmThreads
  • --experimental-vm-worker-memory-limit 現在是 --poolOptions.vmThreads.memoryLimit
  • --isolate 現在是 --poolOptions.<pool-name>.isolate 和 browser.isolate
  • test.maxThreads 現在是 test.poolOptions.<pool-name>.maxThreads
  • test.minThreads 現在是 test.poolOptions.<pool-name>.minThreads
  • test.useAtomics 現在是 test.poolOptions.<pool-name>.useAtomics
  • test.poolMatchGlobs.child_process 現在是 test.poolMatchGlobs.forks
  • test.poolMatchGlobs.experimentalVmThreads 現在是 test.poolMatchGlobs.vmThreads
diff
{
  scripts: {
-    "test": "vitest --no-threads"
     // For identical behaviour:
+    "test": "vitest --pool forks --poolOptions.forks.singleFork"
     // Or multi parallel forks:
+    "test": "vitest --pool forks"

  }
}
diff
{
  scripts: {
-    "test": "vitest --experimental-vm-threads"
+    "test": "vitest --pool vmThreads"
  }
}
diff
{
  scripts: {
-    "test": "vitest --isolate false"
+    "test": "vitest --poolOptions.threads.isolate false"
  }
}
diff
{
  scripts: {
-    "test": "vitest --no-threads --isolate false"
+    "test": "vitest --pool forks --poolOptions.forks.isolate false"
  }
}

覆蓋率變更 #4265, #4442 ​

選項 coverage.all 現在預設啟用。這表示所有符合 coverage.include 模式的專案檔案都將被處理,即使它們未執行。

覆蓋率閾值 API 的形狀已更改,現在支援使用 glob 模式為特定檔案指定閾值:

diff
export default defineConfig({
  test: {
    coverage: {
-      perFile: true,
-      thresholdAutoUpdate: true,
-      100: true,
-      lines: 100,
-      functions: 100,
-      branches: 100,
-      statements: 100,
+      thresholds: {
+        perFile: true,
+        autoUpdate: true,
+        100: true,
+        lines: 100,
+        functions: 100,
+        branches: 100,
+        statements: 100,
+      }
    }
  }
})

模擬類型 #4400 ​

為了採用 Jest 風格的「Mock」命名,一些類型已被移除。

diff
- import { EnhancedSpy, SpyInstance } from 'vitest'
+ import { MockInstance } from 'vitest'

WARNING

SpyInstance 已棄用,改用 MockInstance,並將在下一個主要版本中移除。

計時器模擬 #3925 ​

vi.useFakeTimers() 不再自動模擬 process.nextTick。 仍然可以透過明確指定 vi.useFakeTimers({ toFake: ['nextTick'] }) 來模擬 process.nextTick。

但是,當使用 --pool=forks 時,無法模擬 process.nextTick。如果您需要 process.nextTick 模擬,請使用不同的 --pool 選項。

從 Jest 遷移 ​

Vitest 的設計與 Jest 相容的 API,以便盡可能簡化從 Jest 的遷移。儘管如此,您仍然可能會遇到以下差異:

預設為全域變數 ​

Jest 預設啟用其 全域變數 API。Vitest 則不然。您可以透過 全域變數配置設定 啟用全域變數,或更新您的程式碼以使用從 vitest 模組匯入的內容。

如果您決定停用全域變數,請注意像 testing-library 這樣的常用函式庫將不會自動執行 DOM 清理。

spy.mockReset ​

Jest 的 mockReset 會將模擬實作替換為一個返回 undefined 的空函數。

Vitest 的 mockReset 會將模擬實作重置為其原始實作。 也就是說,重置由 vi.fn(impl) 建立的模擬會將模擬實作重置為 impl。

模組模擬 ​

在 Jest 中模擬模組時,工廠參數的返回值是預設匯出。在 Vitest 中,工廠參數必須返回一個明確定義每個匯出的物件。例如,以下 jest.mock 必須更新如下:

ts
jest.mock('./some-path', () => 'hello') 
vi.mock('./some-path', () => ({ 
  default: 'hello', 
})) 

有關更多詳細資訊,請參閱 vi.mock API 部分。

自動模擬行為 ​

與 Jest 不同,<root>/__mocks__ 中的模擬模組不會載入,除非呼叫 vi.mock()。如果您需要它們在每個測試中都被模擬,就像在 Jest 中一樣,您可以在 setupFiles 中模擬它們。

匯入模擬套件的原始檔案 ​

如果您只部分模擬套件,您可能以前使用過 Jest 的函數 requireActual。在 Vitest 中,您應該將這些呼叫替換為 vi.importActual。

ts
const { cloneDeep } = jest.requireActual('lodash/cloneDeep'); 
const { cloneDeep } = await vi.importActual('lodash/cloneDeep'); 

將模擬擴展到外部函式庫 ​

Jest 預設會這樣做,當模擬模組並希望此模擬擴展到使用相同模組的其他外部函式庫時,您應該明確指出您希望模擬哪個第三方函式庫,以便外部函式庫成為您的原始碼的一部分,方法是使用 server.deps.inline。

server.deps.inline: ["lib-name"]

expect.getState().currentTestName ​

Vitest 的 test 名稱以 > 符號連接,以便更容易區分測試和套件,而 Jest 使用空格 ()。

diff
- `${describeTitle} ${testTitle}`
+ `${describeTitle} > ${testTitle}`

環境變數 ​

就像 Jest 一樣,如果 NODE_ENV 之前未設定,Vitest 會將其設定為 test。Vitest 也有一個 JEST_WORKER_ID 的對應項,稱為 VITEST_POOL_ID(總是小於或等於 maxThreads),因此如果您依賴它,請不要忘記重新命名它。Vitest 還公開了 VITEST_WORKER_ID,它是正在執行工作者的唯一 ID - 此數字不受 maxThreads 影響,並且會隨著每個建立的工作者而增加。

替換屬性 ​

如果您想修改物件,您將在 Jest 中使用 replaceProperty API,您也可以在 Vitest 中使用 vi.stubEnv 或 vi.spyOn 來執行相同的操作。

完成回呼 ​

從 Vitest v0.10.0 開始,宣告測試的回呼樣式已棄用。您可以將它們重寫為使用 async/await 函數,或使用 Promise 來模擬回呼樣式。

js
it('should work', (done) => {  
it('should work', () => new Promise(done => { 
  // ...
  done()
}) 
})) 

鉤子 ​

beforeAll/beforeEach 鉤子在 Vitest 中可能會返回 teardown 函數。因此,如果您的鉤子返回的不是 undefined 或 null,您可能需要重寫您的鉤子宣告:

ts
beforeEach(() => setActivePinia(createTestingPinia())) 
beforeEach(() => { setActivePinia(createTestingPinia()) }) 

在 Jest 中,鉤子是依序呼叫的(一個接一個)。預設情況下,Vitest 會平行執行鉤子。要使用 Jest 的行為,請更新 sequence.hooks 選項:

ts
export default defineConfig({
  test: {
    sequence: { 
      hooks: 'list', 
    } 
  }
})

類型 ​

Vitest 沒有等同於 jest 命名空間的內容,因此您需要直接從 vitest 匯入類型:

ts
let fn: jest.Mock<(name: string) => number>; 
import type { Mock } from 'vitest'; 
let fn: Mock<(name: string) => number>; 

計時器 ​

Vitest 不支援 Jest 的舊版計時器。

逾時 ​

如果您使用 jest.setTimeout,您需要遷移到 vi.setConfig:

ts
jest.setTimeout(5_000); 
vi.setConfig({ testTimeout: 5_000 }); 

Vue 快照 ​

這不是 Jest 特有的功能,但如果您以前使用 Jest 和 vue-cli 預設,您將需要安裝 jest-serializer-vue 套件,並在 setupFiles 中使用它:

js
import { defineConfig } from 'vite';

export default defineConfig({
  test: {
    setupFiles: ['./tests/unit/setup.js'],
  },
});
js
import vueSnapshotSerializer from 'jest-serializer-vue';

expect.addSnapshotSerializer(vueSnapshotSerializer);

否則您的快照將會有許多逸出的 " 字元。

Pager
上一頁常見錯誤
下一頁測試效能分析

以 MIT 授權條款 發布。

版權所有 (c) 2021-Present Vitest Team

https://vitest.dev/guide/migration

以 MIT 授權條款 發布。

版權所有 (c) 2021-Present Vitest Team