В этой статье будем пробовать запустить компонентные тесты Playwright. Мотив простой — e2e тесты с загрузкой всей страницы достаточно медленные. Всевозможные сценарии быстрее бы было протестировать на отдельных компонентах. А основной сценарий взаимодействия с пользователем уже — в e2e. Итак попробуем настроить запуск этих самых компонентных тестов в Playwright.
Содержание
- Пустой проект с поддержкой Playwright
- Установка окружения для компонентных тестов
- Создание и запуск первого теста
- Что еще есть в package.json? Vitest
- Ограничения компонентных тестов Playwright
- Промежуточные выводы
Пустой проект с поддержкой Playwright
Чтобы меньше производить подготовительных действий, попробуем использовать команду быстрого старта для Vue.
nvm use 22
Now using node v22.12.0 (npm v10.9.0)
npm create vue@latest
> npx
> create-vue
┌ Vue.js - The Progressive JavaScript Framework
│
◇ Project name (target directory):
│ vue-playwright-component-test
│
◇ Select features to include in your project: (↑/↓ to navigate, space to select, a to toggle all, enter to confirm)
│ TypeScript, Router (SPA development), Pinia (state management), Vitest (unit testing), End-to-End Testing, ESLint (error prevention), Prettier (code formatting)
│
◇ Select an End-to-End testing framework: (↑/↓ to navigate, enter to confirm)
│ Playwright
│
◇ Select experimental features to include in your project: (↑/↓ to navigate, space to select, a to toggle all, enter to confirm)
│ none
│
◇ Skip all example code and start with a blank Vue project?
│ No
Scaffolding project in /home/igor/projects/vue-playwright-component-test...
│
└ Done. Now run:
cd vue-playwright-component-test
npm install
npm run format
npm run dev
| Optional: Initialize Git in your project directory with:
git init && git add -A && git commit -m "initial commit"
Здесь, как можно видеть, выбран Playwright в качестве платформы для e2e-тестов.
Установка окружения для компонентных тестов
Теперь пойдем по статье из документации для настройки компонентных тестов.
npm init playwright@latest -- --ct
Need to install the following packages:
create-playwright@1.17.139
Ok to proceed? (y)
> vue-playwright-component-test@0.0.0 npx
> create-playwright --ct
Getting started with writing end-to-end tests with Playwright:
Initializing project in '.'
✔ Which framework do you use? (experimental) · vue
✔ Install Playwright browsers (can be done manually via 'npx playwright install')? (Y/n) · false
✔ Install Playwright operating system dependencies (requires sudo / root - can be done manually via 'sudo npx playwright install-deps')? (y/N) · false
Installing Playwright Component Testing (npm install --save-dev @playwright/experimental-ct-vue)…
added 10 packages, and audited 442 packages in 9s
110 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
Writing playwright-ct.config.ts.
Writing playwright/index.html.
Writing playwright/index.ts.
Writing package.json.
✔ Success! Created a Playwright Test project at /home/igor/projects/vue-playwright-component-test
Inside that directory, you can run several commands:
npm run test-ct
Runs the component tests.
npm run test-ct -- --project=chromium
Runs the tests only on Desktop Chrome.
npm run test-ct App.test.ts
Runs the tests in the specific file.
npm run test-ct -- --debug
Runs the tests in debug mode.
We suggest that you begin by typing:
npm run test-ct
Visit https://playwright.dev/docs/intro for more information. ✨
Happy hacking!
Этот шаг создаст файл playwright/index.html, в который будет загружаться тестируемый компонент вместо элемента c id=root.
<html lang="en">
<body>
<div id="root"></div>
<script type="module" src="./index.ts"></script>
</body>
</html>
В нем есть ссылка на файл playwright/index.ts. В него можно будет добавить некоторый дополнительный код, если нужно.
Создание и запуск первого теста
Создадим файл App.spec.ts с первым тестом. Код теста берем прямо со страницы документации.
import { test, expect } from '@playwright/experimental-ct-vue';
import App from './App.vue';
test('should work', async ({ mount }) => {
const component = await mount(App);
await expect(component).toContainText('Learn Vue');
});
Пробуем запустить и получаем ошибку:
npm run test-ct App.spec.ts
> vue-playwright-component-test@0.0.0 test-ct
> playwright test -c playwright-ct.config.ts App.spec.ts
Running 3 tests using 3 workers
vite v6.4.1 building for production...
✓ 10 modules transformed.
Error: [vite]: Rollup failed to resolve import "@/assets/logo.svg" from "/home/igor/projects/vue-playwright-component-test/src/App.vue".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
`build.rollupOptions.external`
at viteLog (/home/igor/projects/vue-playwright-component-test/node_modules/@playwright/experimental-ct-core/node_modules/vite/dist/node/chunks/dep-D4NMHUTW.js:46374:15)
at onRollupLog (/home/igor/projects/vue-playwright-component-test/node_modules/@playwright/experimental-ct-core/node_modules/vite/dist/node/chunks/dep-D4NMHUTW.js:46424:5)
at onLog (/home/igor/projects/vue-playwright-component-test/node_modules/@playwright/experimental-ct-core/node_modules/vite/dist/node/chunks/dep-D4NMHUTW.js:46072:7)
at /home/igor/projects/vue-playwright-component-test/node_modules/rollup/dist/es/shared/node-entry.js:20961:32
at Object.logger (/home/igor/projects/vue-playwright-component-test/node_modules/rollup/dist/es/shared/node-entry.js:22848:9)
at ModuleLoader.handleInvalidResolvedId (/home/igor/projects/vue-playwright-component-test/node_modules/rollup/dist/es/shared/node-entry.js:21592:26)
at /home/igor/projects/vue-playwright-component-test/node_modules/rollup/dist/es/shared/node-entry.js:21550:26
3 did not run
transforming (13) ../node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js
To open last HTML report run:
npx playwright show-report
Чтобы пока не тратить на это время удалим подключение логотипа через @
<img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" />
Теперь снова запустим тест на выполнение.
npm run test-ct App.spec.ts
> vue-playwright-component-test@0.0.0 test-ct
> playwright test -c playwright-ct.config.ts App.spec.ts
Running 3 tests using 3 workers
vite v6.4.1 building for production...
✓ 33 modules transformed.
.cache/index.html 0.32 kB │ gzip: 0.24 kB
.cache/assets/App-BhWmzu7w.css 1.38 kB │ gzip: 0.50 kB
.cache/assets/App-zk5qgemQ.js 97.17 kB │ gzip: 24.84 kB │ map: 222.21 kB
.cache/assets/index-DpUjl_lK.js 580.63 kB │ gzip: 138.89 kB │ map: 998.16 kB
1) [chromium] › src/App.spec.ts:4:1 › should work ────────────────────────────────────────────────
Error: expect(locator).toContainText(expected) failed
Locator: locator('#root').locator('internal:control=component')
Expected substring: "Learn Vue"
Received string: "You did it! You’ve successfully created a project with Vite + Vue 3. What's next? "
Timeout: 5000ms
Call log:
- Expect "toContainText" with timeout 5000ms
- waiting for locator('#root').locator('internal:control=component')
9 × locator resolved to <header data-v-3de9d757="">…</header>
- unexpected value "You did it! You’ve successfully created a project with Vite + Vue 3. What's next? "
4 | test('should work', async ({ mount }) => {
5 | const component = await mount(App);
> 6 | await expect(component).toContainText('Learn Vue');
| ^
7 | });
at /home/igor/projects/vue-playwright-component-test/src/App.spec.ts:6:27
Error Context: test-results/src-App-should-work-chromium/error-context.md
Теперь тест запустился. Тест провальный. Мы ожидали найти строку «Learn Vue», но на странице ее не оказалось. Вместо нее есть строка «You did it!». Поменяем в тесте строку и запустим его снова.
npm run test-ct App.spec.ts
> vue-playwright-component-test@0.0.0 test-ct
> playwright test -c playwright-ct.config.ts App.spec.ts
Running 3 tests using 3 workers
3 passed (4.3s)
To open last HTML report run:
npx playwright show-report
Теперь тест прошел. Три раза, так как в конфигурационном файле playwright-ct.config.ts указано 3 браузера в секции projects.
Также можно запустить тесты в UI-режиме:
npm run test-ct App.spec.ts -- --ui
Что еще есть в package.json? Vitest
Посмотрим на содержимое секции scripts в package.json.
"scripts": {
"dev": "vite",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"test:unit": "vitest",
"test:e2e": "playwright test",
"build-only": "vite build",
"type-check": "vue-tsc --build",
"lint": "eslint . --fix --cache",
"format": "prettier --write src/",
"test-ct": "playwright test -c playwright-ct.config.ts"
}
Кроме команды test-ct, которую мы использовали, здесь есть test:e2e для запуска Playwright в привычном e2e режиме. А также test:unit, которая запускает Vitest. Это будет предметом следующих статей. Но сейчас, все же, попробуем запустить ее.
npm run test:unit
> vue-playwright-component-test@0.0.0 test:unit
> vitest
DEV v3.2.4 /home/igor/projects/vue-playwright-component-test
✓ src/components/__tests__/HelloWorld.spec.ts (1 test) 20ms
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Failed Suites 1 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
FAIL src/App.spec.ts [ src/App.spec.ts ]
Error: Playwright Test did not expect test() to be called here.
Most common reasons include:
- You are calling test() in a configuration file.
- You are calling test() in a file that is imported by the configuration file.
- You have two different versions of @playwright/test. This usually happens
when one of the dependencies in your package.json depends on @playwright/test.
❯ TestTypeImpl._currentSuite node_modules/playwright/lib/common/testType.js:75:13
❯ TestTypeImpl._createTest node_modules/playwright/lib/common/testType.js:88:24
❯ node_modules/playwright/lib/transform/transform.js:275:12
❯ src/App.spec.ts:4:1
2| import App from './App.vue';
3|
4| test('should work', async ({ mount }) => {
| ^
5| const component = await mount(App);
6| await expect(component).toContainText('You did it!');
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯
Test Files 1 failed | 1 passed (2)
Tests 1 passed (1)
Start at 20:13:09
Duration 2.63s (transform 134ms, setup 0ms, collect 198ms, tests 20ms, environment 933ms, prepare 138ms)
FAIL Tests failed. Watching for file changes...
press h to show help, press q to quit
Cancelling test run. Press CTRL+c again to exit forcefully.
Здесь мы видим как успешно выполнился код src/components/__tests__/HelloWorld.spec.ts, но затем получаем ошибку на src/App.spec.ts. Всё понятно. Мы должны использовать такое именование для тестов Playwright, чтобы их не захватывал Vitest.
В файле playwright-ct.config.ts изменим настройку testMatch, а файл теста переименуем в src/App.test.ts:
import { defineConfig, devices } from '@playwright/experimental-ct-vue';
/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: './',
testMatch: /.*\.test\.(ts|tsx)/,
/* The base directory, relative to the config file, for snapshot files created with toMatchSnapshot and toHaveScreenshot. */
snapshotDir: './__snapshots__',
/* Maximum time one test can run for. */
timeout: 10 * 1000,
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html',
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
/* Port to use for Playwright component endpoint. */
ctPort: 3100,
},
/* Configure projects for major browsers */
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
],
});
Теперь Vitest запускается без ошибок и обращается только к своим файлам:
npm run test:unit
> vue-playwright-component-test@0.0.0 test:unit
> vitest
DEV v3.2.4 /home/igor/projects/vue-playwright-component-test
✓ src/components/__tests__/HelloWorld.spec.ts (1 test) 17ms
✓ HelloWorld > renders properly 16ms
Test Files 1 passed (1)
Tests 1 passed (1)
Start at 20:17:47
Duration 825ms (transform 75ms, setup 0ms, collect 164ms, tests 17ms, environment 441ms, prepare 60ms)
PASS Waiting for file changes...
press h to show help, press q to quit
А Playwright работает со своим тестом:
npm run test-ct
> vue-playwright-component-test@0.0.0 test-ct
> playwright test -c playwright-ct.config.ts
Running 3 tests using 3 workers
3 passed (7.6s)
To open last HTML report run:
npx playwright show-report
Интересно, что компонентные тесты Playwright производят сборку приложения в playwright/.cache. При запуске Vitest же похожих сообщений не выводится.
Ограничения компонентных тестов Playwright
В официальной документации возможность компонентного тестирования помечена как экспериментальная (experimental).
Также там написано, что когда Playwright Test используется для тестирования веб-компонентов, тесты выполняются в Node.js, а сами компоненты работают в реальном браузере. Это накладывает ряд ограничений.
Основное из которых заключается в следующем. Нельзя передавать сложные «живые» объекты в компонент. Можно передавать только простые JavaScript-объекты и встроенные типы (строки, числа, даты и т.п.). В общем, только то, что сериализуемо.
Так это работает «под капотом»:
- После запуска тестов Playwright собирает список нужных компонентов.
- Создаёт бандл, включающий эти компоненты, и обслуживает его через локальный статический веб-сервер.
- При вызове
mount()Playwright открывает служебную страницу /playwright/index.html этого бандла и указывает ей, какой компонент нужно отрендерить. - Все необходимое превращается в события, которые передаются в среду Node.js, чтобы тест мог их проверять.
- Для сборки и обслуживания бандла Playwright использует Vite.
Промежуточные выводы
Playwright, как и Cypress имеет возможность создавать компонентные тесты. Но функция помечена как экспериментальная и имеет ряд ограничений. Есть предчувствие, что для компонентов работающих с Pinia и Vue-Router будут сложности. А также опасение, что компоненты на базе таких UI-фреймворков, как Vuetify, тестировать получиться не без «танцев с бубном».
Интересно, что раньше Cypress и Playwright вообще не связывали с компонентными тестами. Более известным инструментом для этого был Vitest. Интересно было бы посмотреть на работу и этого решения.