瀏覽器模式 Experimental
本頁提供 Vitest API 中實驗性瀏覽器模式功能的相關資訊。此功能允許您在瀏覽器中原生執行測試,並可存取 window 和 document 等瀏覽器全域變數。此功能目前仍在開發中,未來的 API 可能會有所調整。


安裝
為簡化設定流程,您可以使用 vitest init browser 命令來安裝所需的依賴項並建立瀏覽器配置。
npx vitest init browseryarn exec vitest init browserpnpx vitest init browserbunx vitest init browser手動安裝
您也可以手動安裝套件。預設情況下,瀏覽器模式無需任何額外的 E2E 提供者即可在本地執行測試,因為它會重用您現有的瀏覽器。
npm install -D vitest @vitest/browseryarn add -D vitest @vitest/browserpnpm add -D vitest @vitest/browserbun add -D vitest @vitest/browserWARNING
然而,要在 CI 環境中執行測試,您需要安裝 playwright 或 webdriverio。我們也建議在本地測試時切換到其中一個提供者,而非使用預設的 preview 提供者,因為 preview 依賴於模擬事件,而非使用 Chrome DevTools Protocol。
如果您尚未接觸這些工具,我們建議您從 Playwright 開始,因為它支援平行執行,能讓您的測試執行得更快。此外,Playwright 使用的 Chrome DevTools Protocol 通常比 WebDriver 更快。
::: tabs key:provider == Playwright Playwright 是一個用於 Web 測試和自動化的框架。
npm install -D vitest @vitest/browser playwrightyarn add -D vitest @vitest/browser playwrightpnpm add -D vitest @vitest/browser playwrightbun add -D vitest @vitest/browser playwright== WebdriverIO
WebdriverIO 允許您使用 WebDriver 協定(protocol)在本地執行測試。
npm install -D vitest @vitest/browser webdriverioyarn add -D vitest @vitest/browser webdriveriopnpm add -D vitest @vitest/browser webdriveriobun add -D vitest @vitest/browser webdriverio配置
要在 Vitest 配置中啟用瀏覽器模式,您可以使用 --browser 標誌或在 Vitest 配置檔中將 browser.enabled 欄位設定為 true。以下是使用 browser 欄位的配置範例:
export default defineConfig({
test: {
browser: {
provider: 'playwright', // 或 'webdriverio'
enabled: true,
name: 'chromium', // 瀏覽器名稱是必需的
},
},
});INFO
Vitest 分配埠號 63315 以避免與開發伺服器發生衝突,讓您可以同時執行兩者。您可以使用 browser.api 選項更改此設定。
自 Vitest 2.1.5 起,CLI 不再自動顯示 Vite URL。在監聽模式下執行時,您可以按「b」來顯示 URL。
如果您之前沒有使用過 Vite,請確保您已安裝並在配置中指定了您的框架外掛程式。某些框架可能需要額外配置才能正常運作 - 請查閱其 Vite 相關文件以確保。
import { defineConfig } from 'vitest/config';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [vue()],
test: {
browser: {
enabled: true,
provider: 'playwright',
name: 'chromium',
},
},
});import { defineConfig } from 'vitest/config';
import { svelte } from '@sveltejs/vite-plugin-svelte';
export default defineConfig({
plugins: [svelte()],
test: {
browser: {
enabled: true,
provider: 'playwright',
name: 'chromium',
},
},
});import { defineConfig } from 'vitest/config';
import solidPlugin from 'vite-plugin-solid';
export default defineConfig({
plugins: [solidPlugin()],
test: {
browser: {
enabled: true,
provider: 'playwright',
name: 'chromium',
},
},
});import { defineConfig } from 'vitest/config';
import marko from '@marko/vite';
export default defineConfig({
plugins: [marko()],
test: {
browser: {
enabled: true,
provider: 'playwright',
name: 'chromium',
},
},
});TIP
react 不需要外掛程式即可運作,但 preact 需要額外配置才能使別名運作。
如果您需要使用基於 Node 的執行器執行某些測試,您可以定義一個工作區檔案,其中包含不同測試策略的獨立配置:
// vitest.workspace.ts
import { defineWorkspace } from 'vitest/config';
export default defineWorkspace([
{
test: {
// 檔案命名慣例範例,
// 您不一定要遵循
include: [
'tests/unit/**/*.{test,spec}.ts',
'tests/**/*.unit.{test,spec}.ts',
],
name: 'unit',
environment: 'node',
},
},
{
test: {
// 檔案命名慣例範例,
// 您不一定要遵循
include: [
'tests/browser/**/*.{test,spec}.ts',
'tests/**/*.browser.{test,spec}.ts',
],
name: 'browser',
browser: {
enabled: true,
name: 'chrome',
},
},
},
]);提供者配置
:::tabs key:provider == Playwright 您可以透過 providerOptions 欄位配置 Vitest 如何啟動瀏覽器並建立頁面上下文:
export default defineConfig({
test: {
browser: {
providerOptions: {
launch: {
devtools: true,
},
context: {
geolocation: {
latitude: 45,
longitude: -30,
},
reducedMotion: 'reduce',
},
},
},
},
});若要啟用類型提示,請將 @vitest/browser/providers/playwright 新增至 tsconfig.json 檔案中的 compilerOptions.types。 == WebdriverIO 您可以透過 providerOptions 欄位配置 Vitest 在啟動瀏覽器時應使用的選項:
export default defineConfig({
test: {
browser: {
browser: 'chrome',
providerOptions: {
region: 'eu',
capabilities: {
browserVersion: '27.0',
platformName: 'Windows 10',
},
},
},
},
});若要啟用類型提示,請將 @vitest/browser/providers/webdriverio 新增至 tsconfig.json 檔案中的 compilerOptions.types。 :::
瀏覽器選項類型
Vitest 中的瀏覽器選項取決於所選的提供者。如果您傳遞 --browser 但未在配置檔中指定其名稱,Vitest 將會失敗。可用選項:
webdriverio支援以下瀏覽器:firefoxchromeedgesafari
playwright支援以下瀏覽器:firefoxwebkitchromium
瀏覽器相容性
Vitest 使用 Vite 開發伺服器來執行您的測試,因此我們僅支援 esbuild.target 選項中指定的功能(預設為 esnext)。
預設情況下,Vite 針對支援原生 ES 模組、原生 ESM 動態導入和 import.meta 的瀏覽器。除此之外,我們還利用 BroadcastChannel 在 iframe 之間進行通訊:
- Chrome >=87
- Firefox >=78
- Safari >=15.4
- Edge >=88
執行測試
當您在瀏覽器選項中指定瀏覽器名稱時,Vitest 將預設嘗試使用 preview 執行指定的瀏覽器,然後在那裡執行測試。如果您不想使用 preview,可以透過 browser.provider 選項配置自訂瀏覽器提供者。
若要使用 CLI 指定瀏覽器,請使用 --browser 標誌,後跟瀏覽器名稱,如下所示:
npx vitest --browser=chrome或者您可以使用點記法向 CLI 提供瀏覽器選項:
npx vitest --browser.name=chrome --browser.headless預設情況下,Vitest 將自動開啟瀏覽器 UI 進行開發。您的測試將在中央的 iframe 中執行。您可以透過選擇偏好的尺寸、在測試中呼叫 page.viewport 或在配置中設定預設值來配置視窗(viewport)。
無頭模式
無頭模式(headless)是瀏覽器模式中另一個可用的選項。在無頭模式下,瀏覽器在後台執行,沒有使用者介面,這使得它對於執行自動化測試非常有用。Vitest 中的 headless 選項可以設定為布林值以啟用或禁用無頭模式。
使用無頭模式時,Vitest 不會自動開啟 UI。如果您想繼續使用 UI 但讓測試以無頭模式執行,您可以安裝 @vitest/ui 套件並在執行 Vitest 時傳遞 --ui 標誌。
以下是啟用無頭模式的配置範例:
export default defineConfig({
test: {
browser: {
provider: 'playwright',
enabled: true,
headless: true,
},
},
});您也可以使用 CLI 中的 --browser.headless 標誌設定無頭模式,如下所示:
npx vitest --browser.name=chrome --browser.headless在此情況下,Vitest 將使用 Chrome 瀏覽器以無頭模式執行。
WARNING
無頭模式預設不可用。您需要使用 playwright 或 webdriverio 提供者才能啟用此功能。
範例
Vitest 提供開箱即用的套件,用於渲染多個流行框架的組件:
vitest-browser-vue用於渲染 vue 組件vitest-browser-svelte用於渲染 svelte 組件vitest-browser-react用於渲染 react 組件
如果您的框架未被支援,請隨時建立您自己的套件 - 它只是框架渲染器和 page.elementLocator API 的簡單包裝(wrapper)。我們將在此頁面上新增連結。請確保其名稱以 vitest-browser- 開頭。
除了渲染組件和定位元素之外,您還需要進行斷言(assertion)。Vitest 捆綁了 @testing-library/jest-dom 庫,以提供開箱即用的各種 DOM 斷言。請參閱斷言 API 以了解更多資訊。
import { expect } from 'vitest';
import { page } from '@vitest/browser/context';
// 元素已正確渲染
await expect.element(page.getByText('Hello World')).toBeInTheDocument();Vitest 暴露了一個上下文 API,其中包含一小部分可能對您的測試有用的實用程式。例如,如果您需要進行互動,例如點擊元素或在輸入框中輸入文字,您可以使用 @vitest/browser/context 中的 userEvent。請參閱互動 API 以了解更多資訊。
import { page, userEvent } from '@vitest/browser/context';
await userEvent.fill(page.getByLabelText(/username/i), 'Alice');
// 或者直接使用 locator.fill
await page.getByLabelText(/username/i).fill('Alice');import { render } from 'vitest-browser-vue';
import Component from './Component.vue';
test('properly handles v-model', async () => {
const screen = render(Component);
// 驗證初始狀態。
await expect
.element(screen.getByText('Hi, my name is Alice'))
.toBeInTheDocument();
// 透過查詢相關聯的標籤來取得輸入 DOM 節點。
const usernameInput = screen.getByLabelText(/username/i);
// 在輸入框中輸入名稱。這已驗證輸入框是否正確填寫,
// 無需手動檢查值。
await usernameInput.fill('Bob');
await expect
.element(screen.getByText('Hi, my name is Bob'))
.toBeInTheDocument();
});import { render } from 'vitest-browser-svelte';
import { expect, test } from 'vitest';
import Greeter from './greeter.svelte';
test('greeting appears on click', async () => {
const screen = render(Greeter, { name: 'World' });
const button = screen.getByRole('button');
await button.click();
const greeting = screen.getByText(/hello world/iu);
await expect.element(greeting).toBeInTheDocument();
});import { render } from 'vitest-browser-react';
import Fetch from './fetch';
test('loads and displays greeting', async () => {
// 將 React 元素渲染到 DOM 中
const screen = render(<Fetch url="/greeting" />);
await screen.getByText('Load Greeting').click();
// 如果找不到元素,則等待一段時間再拋出錯誤
const heading = screen.getByRole('heading');
// 驗證警示訊息是否正確
await expect.element(heading).toHaveTextContent('hello there');
await expect.element(screen.getByRole('button')).toBeDisabled();
});Vitest 並非開箱即用支援所有框架,但您可以使用外部工具來執行這些框架的測試。我們也鼓勵社群建立自己的 vitest-browser 包裝器 - 如果您有,請隨時將其新增到上面的範例中。
對於不支援的框架,我們建議使用 testing-library 套件:
@testing-library/preact用於渲染 preact 組件@solidjs/testing-library用於渲染 solid 組件@marko/testing-library用於渲染 marko 組件
WARNING
testing-library 提供了一個套件 @testing-library/user-event。我們不建議直接使用它,因為它模擬事件而不是實際觸發它們 - 相反,請使用從 @vitest/browser/context 導入的 userEvent,它在底層使用 Chrome DevTools Protocol 或 Webdriver(取決於提供者)。
// 基於 @testing-library/preact 範例
// https://testing-library.com/docs/preact-testing-library/example
import { h } from 'preact';
import { page } from '@vitest/browser/context';
import { render } from '@testing-library/preact';
import HiddenMessage from '../hidden-message';
test('shows the children when the checkbox is checked', async () => {
const testMessage = 'Test Message';
const { baseElement } = render(<HiddenMessage>{testMessage}</HiddenMessage>);
const screen = page.elementLocator(baseElement);
// .query() 將返回元素,如果找不到則返回 null。
// .element() 將返回元素,如果找不到則拋出錯誤。
expect(screen.getByText(testMessage).query()).not.toBeInTheDocument();
// 查詢可以接受正規表達式,以使您的選擇器更具彈性,
// 以應對內容調整和更改。
await screen.getByLabelText(/show/i).click();
await expect.element(screen.getByText(testMessage)).toBeInTheDocument();
});// 基於 @testing-library/solid API
// https://testing-library.com/docs/solid-testing-library/api
import { render } from '@testing-library/solid';
it('uses params', async () => {
const App = () => (
<>
<Route
path="/ids/:id"
component={() => (
<p>
Id:
{useParams()?.id}
</p>
)}
/>
<Route path="/" component={() => <p>Start</p>} />
</>
);
const { baseElement } = render(() => <App />, { location: 'ids/1234' });
const screen = page.elementLocator(baseElement);
await expect.screen(screen.getByText('Id: 1234')).toBeInTheDocument();
});// 基於 @testing-library/marko API
// https://testing-library.com/docs/marko-testing-library/api
import { render, screen } from '@marko/testing-library';
import Greeting from './greeting.marko';
test('renders a message', async () => {
const { baseElement } = await render(Greeting, { name: 'Marko' });
const screen = page.elementLocator(baseElement);
await expect.element(screen.getByText(/Marko/)).toBeInTheDocument();
await expect.element(container.firstChild).toMatchInlineSnapshot(`
<h1>Hello, Marko!</h1>
`);
});限制
執行緒阻塞對話框
使用 Vitest 瀏覽器時,請務必注意 alert 或 confirm 等執行緒阻塞(thread-blocking)對話框無法原生使用。這是因為它們會阻塞網頁,導致 Vitest 無法繼續與頁面通訊,進而使執行掛起。
在這種情況下,Vitest 為這些 API 提供了預設的模擬(mock),並帶有預設的回傳值。這確保了即使使用者意外使用同步彈出式 Web API,執行也不會掛起。然而,仍然建議使用者模擬這些 Web API 以獲得更好的體驗。請參閱模擬以了解更多資訊。