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

简介

为什么选择浏览器模式

浏览器模式

配置

浏览器配置

配置 Playwright

配置 WebdriverIO

API

Context API

交互 API

定位器

断言 API

命令 API

指南

多实例设置

配置参考

测试 API 参考

高级 API

页面导航

浏览器模式 实验性 ​

本页面介绍了 Vitest API 中的实验性浏览器模式功能。此功能允许您在浏览器环境中原生运行测试,从而能够访问 window 和 document 等浏览器全局对象。该功能目前仍在开发中,未来的 API 可能会有所变化。

TIP

如果您正在寻找 expect、vi 或任何通用 API(如测试项目或类型测试)的文档,请参阅《入门指南》。

Vitest UIVitest UI

安装 ​

为了简化设置,您可以使用 vitest init browser 命令安装所需的依赖项并创建浏览器配置。

bash
npx vitest init browser
bash
yarn exec vitest init browser
bash
pnpx vitest init browser
bash
bunx vitest init browser

手动安装 ​

您也可以手动安装这些包。默认情况下,浏览器模式在本地运行测试时不需要任何额外的端到端(E2E)提供者,因为它会复用您现有的浏览器。

bash
npm install -D vitest @vitest/browser
bash
yarn add -D vitest @vitest/browser
bash
pnpm add -D vitest @vitest/browser
bash
bun add -D vitest @vitest/browser

WARNING

然而,要在持续集成(CI)环境中运行测试,您需要安装 playwright 或 webdriverio。我们还建议在本地测试时切换到其中一个提供者,而不是使用默认的 preview 提供者,因为 preview 依赖于模拟事件,而 Playwright/WebdriverIO 使用 Chrome DevTools Protocol。

如果您尚未接触这些工具,建议从 Playwright 开始,因为它支持并行执行,这能让您的测试运行得更快。此外,Playwright 使用 Chrome DevTools Protocol,通常比 WebDriver 更快。

::: tabs key:provider == Playwright Playwright 是一个用于 Web 测试和自动化的框架。

bash
npm install -D vitest @vitest/browser playwright
bash
yarn add -D vitest @vitest/browser playwright
bash
pnpm add -D vitest @vitest/browser playwright
bash
bun add -D vitest @vitest/browser playwright

== WebdriverIO

WebdriverIO 允许您使用 WebDriver 协议在本地运行测试。

bash
npm install -D vitest @vitest/browser webdriverio
bash
yarn add -D vitest @vitest/browser webdriverio
bash
pnpm add -D vitest @vitest/browser webdriverio
bash
bun add -D vitest @vitest/browser webdriverio

配置 ​

要在 Vitest 配置中激活浏览器模式,请将 browser.enabled 字段设置为 true。以下是使用 browser 字段的配置示例:

ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
  test: {
    browser: {
      provider: 'playwright', // 或 'webdriverio'
      enabled: true,
      // 至少需要一个实例
      instances: [{ browser: 'chromium' }],
    },
  },
});

INFO

Vitest 分配端口 63315 以避免与开发服务器冲突,从而允许您并行运行两者。您可以使用 browser.api 选项更改此设置。

自 Vitest 2.1.5 起,CLI 不再自动打印 Vite URL。在监听模式下运行时,您可以按“b”打印 URL。

如果您之前没有使用过 Vite,请确保已安装并配置了您所用框架的 Vite 插件。某些框架可能需要额外配置才能正常工作,请查阅其 Vite 相关文档以确认。

ts
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  test: {
    browser: {
      enabled: true,
      provider: 'playwright',
      instances: [{ browser: 'chromium' }],
    },
  },
});
ts
import { defineConfig } from 'vitest/config';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
  plugins: [vue()],
  test: {
    browser: {
      enabled: true,
      provider: 'playwright',
      instances: [{ browser: 'chromium' }],
    },
  },
});
ts
import { defineConfig } from 'vitest/config';
import { svelte } from '@sveltejs/vite-plugin-svelte';

export default defineConfig({
  plugins: [svelte()],
  test: {
    browser: {
      enabled: true,
      provider: 'playwright',
      instances: [{ browser: 'chromium' }],
    },
  },
});
ts
import { defineConfig } from 'vitest/config';
import solidPlugin from 'vite-plugin-solid';

