Тестирование с playwright. Компонентный тест

В этой статье будем пробовать запустить компонентные тесты Playwright. Мотив простой — e2e тесты с загрузкой всей страницы достаточно медленные. Всевозможные сценарии быстрее бы было протестировать на отдельных компонентах. А основной сценарий взаимодействия с пользователем уже — в e2e. Итак попробуем настроить запуск этих самых компонентных тестов в 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-объекты и встроенные типы (строки, числа, даты и т.п.). В общем, только то, что сериализуемо.

Так это работает «под капотом»:

  1. После запуска тестов Playwright собирает список нужных компонентов.
  2. Создаёт бандл, включающий эти компоненты, и обслуживает его через локальный статический веб-сервер.
  3. При вызове mount() Playwright открывает служебную страницу /playwright/index.html этого бандла и указывает ей, какой компонент нужно отрендерить.
  4. Все необходимое превращается в события, которые передаются в среду Node.js, чтобы тест мог их проверять.
  5. Для сборки и обслуживания бандла Playwright использует Vite.

Промежуточные выводы

Playwright, как и Cypress имеет возможность создавать компонентные тесты. Но функция помечена как экспериментальная и имеет ряд ограничений. Есть предчувствие, что для компонентов работающих с Pinia и Vue-Router будут сложности. А также опасение, что компоненты на базе таких UI-фреймворков, как Vuetify, тестировать получиться не без «танцев с бубном».

Интересно, что раньше Cypress и Playwright вообще не связывали с компонентными тестами. Более известным инструментом для этого был Vitest. Интересно было бы посмотреть на работу и этого решения.

0 0 голоса
Рейтинг статьи
guest
0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии