Режим браузера Экспериментальный
Эта страница содержит информацию об экспериментальной функции режима браузера в 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 по умолчанию, поскольку он основан на симуляции событий, а не на использовании Chrome DevTools Protocol.
Если вы ещё не используете один из этих инструментов, мы рекомендуем начать с Playwright, потому что он поддерживает параллельное выполнение, что ускоряет ваши тесты. Кроме того, Chrome DevTools Protocol, используемый Playwright, обычно быстрее, чем WebDriver.
::: tabs key:provider == Playwright Playwright — это фреймворк для веб-тестирования и автоматизации.
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.
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 или установить поле browser.enabled в true в вашем файле конфигурации Vitest. Вот пример конфигурации с использованием поля browser:
export default defineConfig({
test: {
browser: {
provider: 'playwright', // или 'webdriverio'
enabled: true,
name: 'chromium', // имя браузера обязательно
},
},
});INFO
Vitest использует порт 63315, чтобы избежать конфликтов с сервером разработки, что позволяет запускать их оба параллельно. Вы можете изменить это с помощью опции browser.api.
Начиная с Vitest 2.1.5, CLI больше не выводит URL Vite автоматически. Вы можете нажать "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.js, вы можете определить файл рабочей области с отдельными конфигурациями для различных стратегий тестирования:
// 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 Вы можете настроить, как Vitest запускает браузер и создает контекст страницы через поле providerOptions:
export default defineConfig({
test: {
browser: {
providerOptions: {
launch: {
devtools: true,
},
context: {
geolocation: {
latitude: 45,
longitude: -30,
},
reducedMotion: 'reduce',
},
},
},
},
});Для получения подсказок по типам добавьте @vitest/browser/providers/playwright в compilerOptions.types в вашем файле tsconfig.json. == WebdriverIO Вы можете настроить, какие опции Vitest должен использовать при запуске браузера через поле providerOptions:
export default defineConfig({
test: {
browser: {
browser: 'chrome',
providerOptions: {
region: 'eu',
capabilities: {
browserVersion: '27.0',
platformName: 'Windows 10',
},
},
},
},
});Для получения подсказок по типам добавьте @vitest/browser/providers/webdriverio в compilerOptions.types в вашем файле tsconfig.json. :::
Типы опций браузера
Опция браузера в Vitest зависит от провайдера. Vitest выдаст ошибку, если вы передадите --browser и не укажете его имя в файле конфигурации. Доступные опции:
webdriverioподдерживает следующие браузеры:firefoxchromeedgesafari
playwrightподдерживает следующие браузеры:firefoxwebkitchromium
Совместимость с браузерами
Vitest использует сервер разработки Vite для запуска ваших тестов, поэтому мы поддерживаем только функции, определенные в опции esbuild.target (esnext по умолчанию).
По умолчанию Vite ориентирован на браузеры, которые поддерживают нативные ES Modules, нативный динамический импорт ESM и import.meta. Кроме того, мы используем BroadcastChannel для связи между iframe:
- Chrome >=87
- Firefox >=78
- Safari >=15.4
- Edge >=88
Запуск тестов
Когда вы указываете имя браузера в опции browser, Vitest по умолчанию попытается запустить указанный браузер с помощью preview, а затем выполнит тесты в нём. Если вы не хотите использовать preview, вы можете настроить пользовательский провайдер браузера с помощью опции browser.provider.
Чтобы указать браузер с помощью CLI, используйте флаг --browser с именем браузера, например:
npx vitest --browser=chromeИли вы можете предоставить опции браузера в CLI с помощью точечной нотации:
npx vitest --browser.name=chrome --browser.headlessПо умолчанию Vitest автоматически откроет пользовательский интерфейс браузера для разработки. Ваши тесты будут запускаться внутри iframe в центре. Вы можете настроить область просмотра, выбрав предпочтительные размеры, вызвав page.viewport внутри теста или установив значения по умолчанию в конфигурации.
Безголовый режим (Headless)
Безголовый режим — это дополнительная опция, доступная в режиме браузера. В безголовом режиме браузер работает в фоновом режиме без пользовательского интерфейса, что делает его полезным для запуска автоматизированных тестов. Опция headless в Vitest может быть установлена в логическое значение для включения или отключения безголового режима.
При использовании безголового режима Vitest не будет автоматически открывать пользовательский интерфейс. Если вы хотите продолжать использовать пользовательский интерфейс, но запускать тесты в безголовом режиме, вы можете установить пакет @vitest/ui и передать флаг --ui при запуске Vitest.
Вот пример конфигурации, включающей безголовый режим:
export default defineConfig({
test: {
browser: {
provider: 'playwright',
enabled: true,
headless: true,
},
},
});Вы также можете установить безголовый режим с помощью флага --browser.headless в CLI, например:
npx vitest --browser.name=chrome --browser.headlessВ этом случае Vitest будет работать в безголовом режиме с использованием браузера Chrome.
WARNING
Безголовый режим недоступен по умолчанию. Для включения этой функции необходимо использовать провайдеры playwright или webdriverio.
Примеры
Vitest предоставляет пакеты для рендеринга компонентов для нескольких популярных фреймворков по умолчанию:
vitest-browser-vueдля рендеринга компонентов vuevitest-browser-svelteдля рендеринга компонентов sveltevitest-browser-reactдля рендеринга компонентов react
Если ваш фреймворк не представлен, вы можете создать свой собственный пакет — это простая обертка вокруг рендерера фреймворка и API page.elementLocator. Мы добавим ссылку на него на этой странице. Убедитесь, что его имя начинается с vitest-browser-.
Помимо рендеринга компонентов и поиска элементов, вам также потребуется выполнять утверждения. Vitest включает библиотеку @testing-library/jest-dom для предоставления широкого спектра утверждений DOM по умолчанию. Подробнее читайте в Assertions API.
import { expect } from 'vitest';
import { page } from '@vitest/browser/context';
// элемент отображается правильно
await expect.element(page.getByText('Hello World')).toBeInTheDocument();Vitest предоставляет Context API с небольшим набором утилит, которые могут пригодиться вам в тестах. Например, если вам нужно выполнить взаимодействие, такое как нажатие на элемент или ввод текста в поле ввода, вы можете использовать userEvent из @vitest/browser/context. Подробнее читайте в Interactivity 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. Мы не рекомендуем использовать его напрямую, потому что он имитирует события вместо их фактического запуска — вместо этого используйте userEvent, импортированный из @vitest/browser/context, который использует 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();
});// на основе API @testing-library/solid
// 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();
});// на основе API @testing-library/marko
// 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 Browser важно отметить, что диалоги, блокирующие поток, такие как alert или confirm, не могут быть использованы в нативном режиме. Это связано с тем, что они блокируют веб-страницу, что означает, что Vitest не может продолжать связь со страницей, приводя к зависанию выполнения.
В таких ситуациях Vitest предоставляет стандартные моки с заранее определёнными возвращаемыми значениями для этих API. Это гарантирует, что случайное использование синхронных API для всплывающих окон не приведёт к зависанию выполнения. Однако всё же рекомендуется пользователям мокировать эти веб-API для улучшения взаимодействия. Подробнее читайте в разделе Мокирование.