Skip to content
Vitest 2
Main Navigation 指南API配置瀏覽器模式高級
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

開始使用

功能特性

工作區

命令列界面

測試過濾器

報告器

覆蓋率

快照

模擬(Mocking)

測試類型

Vitest UI

原始碼測試

測試上下文

測試環境

擴展匹配器

IDE 整合支援

偵錯

與其他測試執行器的比較

遷移指南

常見錯誤

Profiling Test Performance

提升效能

本頁導覽

遷移指南 ​

遷移至 Vitest 2.0 ​

預設執行緒池變更為 forks ​

Vitest 2.0 已將 pool 的預設配置調整為 'forks',以提升穩定性。您可透過此 PR 深入了解其完整動機。

若您先前在使用 poolOptions 時未明確指定 pool 類型,則可能需要更新您的配置:

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

鉤子(Hooks)以堆疊方式執行 ​

在 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 { type Mock, vi } from 'vitest';

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

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

// 使用 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

Pool 標準化 #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"
  }
}

Coverage 變更 #4265, #4442 ​

選項 coverage.all 現在預設為啟用。這表示即使未執行,也會處理所有符合 coverage.include 樣式的專案檔案。

Coverage 臨界值 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,
+      }
    }
  }
})

Mock 類型變更 #4400 ​

為了採用 Jest 風格的 "Mock" 命名,移除了一些類型。

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

WARNING

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

Timer Mock #3925 ​

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

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

從 Jest 遷移 ​

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

預設為全域變數 ​

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

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

模組模擬 ​

在 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 來模擬回調樣式。

it('should work', (done) => {  // [!code --]
it('should work', () => new Promise(done => { // [!code ++]
  // ...
  done()
}) // [!code --]
})) // [!code ++]

鉤子(Hooks) ​

beforeAll/beforeEach 鉤子在 Vitest 中可能會返回 清理函數。因此,若您的鉤子返回的不是 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) 2024 Mithril Contributors

https://v2.vitest.dev/guide/migration

以 MIT 授權條款 發布。

版權所有 (c) 2024 Mithril Contributors