Объектная модель страницы (POM) — это шаблон проектирования, широко используемый в автоматизации тестирования, который создает репозиторий объектов для элементов веб-интерфейса. Преимущество модели в том, что она уменьшает дублирование кода и улучшает сопровождение тестов.

Эта история представляет собой руководство по использованию Puppeteer, TypeScript и Jest для написания простого сквозного теста (E2E). В учебнике будет написано несколько тестов, чтобы охватить несколько простых тестовых случаев. В учебнике также используется модальный шаблон объекта страницы для выполнения этих тестовых случаев.

Мы будем использовать демо-сайт электронной коммерции — https://www.saucedemo.com/.

С помощью этого веб-сайта мы можем написать готовые примеры для страницы входа и добавить поток корзины.

Вход в систему: должно возвращать правильное сообщение об ошибке, если имя пользователя или пароль недействительны или учетная запись заблокирована.

Добавление товаров в корзину. На главной странице добавьте несколько товаров в корзину. Перейдите на страницу корзины, эти товары должны были появиться.

Проект E2E с Puppeteer, TypeScript и Jest

Первоначальный проект

В каталоге вашего проекта установите TypeScript и создайте файл tsconfig.json:

$ npm init -y # Init nodejs project
$ npm install typescript
$ npx tsc --init # Create tsconfig.json file with default values

Установите пакеты зависимостей:

$ npm install jest jest-puppeteer puppeteer ts-jest @types/jest @types/jest-environment-puppeteer @types/puppeteer
  • jest-puppeteer: предустановка Jest, упрощающая настройку безголового браузера puppeteer.
  • @types/jest-environment-puppeteer: определение типа поддерживает TypeScript, когда вы пишете код TS с помощью Jest и Puppeteer.

Конфигурация TypeScript, Jest и Puppeteer:

tsconfig.json :

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "rootDir": "./__tests__",
    "sourceMap": true,
    "types": [
      "jest",
      "puppeteer",
      "jest-environment-puppeteer",
    ],
    "outDir": "dist",
  },
  "include": [
    "./__tests__",
  ]
}

jest-puppeteer.config.js :

module.exports = {
  launch: {
    dumpio: true,
    headless: process.env.HEADLESS === 'true',
    args: ['--disable-infobars', '--window-size=1200,800'],
    defaultViewport: null,
  },
  browserContext: 'default',
};

jest.config.js :

module.exports = {
  testTimeout: 30000,
  testMatch: ['**/?(*.)+(spec|test).[t]s'],
  preset: 'jest-puppeteer',
  transform: {
    '^.+\\.ts$': 'ts-jest',
  },
  testPathIgnorePatterns: ['/node_modules/', 'dist'],
};

Создайте тестовый сценарий для проекта. Обновим файл package.json:

...
  "scripts": {
    "test": "jest --runInBand"
  },
...

Параметр --runInBrand для последовательного запуска всех тестовых случаев.

Создайте простой тест

Создайте простой файл спецификаций в каталоге __test__. И напишите простой тест «Зайдите на главную страницу Google и убедитесь, что заголовок страницы Google».

google.spec.ts

describe("Google.com", () => {
  it('should get correct title when go to home page', async () => {
    await page.goto('https://google.com');
    const title = await page.title();
    expect(title).toEqual('Google');
  });
});

С помощью @types/jest-environment-puppeteer мы можем легко использовать объект page в качестве объекта страницы Puppeteer в нашем файле TS.

Запустите тестовый скрипт:

# Run in normal mode
$ npm run test # Or `npm test` or `npm t`
# Run with headless mode
$ HEADLESS=true npm run test

Вывод будет выглядеть следующим образом:

Determining test suites to run...
DevTools listening on ws://127.0.0.1:63472/devtools/browser/6a96a46a-6fea-4511-9374-5d9511557abb
 PASS  __tests__/google.spec.ts
  Google.com
    ✓ should get correct title when go to home page (859 ms)
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.649 s, estimated 3 s
Ran all test suites.

Реализуйте объектные модели страницы

Создайте объект базовой страницы — объект включает в себя некоторые общие функции

./__test__/pages/base.po.ts

Это абстрактный класс с go абстрактной функцией — функцией для перехода к правильному URL-адресу каждой страницы.

Сосредоточьтесь на нашем первом тестовом примере — странице входа на демонстрационный веб-сайт. Взгляните на страницу входа:

Тогда объектная модель страницы входа будет включать 4 элемента и 1 действие.

./__test__/pages/login.po.ts

У нас есть действие login и вспомогательная функция getErrorMessage для получения текущего сообщения об ошибке.

Теперь мы можем создать тестовую спецификацию для страницы входа:

./__test__/login.spec.ts

Мы используем синтаксис test.each Jest для создания 3 «неудачных» тестовых случаев.

Теперь вы можете снова запустить тест npm run test , и результат будет выглядеть так:

Determining test suites to run...
DevTools listening on ws://127.0.0.1:64018/devtools/browser/ef8bc336-90ee-414b-bb1e-2df87fe8fe4c
 PASS  __tests__/login.spec.ts
  Login
    ✓ should display "Epic sadface: Username and password do not match any user in this service" when username|password is "wrong_username|secret_sauce" (366 ms)
    ✓ should display "Epic sadface: Username and password do not match any user in this service" when username|password is "standard_user|wrong_password" (185 ms)
    ✓ should display "Epic sadface: Sorry, this user has been locked out." when username|password is "locked_out_user|secret_sauce" (150 ms)
    ✓ should go to inventory page when username and password are correct (193 ms)
Test Suites: 1 passed, 1 total
Tests:       4 passed, 4 total
Snapshots:   0 total
Time:        3.418 s
Ran all test suites.

Это все, что касается страницы входа.

Спецификация добавления товара в корзину более сложна, чем спецификация входа. История спецификации будет такой:

GIVE: List of products on the inventory page
WHEN: Click "Add to cart" button on some products
THEN: Number of cart item (top-right badge) should be updated corectly.
WHEN: Go to cart page
THEN: The added products should be appeared

Давайте сначала cart.spect.ts файл:

Мы получаем все продукты на странице инвентаря, выбираем 3 случайных товара, затем пытаемся добавить их в корзину. Подтвердите количество корзины.

Перейдите на страницу корзины, получите все товары на этой странице и сравните с 3 товарами.

Спецификация e2e может использовать один или несколько объектов страницы. Как и наша спецификация, она использует inventory page object и cart page object.

inventory.po.ts

cart.po.ts

Выполнить тестовый скрипт с опцией --verbose:

$ npm run test -- --verbose
# Result
Determining test suites to run...
DevTools listening on ws://127.0.0.1:56282/devtools/browser/61fb6612-de1f-4b08-8729-be984829f009
 PASS  __tests__/login.spec.ts
  Login
    ✓ should display "Epic sadface: Username and password do not match any user in this service" when username|password is "wrong_username|secret_sauce" (367 ms)
    ✓ should display "Epic sadface: Username and password do not match any user in this service" when username|password is "standard_user|wrong_password" (196 ms)
    ✓ should display "Epic sadface: Sorry, this user has been locked out." when username|password is "locked_out_user|secret_sauce" (147 ms)
    ✓ should go to inventory page when username and password are correct (181 ms)
PASS  __tests__/cart.spec.ts
  Cart
    ✓ should add correct products to cart (488 ms)
Test Suites: 2 passed, 2 total
Tests:       5 passed, 5 total
Snapshots:   0 total
Time:        3.92 s, estimated 5 s
Ran all test suites.

Мы закончили учебник e2e, используя объектные модели страниц.

Вывод

  • Объектная модель страницы TypeScript Puppeteer делает наш код тестирования e2e пригодным для сопровождения и повторного использования.
  • С предустановкой jest-puppeteer мы можем «внедрять» объекты page и browser в любое место проекта Jest, легко создавая классы объектов страницы.

Исходный код, используемый в этой статье, опубликован на Github.

Спасибо за чтение!

Дополнительные материалы на plainenglish.io