export default defineConfig({
  plugins: [solidPlugin()],
  test: {
    browser: {
      enabled: true,
      provider: 'playwright',
      instances: [{ browser: 'chromium' }],
    },
  },
});
ts
import { defineConfig } from 'vitest/config';
import marko from '@marko/vite';

export default defineConfig({
  plugins: [marko()],
  test: {
    browser: {
      enabled: true,
      provider: 'playwright',
      instances: [{ browser: 'chromium' }],
    },
  },
});

如果您需要使用基于 Node 的运行器运行某些测试,可以定义一个 projects 选项,其中包含针对不同测试策略的单独配置:

ts
import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    projects: [
      {
        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,
            instances: [{ browser: 'chromium' }],
          },
        },
      },
    ],
  },
});

浏览器选项类型 ​

Vitest 中的浏览器选项取决于所选的提供者。如果您传递 --browser 但未在配置文件中指定其名称,Vitest 将会失败。可用选项:

  • webdriverio 支持以下浏览器:
    • firefox
    • chrome
    • edge
    • safari
  • playwright 支持以下浏览器:
    • firefox
    • webkit
    • chromium

TypeScript ​

默认情况下,TypeScript 不识别提供者选项和额外的 expect 属性。如果您不使用任何提供者,请确保在您的测试、设置文件 或 配置文件 中引用 @vitest/browser/matchers,以获取额外的 expect 定义。如果您使用自定义提供者,请确保将 @vitest/browser/providers/playwright 或 @vitest/browser/providers/webdriverio 添加到同一文件中,以便 TypeScript 可以获取自定义选项的定义:

ts
/// <reference types="@vitest/browser/matchers" />
ts
/// <reference types="@vitest/browser/providers/playwright" />
ts
/// <reference types="@vitest/browser/providers/webdriverio" />

或者,您也可以将它们添加到 tsconfig.json 文件中的 compilerOptions.types 字段。请注意,在此字段中进行任何指定将禁用 @types/* 包的自动加载。

json
{
  "compilerOptions": {
    "types": ["@vitest/browser/matchers"]
  }
}
json
{
  "compilerOptions": {
    "types": ["@vitest/browser/providers/playwright"]
  }
}
json
{
  "compilerOptions": {
    "types": ["@vitest/browser/providers/webdriverio"]
  }
}

浏览器兼容性 ​

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 标志后跟浏览器名称,如下所示:

sh
npx vitest --browser=chromium

或者您可以使用点表示法向 CLI 传递浏览器选项:

sh
npx vitest --browser.headless

WARNING

自 Vitest 3.2 起,如果您在配置中没有 browser 选项但指定了 --browser 标志,Vitest 将会失败,因为它无法假定该配置是针对浏览器测试而非 Node.js 测试的。

默认情况下,Vitest 会自动打开浏览器 UI 以供开发使用。您的测试将在中央的 iframe 中运行。您可以通过选择所需的尺寸、在测试中调用 page.viewport 或在配置中设置默认值来配置视口。

无头模式 ​

无头模式是浏览器模式下的一个可用选项。在无头模式下,浏览器在后台运行,没有用户界面,这使其非常适合运行自动化测试。Vitest 中的无头选项可以设置为布尔值来启用或禁用无头模式。

在无头模式下,Vitest 不会自动打开 UI。如果您想继续使用 UI 但仍希望测试以无头模式运行,您可以安装 @vitest/ui 包并在运行 Vitest 时传递 --ui 标志。

以下是启用无头模式的配置示例:

ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
  test: {
    browser: {
      provider: 'playwright',
      enabled: true,
      headless: true,
    },
  },
});

您还可以使用 CLI 中的 --browser.headless 标志设置无头模式,如下所示:

sh
npx vitest --browser.headless

在这种情况下,Vitest 将使用 Chrome 浏览器以无头模式运行。

WARNING

无头模式默认不可用。您需要使用 playwright 或 webdriverio 提供者才能启用此功能。

示例 ​

默认情况下,您不需要任何外部包即可在浏览器模式下工作:

js
import { expect, test } from 'vitest';
import { page } from '@vitest/browser/context';
import { render } from './my-render-function.js';

test('properly handles form inputs', async () => {
  render(); // 挂载 DOM 元素

  // 断言初始状态。
  await expect
    .element(page.getByText('Hi, my name is Alice'))
    .toBeInTheDocument();

  // 通过查询关联的标签获取输入 DOM 节点。
  const usernameInput = page.getByLabelText(/username/i);

  // 将名称输入到输入框中。这已验证输入是否正确填充,
  // 无需手动检查值。
  await usernameInput.fill('Bob');

  await expect
    .element(page.getByText('Hi, my name is Bob'))
    .toBeInTheDocument();
});

然而,Vitest 还提供了开箱即用的组件渲染包,用于多个流行框架:

  • vitest-browser-vue 用于渲染 Vue 组件
  • vitest-browser-svelte 用于渲染 Svelte 组件
  • vitest-browser-react 用于渲染 React 组件

社区包可用于其他框架:

  • vitest-browser-lit 用于渲染 Lit 组件
  • vitest-browser-preact 用于渲染 Preact 组件

如果您的框架未被涵盖,请随意创建您自己的包——它仅仅是框架渲染器和 page.elementLocator API 的简单包装。我们将在本页添加其链接。请确保其名称以 vitest-browser- 开头。

除了渲染组件和定位元素,您还需要进行断言。Vitest 复刻了 @testing-library/jest-dom 库,以提供开箱即用的各种 DOM 断言。请阅读 断言 API 了解更多信息。

ts
import { expect } from 'vitest';
import { page } from '@vitest/browser/context';
// 元素渲染正确
await expect.element(page.getByText('Hello World')).toBeInTheDocument();

Vitest 提供了一个 Context API,其中包含少量可能对您的测试有用的实用程序。例如,如果您需要执行交互操作,例如单击元素或在输入框中键入文本,您可以使用 @vitest/browser/context 中的 userEvent。请阅读 交互 API 了解更多信息。

ts
import { page, userEvent } from '@vitest/browser/context';
await userEvent.fill(page.getByLabelText(/username/i), 'Alice');
// 或者直接使用 locator.fill
await page.getByLabelText(/username/i).fill('Alice');
ts
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();
});
ts
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();
});
tsx
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();
});
ts
import { render } from 'vitest-browser-lit';
import { html } from 'lit';
import './greeter-button';

test('greeting appears on click', async () => {
  const screen = render(html`<greeter-button name="World"></greeter-button>`);

  const button = screen.getByRole('button');
  await button.click();
  const greeting = screen.getByText(/hello world/iu);

  await expect.element(greeting).toBeInTheDocument();
});
tsx
import { render } from 'vitest-browser-preact';
import { createElement } from 'preact';
import Greeting from '.Greeting';

test('greeting appears on click', async () => {
  const screen = render(<Greeting />);

  const button = screen.getByRole('button');
  await button.click();
  const greeting = screen.getByText(/hello world/iu);

  await expect.element(greeting).toBeInTheDocument();
});

Vitest 并非开箱即用地支持所有框架,但您可以使用外部工具来运行这些框架的测试。我们也鼓励社区创建自己的 vitest-browser 包装器——如果您有,欢迎将其添加到上述示例中。

对于不支持的框架,建议使用 testing-library 包:

  • @solidjs/testing-library 用于渲染 Solid 组件
  • @marko/testing-library 用于渲染 Marko 组件

您还可以在 browser-examples 仓库中查看更多示例。

WARNING

testing-library 提供了一个名为 @testing-library/user-event 的包。我们不建议直接使用它,因为它模拟事件而非实际触发——相反,请使用从 @vitest/browser/context 导入的 userEvent,它在底层使用 Chrome DevTools Protocol 或 Webdriver(取决于提供者)。

tsx
// 基于 @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();
});
ts
// 基于 @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();
  expect(container.firstChild).toMatchInlineSnapshot(`
    <h1>Hello, Marko!</h1>
  `);
});

限制 ​

线程阻塞对话框 ​

使用 Vitest 浏览器时,请注意 alert 或 confirm 等线程阻塞对话框无法原生使用。这是因为它们会阻塞网页,这意味着 Vitest 无法继续与页面通信,从而导致执行挂起。

针对这种情况,Vitest 为这些 API 提供了带有默认返回值的模拟。这可以确保如果用户意外使用同步弹出式 Web API,执行不会被挂起。但仍建议用户模拟这些 Web API 以优化体验。请阅读 模拟 了解更多信息。

Pager
上一页为什么选择浏览器模式
下一页浏览器配置

基于 MIT 许可证 发布。

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

https://vitest.dev/guide/

基于 MIT 许可证 发布。

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