E2E-тестування за допомогою Playwright та Cucumber
Добрий день, DOU комʼюніті! Мене звати Микита Парфенчук, я Senior Software Engineer в SoftServe. Сьогодні хочу поділитися своїм досвідом налаштування та використання фреймворку для вебтестування Playwright разом з таким інструментом, як Cucumber.
На проєкті, де я працюю, дуже прискіпливо ставляться до E2E-тестування: для нас важливо покрити тестами якомога більше різних use case нашого вебсервісу, мати змогу автоматично їх виконувати, налаштовувати, бачити результат та запускати їх у різних браузерах. Тому проаналізувавши всі інструменти для вебтестування ми вирішили, що саме Playwright в поєднанні з Cucumber — це саме те, що нам треба. А зараз більш детально розглянемо кожен з них.
Чому саме Playwright та Cucumber
Playwright — це фреймворк для вебтестування та автоматизації, який підтримує такі механізмі візуалізації, як Chromium, Firefox і WebKit та надає API для роботи з ними. Це означає, що можна запустити тести одразу в декількох веббраузерах, не турбуючись про відмінності в поведінці. Також Playwright підтримує:
— основні мови програмування;
— емуляцію мобільних браузерів;
— підключення через Chrome DevTools Protocol;
— кросплатформеність;
— налаштування контексту браузера;
— комплексний API, який дозволяє різноманітно взаємодіяти з елементами сторінки;
— потужні інструменти для інспектування тестів.
Cucumber — це популярний інструмент тестування, який використовує Behavior-Driven Development (BDD) підхід до тестування та Gherkin-синтаксис для написання тестів, що дозволяє вказувати очікувану поведінку простою та зрозумілою мовою. Він також підтримує написання тестів за допомогою JavaScript та TypeScript.
Створюємо проєкт
Що ж, перейдімо до практики та перевіримо можливості даних інструментів на прикладі. Для початку створимо новий проєкт. Використаємо npm-менеджер пакетів:
mkdir e2e-testing && cd e2e-testing
npm init -y
Далі встановимо Playwright:
npm i -D @playwright/test
# install supported browsers
npx playwright install
А також Cucumber.js:
npm i -D @cucumber/cucumber
Щоб проєкт підтримував TypeScript, встановимо такі пакети:
npm i -D ts-node @types/node
Налаштування Playwright та Cucumber
Почнемо з того, що налаштуємо середовище тестування, у якому ми будемо писати E2E-тести. Створим файл world.ts
, де визначимо основні змінні, які будуть використовуватися в кожному сценарії.
import {
World,
setDefaultTimeout,
setWorldConstructor,
IWorldOptions,
} from "@cucumber/cucumber";
import { Browser, BrowserContext, Page } from "@playwright/test"; export default class ExampleWorld extends World {
browser!: Browser;
browserContext!: BrowserContext;
page!: Page; constructor(options: IWorldOptions) {
super(options);
}
} setDefaultTimeout(10 * 1000); // increase timeout for some cases
setWorldConstructor(ExampleWorld);
Далі створимо хуки в файлі hooks.ts
, які будуть виконуватися до та після кожного сценарію. Перед кожним тестом буде створюватися нова сторінка браузера, а сам процес виконання буде записуватися та зберігатися в папці videos/
. Також у випадку виникненні помилки буде зроблений скриншот сторінки та збережений в папці screenshots/errors/
. Усе це допомагатиме нам бачити результат тестів та відстежувати помилки. Наприкінці кожного сценарію браузер закривається.
import { Before, After, AfterStep, Status } from "@cucumber/cucumber";
import { Browser, chromium, devices, firefox, webkit } from "@playwright/test"; import ExampleWorld from "./world"; const createBrowser = (browserType: string): Promise<Browser> => {
switch (browserType) {
case "chromium":
return chromium.launch();
case "firefox":
return firefox.launch();
case "webkit":
return webkit.launch();
default:
throw new Error(`Unknown browser type: ${browserType}`);
}
}; Before<ExampleWorld>(async function (this, scenario) {
const targetDevice = devices[this.parameters.device];
if (!targetDevice) {
throw new Error(`Unknown device type: ${this.parameters.device}`);
}
this.browser = await createBrowser(targetDevice.defaultBrowserType);
this.browserContext = await this.browser.newContext({
...targetDevice,
recordVideo: { dir: `videos/${scenario.pickle.name}` },
});
this.page = await this.browserContext.newPage();
}); AfterStep<ExampleWorld>(async function ({ result, pickle }) {
if (result.status === Status.FAILED) {
await this.page.screenshot({
path: `screenshots/errors/${pickle.name}.png`,
});
}
}); After<ExampleWorld>(async function (this) {
await this.page.close();
await this.browserContext.close();
await this.browser.close();
});
Потім створимо файл cucumber.js
з налаштуваннями для виконання майбутніх тестів. Тут ми визначимо базові налаштування та типи девайсів, які ми будемо використовувати. Повний перелік доступних девайсів можна знайти тут.
const commonOptions = {
requireModule: ["ts-node/register"],
require: ["world.ts", "hooks.ts", "features/**/*.step.ts"],
formatOptions: {
snippetInterface: "async-await",
},
}; const profiles = {
desktop: {
device: "Desktop Chrome",
},
ios: {
device: "iPhone 14 Pro",
},
android: {
device: "Pixel 5",
},
}; const options = {};
for (const profile in profiles) {
options[profile] = {
...commonOptions,
worldParameters: {
device: profiles[profile].device,
},
};
} module.exports = options;
Відкриємо package.json
та зазначимо команди для виконання тестів на різних девайсах:
"scripts": {
"test:desktop": "cucumber-js --config cucumber.js --profile desktop",
"test:ios": "cucumber-js --config cucumber.js --profile ios",
"test:android": "cucumber-js --config cucumber.js --profile android"
}
Пишемо тести
Усі наші тести будуть розміщені в папці features/
. Створимо сценарій у файлі example.feature
, який би перевіряв title
вказаних сторінок. Використаємо Gherkin-синтаксис.
Feature: What is the page title? Scenario Outline: The page contains a specific title
Given url is "<url>"
When I open the page
Then it should have a "<title>" title Examples:
| url | title |
| https://playwright.dev/ | Fast and reliable end-to-end testing for modern web apps \| Playwright |
| https://cucumber.io/ | BDD Testing & Collaboration Tools for Teams \| Cucumber |
А також напишемо сам тест у файлі example.step.ts
, що безпосередньо перевіряє title
сторінок.
import { Given, When, Then } from "@cucumber/cucumber";
import { expect } from "@playwright/test"; import ExampleWorld from "../world"; interface ExampleStep extends ExampleWorld {
url: string;
} Given<ExampleStep>("url is {string}", async function (givenUrl: string) {
this.url = givenUrl;
}); When<ExampleStep>("I open the page", async function () {
await this.page.goto(this.url);
}); Then<ExampleStep>(
"it should have a {string} title",
async function (expectedTitle: string) {
await expect(this.page).toHaveTitle(expectedTitle);
}, );
Що ж, запустімо наш E2E-тест! Спершу перевіримо наші сценарії на Desktop:
npm run test:desktop
Очікуваним результатом буде:
Тепер перевіримо наші сценарії на iOS:
npm run test:ios
Очікуваним результатом буде:
Зрештою перевіримо наші сценарії на Android:
npm run test:android
Очікуваним результатом буде:
А сам процес виконання тестів буде записаний та збережений в папці videos/
для кожного сценарію:
Як бачимо, налаштувати проєкт з Playwright та Cucumber нескладно, його можна масштабувати чи додати до того, що існуює.
Що далі
Щоб автоматизувати процес виконання тестів, можна додати виконання створених команд до CI/CD та створити можливість збереження результатів тестів до хмарного сховища. Наприклад, на нашому проєкті ми створили свій власний вебзастосунок, який використовує файли результатів тестів (що завантажуються до Amazon S3 під час перевірки нової збірки) та дозволяє переглянути статус усіх сценаріїв для вказаних девайсів. Таким способом будь-який розробник чи навіть стейкхолдер може подивитися на результат виконання E2E-тестів та дізнатися їхній статус, що дозволяє швидко виявляти та реагувати на помилки.
Сподіваюся, стаття була корисною! Приємного використання!
76 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів