🌟 Функціональне програмування в автоматизованому тестуванні за допомогою TypeScript і Playwright 🤖🚀 Частина II

25 хв читання
🌟 Функціональне програмування в автоматизованому тестуванні за допомогою TypeScript і Playwright 🤖🚀 Частина II

Ласкаво просимо до другої частини нашого дослідження функціонального програмування в автоматизованому тестуванні. У цьому продовженні ми глибше заглибимося в практичну реалізацію концепцій, які вже обговорювалися досі. Ось що ви можете очікувати в цій частині:

Встановлення необхідних бібліотек

Ось покрокові інструкції щодо встановлення TypeScript, Playwright і fp-ts. Ми також додамо фрагменти коду та команди, які допоможуть вам у процесі встановлення. Будь ласка, зверніть увагу, що вам потрібно встановити Node.js, перш ніж продовжити ці інсталяції. Якщо ви ще не встановили Node.js, ви можете завантажити його з офіційного веб-сайту: Node.js

Крок 1: Встановіть TypeScript

  1. Відкрийте інтерфейс командного рядка (CLI) або термінал.
  2. Використовуйте Node Package Manager (npm), щоб установити TypeScript глобально:
npm install -g typescript
  1. Перевірте встановлення TypeScript, виконавши таку команду:
tsc --version

Ця команда має відобразити встановлену версію TypeScript.

Крок 2: Встановіть Playwright

  1. Відкрийте свій CLI або термінал.
  2. Створіть новий каталог для свого проекту Playwright, якщо ви ще цього не зробили:
mkdir my-playwright-project-fp
cd my-playwright-project-fp
  1. Ініціалізуйте новий проект Node.js у своєму каталозі:
npm init -y
  1. Встановіть Playwright, виконавши таку команду:
npm init playwright@latest
  1. Після встановлення Playwright ви можете використовувати його з JavaScript або TypeScript для автоматизованого тестування. TypeScript рекомендується для безпеки типу.

Крок 3: Встановіть fp-ts (функціональне програмування на TypeScript)

  1. Відкрийте свій CLI або термінал.
  2. Перейдіть до каталогу вашого проекту (наприклад, my-playwright-project-fp).
  3. Встановіть fp-ts як залежність для вашого проекту:
npm install fp-ts
  1. Тепер ви можете почати використовувати fp-ts у своєму коді TypeScript. Обов’язково імпортуйте необхідні модулі у ваші файли TypeScript.

Поширені проблеми та усунення несправностей

  1. Проблема з дозволами: якщо ви зіткнулися з проблемою з дозволами під час встановлення пакетів, можливо, вам знадобиться використати sudo або налаштувати належні дозволи для встановлення npm.
  2. Версія вузла: переконайтеся, що у вас встановлено сумісну версію Node.js. Ви можете перевірити свою версію Node.js за допомогою node -v і переконатися, що вона актуальна.
  3. Каталог проекту: переконайтеся, що ви знаходитесь у правильному каталозі під час виконання команд npm. Під час інсталяції Playwright і fp-ts ви повинні перебувати в каталозі проекту.
  4. Конфігурація TypeScript: якщо ви збираєтеся використовувати TypeScript із Playwright, вам може знадобитися налаштувати файл конфігурації TypeScript (tsconfig.json) у каталозі вашого проекту, щоб указати, як TypeScript має компілювати ваш код. Ви можете ініціалізувати файл конфігурації TypeScript за допомогою 'tsc --init' і налаштувати його за потреби.

Пам’ятаючи про ці інсталяції та деякі поширені кроки з усунення несправностей, ви маєте бути на шляху до створення функціональної системи автоматизованого тестування на основі програмування за допомогою TypeScript, Playwright і fp-ts.

Налаштування проекту

Структура проекту

Після встановлення необхідних бібліотек, таких як TypeScript, Playwright і fp-ts для вашого проекту автоматизованого тестування, важливо мати добре структурований каталог проекту, щоб ефективно підтримувати ваш код. Ось типова структура файлу проекту після встановлення необхідних бібліотек:

│
├── node_modules/
├── tests/
│   ├── example.spec.ts
├── tests-examples/
│   ├── demo-todo-app.spec.ts
├── .gitignore
├── package-lock.json
├── package.json
├── playwright.config.ts
├── tsconfig.json

Ось розбивка структури проекту:

  • node_modules/: цей каталог містить бібліотеки та залежності, встановлені для вашого проекту. Вам не потрібно керувати цим каталогом вручну; npm подбає про це.
  • tests/: цей каталог призначений для ваших загальних сценаріїв тестування. Файл example.spec.ts є ілюстрацією типового тестового сценарію.
  • tests-examples/: цей каталог, здається, зарезервовано для конкретних прикладів тестів. Файл demo-todo-app.spec.ts містить тестові випадки, пов’язані з демонстрацією програми todo.
  • .gitignore: цей файл визначає, які файли чи каталоги Git має ігнорувати, коли ви передаєте свій проект системі контролю версій. Це надзвичайно важливо для керування вашим проектом у середовищі з керуванням версіями.
node_modules/
/test-results/
/playwright-report/
/playwright/.cache/
  • package-lock.json: цей файл містить інформацію про точні версії пакетів, встановлених у вашому проекті, забезпечуючи узгодженість між членами команди або на різних машинах.
  • package.json: цей файл містить метадані про ваш проект і перелік залежностей проекту. Він також включає сценарії npm для запуску тестів, серед іншого.
{
  "name": "my-playwright-project-fp",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {},
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@playwright/test": "^1.39.0",
    "@types/node": "^20.8.7"
  },
  "dependencies": {
    "fp-ts": "^2.16.1"
  }
}
  • playwright.config.ts: цей файл конфігурації необхідний для налаштування параметрів Playwright, таких як браузери для використання, емуляція пристрою тощо.
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  reporter: 'html',
  use: {
    trace: 'on-first-retry',
  },
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
  ],
});

Ми можемо спростити нашу конфігурацію Playwright, щоб видалити додаткові проекти (firefox і webkit)

  • tsconfig.json: файл конфігурації TypeScript визначає, як TypeScript повинен компілювати ваш код. Ви можете налаштувати різні параметри, щоб адаптувати процес компіляції до вимог вашого проекту.
{
  "compilerOptions": {
    "target": "es2016",
    "module": "commonjs",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  }
}

Структура вашого проекту організована так, щоб акуратно розмістити ваші тестові сценарії та відповідні конфігурації. Ви можете створювати додаткові каталоги для службових функцій, об’єктів сторінки або будь-якого іншого допоміжного коду в міру розширення проекту. Ця структура забезпечує хорошу основу для автоматизованого тестування за допомогою Playwright і TypeScript.

Спробуємо провести наші перші тести 😊:

  1. Відкрийте CLI або термінал.
  2. Перейдіть до каталогу вашого проекту (наприклад, my-playwright-project-fp).
  3. Виконайте перші тести:
npx playwright test
  1. Результат:
2 passed (6.3s)
To open last HTML report run:
  npx playwright show-report

Щоб спростити виконання тестів, просто додайте цю команду «npx playwright test» у наш файл package.json у розділі «сценарії»:

{
  "name": "my-playwright-project-fp",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "npx playwright test"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@playwright/test": "^1.39.0",
    "@types/node": "^20.8.7"
  },
  "dependencies": {
    "fp-ts": "^2.16.1"
  }
}

Тепер ми можемо використовувати просту команду

npm test

Результат:

2 passed (6.3s)
To open last HTML report run:
  npx playwright show-report

Написання функціональних тестів

Тести на Playwright за замовчуванням

Надані тести Playwright є простими імперативними тестами для перевірки елементів веб-сторінки та взаємодії. Вони служать хорошою відправною точкою для розуміння можливостей Playwright, але мають деякі недоліки, якщо розглядати їх через призму функціонального програмування:

  1. Імперативний стиль:
  • Тести дотримуються імперативного стилю, де дії вказуються крок за кроком, що може ускладнити код для обґрунтування та підтримки.
  1. Побічні ефекти:
  • Тести включають побічні ефекти, такі як взаємодія зі сторінкою (наприклад, клацання), які зазвичай не рекомендуються у функціональному програмуванні, оскільки вони можуть внести непередбачуваність і вплинути на чистоту тесту.
  1. Відсутність повторного використання:
  • Тести не дуже багаторазові. Якщо вам потрібно виконати подібну дію на іншій сторінці або в кількох тестах, ви можете дублювати код, що призведе до проблем з обслуговуванням.
  1. Обробка тестових даних:
  • Дані, які використовуються в тестах (наприклад, URL-адреси, назви елементів), жорстко закодовані в тестових функціях, що робить їх менш гнучкими та важчими для оновлення, якщо в програмі відбуваються зміни.

Як перетворити тести на підхід функціонального програмування

Тепер давайте дослідимо, як можна перетворити ці тести на підхід функціонального програмування за допомогою fp-ts і TypeScript. Ми зосередимося на створенні більш модульних, багаторазових і чистих функцій.

Трансформовані тести є чудовими прикладами того, як застосувати принципи функціонального програмування до автоматизованого тестування за допомогою TypeScript, Playwright і fp-ts (функціональне програмування на TypeScript). Ці тести зосереджені на складанні чистих функцій і обробці помилок за допомогою TaskEither.

Ось розбивка підходу функціонального програмування та детальний опис кожного тесту:

Функціональний підхід:

У цьому підході ми створили чисті функції, які повертають монади TaskEither. Кожна функція представляє певну дію та складається з використанням функції каналу бібліотеки fp-ts для створення тестових сценаріїв.

  • Функція goto:
const goto = (page: Page) => (url: string): TE.TaskEither<void, Page> =>
  TE.tryCatch<void, Page>(
    async () => {
      await page.goto(url);
      return page;
    },
    (error) => {
      throw new Error(error as string);
    }
  );

Функція goto приймає об’єкт сторінки Playwright і повертає функцію, яка приймає URL-адресу для переходу. Він інкапсулює логіку для переходу до вказаної URL-адреси. Він повертає TaskEither, який може обробляти помилки.

  • Функція clickGetStarted:
const clickGetStarted = (page: Page): TE.TaskEither<void, Page> =>
  TE.tryCatch<void, Page>(
    async () => {
      await page.getByRole('link', { name: 'Get started' }).click();
      return page;
    },
    (error) => {
      throw new Error(error as string);
    }
  );

Функція clickGetStarted приймає об’єкт сторінки Playwright і повертає функцію, яка клацає посилання «Почати» на сторінці. Він також повертає TaskEither для керування будь-якими потенційними помилками під час дії.

  • Функція verifyTitle:
const verifyTitle = (page: Page) => (expectTitle: RegExp | string): TE.TaskEither<void, void> =>
  TE.tryCatch<void, void>(
    async () => await expect(page).toHaveTitle(expectTitle),
    (error) => {
      throw new Error(error as string);
    }
  );

Функція verifyTitle приймає об’єкт сторінки Playwright і очікуваний заголовок (як регулярний вираз або рядок) і повертає функцію, яка перевіряє, чи заголовок сторінки відповідає очікуваному значенню. Він повертає TaskEither.

  • Функція verifyIfHeadingInstallationElementIsVisible:
const verifyIfHeadingInstallationElementIsVisible = (page: Page): TE.TaskEither<void, void> =>
  TE.tryCatch<void, void>(
    async () => {
      await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible();
    },
    (error) => {
      throw new Error(error as string);
    }
  );

Ця функція перевіряє, чи відображається на сторінці елемент заголовка «Встановлення». Він приймає об’єкт сторінки Playwright і повертає TaskEither.

Тестові випадки:

У тестах використовується функція каналу з fp-ts для послідовного створення дій. Ось детальний опис кожного тесту:

  • "has title fp" Тест:
test('has title fp', async ({ page }) => {
  await F.pipe(
    goto(page)('https://playwright.dev/'),
    TE.chain((page) => verifyTitle(page)(/Playwright/))
  )();
});
  • Тест переходить до URL-адреси "https://playwright.dev/" за допомогою функції goto.

  • Потім він перевіряє, що заголовок сторінки містить рядок "Playwright" за допомогою функції verifyTitle із регулярним виразом.

  • Усі дії складаються з використанням TE.chain для обробки помилок і забезпечення чистоти та передбачуваності тесту.

  • "get started link fp" Тест:

test('get started link fp', async ({ page }) => {
  await F.pipe(
    goto(page)('https://playwright.dev/'),
    TE.chain((page) => clickGetStarted(page)),
    TE.chain((page) => verifyIfHeadingInstallationElementIsVisible(page))
  )();
});
  • Цей тест також починається з переходу до 'https://playwright.dev/' за допомогою функції goto.
  • Потім клацає посилання «Почати» за допомогою функції clickGetStarted.
  • Нарешті, він перевіряє, чи видимий елемент заголовка "Installation" за допомогою функції verifyIfHeadingInstallationElementIsVisible.
  • Як і в першому тесті, він використовує TE.chain для послідовності дій і обробки помилок.

Обробка помилок:

Кожна функція включає обробку помилок за допомогою TE.tryCatch. У разі помилок він видає повідомлення про помилку з описовим повідомленням, гарантуючи, що помилки обробляються контрольованим способом.

Цей функціональний підхід добре узгоджується з принципами функціонального програмування, наголошуючи на використанні чистих функцій, композиції та керування помилками. Це призводить до більш зручного та передбачуваного тестового коду, що полегшує написання та налагодження складних тестових сценаріїв. Крім того, він забезпечує гнучкість для ефективної обробки помилок і надання значущих повідомлень про помилки.

Передові методи

Передові методи функціонального програмування можуть значно покращити автоматизоване тестування, зробивши ваш тестовий код більш надійним, придатним для обслуговування та ефективним. Ось кілька передових методів і концепцій, які можна застосувати до автоматизованого тестування в рамках парадигми функціонального програмування:

  1. Функції вищого порядку (HOF):
  • HOF - це функції, які приймають інші функції як аргументи або повертають функції як результати. Під час автоматизованого тестування ви можете створювати функції вищого порядку для інкапсуляції загальних тестових шаблонів. Наприклад, ви можете створити функцію вищого порядку для обробки автентифікації, налаштування даних або навігації сторінками, зробивши ваші тести більш модульними та СУХИМИ (не повторюйтеся).
  1. Функціональний склад:
  • Функціональна композиція - це акт поєднання двох або більше функцій для отримання нової функції. Під час тестування ви можете створювати функції для створення складних тестових сценаріїв. Це дозволяє повторно використовувати та комбінувати менші чисті функції для ефективного створення комплексних тестів.
  1. Монади та функтори:
  • Монади та функтори — це передові концепції функціонального програмування, які можна застосовувати для обробки послідовності та обробки помилок у тестах. Такі бібліотеки, як fp-ts, надають такі монади, як Task і TaskEither, для ефективного керування асинхронними діями та помилками.
  1. Незмінність:
  • Незмінність є основним принципом функціонального програмування. Незмінні структури даних, як і постійні структури даних, можна використовувати для представлення та обробки тестових даних. Це гарантує, що тестові дані залишаються узгодженими під час виконання тесту, підвищуючи надійність.
  1. Часткове нанесення та каррірування:
  • Часткове застосування та каррінг дозволяють створювати функції з кількома параметрами крок за кроком, полегшуючи передачу конфігурацій і залежностей у ваші тестові функції. Це покращує обробку тестових даних і гнучкість.
  1. Безпека типу та статичний аналіз:
  • Використовуйте TypeScript або інші статично типізовані мови для свого коду тестування. Статична типізація гарантує, що ваш код відповідає очікуваним типам даних, зменшуючи помилки, пов’язані з типами, і роблячи ваші тести більш надійними.
  1. Чисті функції:
  • Функціональне програмування заохочує використання чистих функцій, які створюють той самий вихід для того самого входу. Написання чистих функцій для ваших тестових дій забезпечує передбачуваність, легке тестування та надійні тестові налаштування.

Включивши ці передові методи функціонального програмування у своє автоматизоване тестування, ви можете створити тестовий код, який є більш надійним, придатним для обслуговування та адаптацією. Це також допомагає оптимізувати розробку тестових прикладів, покращити повторне використання коду та підвищити загальну якість вашої системи тестування.

Як розширити існуючі тести за допомогою фіксутр

Поточна проблема з визначенням цих функцій (наприклад, goto, clickGetStarted, verifyTitle і verifyIfHeadingInstallationElementIsVisible) в одному тестовому файлі полягає в тому, що це порушує принципи модульності, багаторазове використання та поділ проблем. Ось чому вам варто розглянути можливість використання фікстур і переміщення цих функцій в окремі модулі:

  1. Порушення розподілу завдань: збереження цих функцій у тестовому файлі ускладнює відокремлення питань налаштування та взаємодії зі сторінкою від фактичної логіки тестування. Це порушує принцип поділу проблем, що може призвести до менш зручного обслуговування та більш складного коду.
  2. Дублювання коду: якщо у вас є кілька тестових файлів, які повинні виконувати однакові дії (наприклад, перехід на сторінку, клацання посилання), ви в кінцевому підсумку дублюєте ці функції в кількох тестових файлах. Це не тільки збільшує надлишковість коду, але й ускладнює підтримку та оновлення коду, коли потрібні зміни.
  3. Неможливість повторного використання: такі функції, як goto, clickGetStarted і verifyTitle, є загальними діями, які можна повторно використовувати в кількох тестових файлах. Централізувавши ці дії, ви сприяєте повторному використанню та зручності обслуговування.
  4. Test Fixture: використання фікстури в Playwright забезпечує спеціальне та структуроване середовище для налаштування екземплярів і сторінок браузера та керування ними. Перемістивши ці функції в прилад, ви можете гарантувати, що кожен тест починається з чистого та передбачуваного стану. Це також покращує ізоляцію ваших тестів, роблячи їх більш надійними.
  5. Організація коду: переміщення цих функцій в окремі модулі дозволяє більш ефективно організувати ваш код. Ви можете створити спеціальний модуль для дій, модуль для тестових приладів і інший для реальних тестів. Це розділення покращує читабельність і зручність обслуговування вашої кодової бази.
  6. Співпраця: під час роботи в команді стандартизований підхід до налаштування та дій тестування, як це передбачено фікстурами та централізованими модулями, гарантує, що всі дотримуються однакових практик. Це покращує співпрацю та полегшує розуміння та розширення набору тестів.

Щоб покращити свій підхід, розгляньте наступні кроки:

  1. Створіть спеціальний пристрій для налаштування тестового середовища, яке включає запуск браузера та створення сторінки.
  2. Визначте окремі модулі для дій, які ви хочете виконати (наприклад, навігація, взаємодія, перевірка).
  3. Використовуйте кріплення у ваших тестових файлах, щоб налаштувати середовище перед кожним тестом.
  4. Створіть дії з ваших модулів дій у ваших тестових функціях.

Прийнявши цей підхід, ви отримаєте більш модульний код, який можна багаторазово використовувати та підтримувати, який відповідає найкращим практикам автоматизації тестування. Він сприяє організації коду, спільному використанню коду та стандартизації, що зрештою робить ваші спроби тестування ефективнішими та надійнішими.

Створіть спеціальну фікстуру

Давайте створимо спеціальну програму для налаштування вашого тестового середовища, яка включає створення екземпляра цільової сторінки. Створіть нову папку fixtures у папці tests з файлом fixture.ts: тепер структура проекту така:

│
├── node_modules/
├── tests/
│   ├── fixtures/
│   │   ├── fixture.ts
│   ├── example.spec.ts
├── .gitignore
├── package-lock.json
├── package.json
├── playwright.config.ts
├── tsconfig.json

Щоб створити нашу фікстуру, давайте почнемо з імпорту необхідних залежностей:

import { test as base } from '@playwright/test';

Визначте тип фікстури, який представляє її структуру. У цьому випадку він включає властивість landingPage типу LandingPage, який є типом, пов’язаним із цільовою сторінкою вашої програми.

import { test as base } from '@playwright/test';

type Fixture = {
  landingPage: LandingPage;
};

Створіть тестову фікстуру за допомогою base.extend. Цей метод розширює базовий набір тестів додатковими функціями. Тут ви розширюєте його за допомогою фікстури, яке налаштує вашу цільову сторінку.

import { test as base } from '@playwright/test';

type Fixture = {
  landingPage: LandingPage;
};
export const test = base.extend<Fixture>({
  landingPage: async ({ page }, use) => {
    const landing = landingPage(page);
    await use(landing);
    await page.close();
  }
});

У визначенні фіксутри:

  • Ви надаєте функцію зворотного виклику, яка приймає два аргументи: page і use. сторінка — це об’єкт Сторінка Playwright, а використання — це функція, яка дозволяє передавати дані налаштування (у цьому випадку об’єкт landingPage) до тестів, які використовують цей фікстур.
  • Ви створюєте екземпляр LandingPage за допомогою функції landingPage, передаючи об’єкт page.
  • Ви передаєте об’єкт landing у функцію use. Це дозволяє тестам, які використовують цей прилад, отримувати доступ до об’єкта landingPage.
  • Нарешті, ви закриваєте сторінку, щоб очистити після тесту. Це важливо для підтримки чистого та ізольованого тестового середовища.

Експортуйте функцію очікування з бібліотеки @playwright/test. Ця функція дозволяє робити твердження у ваших тестових випадках.

import { test as base } from '@playwright/test';

type Fixture = {
  landingPage: LandingPage;
};
export const test = base.extend<Fixture>({
  landingPage: async ({ page }, use) => {
    const landing = landingPage(page);
    await use(landing);
    await page.close();
  }
});

export { expect } from '@playwright/test';

Тепер у вас можуть виникнути деякі помилки, оскільки ми не використовуємо Цільову сторінку та цільову сторінку.

Визначте окремі модулі для дій

Давайте визначимо окремі модулі для дій, які ви хочете виконувати, наприклад навігацію, взаємодію та перевірку. Створіть нову папку src у корені. Потім створіть папку pages, що означає, що ми розмістимо всі сторінки в одній папці.

Потім створіть файл landing-page.ts у папці pages.

│
├── node_modules/
├── src/
│   ├── pages/
│   │   ├── landing-page.ts
├── tests/
│   ├── fixtures/
│   │   ├── fixture.ts
│   ├── example.spec.ts
├── .gitignore
├── package-lock.json
├── package.json
├── playwright.config.ts
├── tsconfig.json

Щоб створити наші окремі модулі, давайте почнемо з імпорту необхідних залежностей:

import { PageOf } from "./pages";

Заява про імпорт: Цей рядок імпортує тип або інтерфейс під назвою PageOf з модуля, розташованого у відносному шляху до файлу ./pages.

Тепер нам потрібно створити один додатковий тип PageOf. Створіть файл pages.ts у папці pages.

│
├── node_modules/
├── src/
│   ├── pages/
│   │   ├── landing-page.ts
│   │   ├── pages.ts
├── tests/
│   ├── fixtures/
│   │   ├── fixture.ts
│   ├── example.spec.ts
├── .gitignore
├── package-lock.json
├── package.json
├── playwright.config.ts
├── tsconfig.json

Щоб створити наш тип, ми визначаємо наступний код:

import { Page } from '@playwright/test';

export type PageOf<T> = (page: Page) => T;

Модуль pages.ts зосереджений на визначенні типу , який є загальним типом. Давайте зануримося глибше в цей модуль:

  1. Імпорт:
  • Модуль імпортує тип сторінки з середовища Playwright. Цей тип представляє об’єкт сторінки Playwright.
  1. Визначення типу:
  • Визначення типу є загальним типом, який приймає тип T. Цей тип представляє функцію, яка приймає Playwright Page і повертає об’єкт типу T. Цей шаблон зазвичай використовується для визначення об’єктів сторінки або інтерфейсів елементів.

Створюючи цей тип, ви встановлюєте контракт, який передбачає, що будь-яка функція типу повинна повертати об’єкт, що відповідає типу T, що допомагає забезпечити узгодженість у ваших об’єктних моделях сторінки. .

Повернемося до реалізації нашого модуля дій для цільової сторінки у файлі landing-page.ts.

import { PageOf } from "./pages";

export interface LandingPage {

}

Інтерфейси та типи: Інтерфейс LandingPage виглядає як заповнювач для визначення елементів і дій, характерних для цільової сторінки. У об’єктних моделях сторінок зазвичай створюють такі інтерфейси для визначення структури сторінки.

import { PageOf } from "./pages";

export interface LandingPage {

}

export const landingPage: PageOf<LandingPage> = (page) => {
    return {

    };
}

Функція landingPage: Функція landingPage експортується з цього модуля. Він приймає Playwright Page як аргумент і повертає об’єкт, який відповідає інтерфейсу LandingPage. Ця функція, по суті, є фабричною функцією для створення екземплярів POM цільової сторінки.

Функція landingPage, викликана зі сторінкою, має повертати об’єкт, який надає методи та властивості для взаємодії з елементами на цільовій сторінці. Ці методи можуть включати такі дії, як натискання кнопок, заповнення форм і перевірка елементів.

Підводячи підсумок, модуль landingPage призначений для інкапсуляції структури та дій, пов’язаних із конкретною сторінкою (в даному випадку це цільова сторінка). Він використовує функцію landingPage для створення екземплярів цієї сторінки з методами взаємодії з елементами. Модуль pages.ts визначає тип () для забезпечення виконання контракту для об’єктів сторінки та підтримки безпеки типу.

За допомогою такого підходу ви можете створювати подібні модулі для інших сторінок у вашій програмі, в результаті чого ви отримаєте добре структурований і модульний набір тестів. Ці модулі допомагають розділити вашу тестову логіку та взаємодію сторінок, роблячи автоматизовані тести більш організованими та простішими в обслуговуванні.

Використовуйте фікстури в тестових файлах

Щоб використовувати наш фікстури зі створеними модулями в наших тестах, давайте перемістимо визначені методи з файлу example.spec.ts у наш файл landing-page.ts.

import { expect } from "../../tests/fixtures/fixture";
import { PageOf } from "./pages";
import * as TE from 'fp-ts/TaskEither';

export interface LandingPage {
  goto: (url: string) => TE.TaskEither<void, void>;
  clickGetStarted: () => TE.TaskEither<void, void>;
  verifyTitle: (title: RegExp | string) => TE.TaskEither<void, void>;
}

export const landingPage: PageOf<LandingPage> = (page) => {
  return {
    goto: (url): TE.TaskEither<void, void> => 
      TE.tryCatch(
        async () => { await page.goto(url) },
        (error) => { throw new Error(error as string) }
      ),
    clickGetStarted: (): TE.TaskEither<void, void> => 
      TE.tryCatch(
        async () => page.getByRole('link', { name: 'Get started' }).click(),
        (error) => {
        throw new Error(error as string);
        }
      ),
    verifyTitle: (title): TE.TaskEither<void, void> => 
      TE.tryCatch(
        async () => await expect(page).toHaveTitle(title),
        (error) => {
          throw new Error(error as string);
        }
      ),
  };
}

Ми створили окремий модуль під назвою landing-pages.ts, щоб інкапсулювати дії та функції, пов’язані з цільовою сторінкою вашої програми. Цей підхід сприяє модульності та багаторазовому використанню, що узгоджується з принципами функціонального програмування. Давайте розберемо ваш модуль і його компоненти:

  1. Залежності та типи імпорту:
  • Ви починаєте з імпорту необхідних залежностей і типів, на які покладається ваш модуль. Це включає імпорт expect для тверджень, PageOf з модуля pages і монади TE (TaskEither) з fp-ts для обробки асинхронних дій і потенційних помилки.
  1. Визначте інтерфейс LandingPage:
  • Ви визначаєте інтерфейс під назвою LandingPage, який визначає структуру дій цільової сторінки. Цей інтерфейс описує три ключові дії для цільової сторінки: goto, clickGetStarted і verifyTitle.
  1. Створіть функцію landingPage: Ця функція служить фабричною функцією, яка створює об’єкт LandingPage. Він приймає об’єкт page як параметр, який представляє сторінку Playwright, де виконуватимуться ці дії. Ця функція повертає об’єкт із визначеними діями.
  2. Визначення дій:
  • У функції landingPage ви визначаєте три дії:
    • goto: ця функція переходить до вказаної URL-адреси та повертає TaskEither для обробки помилок.
    • clickGetStarted: ця функція натискає посилання «Почати», а також повертає TaskEither.
    • verifyTitle: ця функція перевіряє, чи заголовок сторінки відповідає наданому регулярному виразу або рядку, і повертає TaskEither.

Кожна з цих функцій дій використовує TE.tryCatch для акуратної обробки помилок і гарантує, що будь-які помилки фіксуються та повідомляються. Цей підхід узгоджується з функціоналом принципи програмування, зберігаючи чисті дії, відокремлюючи проблеми та інкапсулюючи функціональність у модульний спосіб.

Структуруючи свій код таким чином, ви сприяєте повторному використанню, зручності обслуговування та ізоляції тестів. Тепер цей модуль можна легко імпортувати та використовувати в різних тестових файлах для послідовної та надійної взаємодії з цільовою сторінкою. Це також сприяє співпраці та узгодженості коду, коли кілька членів команди працюють над одним проектом. Тож давайте імпортуємо наш модуль у тестовий файл.

import { test } from './fixtures/fixture';
import * as TE from 'fp-ts/TaskEither';
import * as F from 'fp-ts/function';

test('has title fp', async ({ landingPage }) => {
  await F.pipe(
    landingPage.goto('https://playwright.dev/'),
    TE.chain(() => landingPage.verifyTitle(/Playwright/))
  )();
});

У вашому тестовому файлі ви успішно імпортували модуль landingPage та інтегрували його у свої тестові випадки відповідно до парадигми функціонального програмування. Ось детальне пояснення тестового коду:

  1. Тестовий імпорт:
  • Ви починаєте з імпорту функції test із вашого тестового приладу, який надає тестове середовище Playwright і фікстуру landingPage.
  1. Функціональний склад:
  • Ви використовуєте функцію F.pipe для створення послідовності дій. Функція pipe дозволяє вам виконувати функції в конвеєрі, де вихідні дані однієї функції передаються як вхідні дані для наступної функції.
  1. landingPage.goto('https://playwright.dev/'):
  • Ця дія складається спочатку. Він використовує фікстуру landingPage для переходу до URL-адреси «https://playwright.dev/». Функція goto повертає TaskEither, що представляє дію навігації.
  1. TE.chain(() => landingPage.verifyTitle(/Playwright/)):
  • Функція TE.chain використовується для ланцюжка наступної дії. У цьому випадку це функція verifyTitle. Функція verifyTitle перевіряє, чи заголовок сторінки відповідає регулярному виразу /Playwright/. Якщо перевірка заголовка вдається, вона повертає TaskEither, що вказує на успіх.
  1. ()(); - Виконайте складені дії:
  • Кінцевий ()(); в кінці композиції використовується для виконання складених дій. Цей шаблон часто можна побачити у функціональному програмуванні з асинхронними операціями. Це спосіб ініціювати виконання складених функцій і переконатися, що будь-які помилки належним чином обробляються монадою TaskEither.

Побудувавши свій тест таким чином, ви досягли таких переваг:

  • Модульність: дії для переходу до URL-адреси та перевірки заголовка інкапсульовані в фікстурі landingPage, сприяючи модульності коду та повторному використанню.
  • Функціональна композиція: ви використали функціональну композицію для створення послідовності дій, завдяки чому ваш тестовий код став більш декларативним і легшим для читання.
  • Обробка помилок: помилки витончено обробляються за допомогою монади TaskEither, гарантуючи, що будь-які помилки під час тестування фіксуються та можуть бути керовані передбачуваним способом.
  • Ізоляція тестів: завдяки використанню фіксаторів і модульного підходу кожен тест може починатися з чистого стану, сприяючи ізоляції тестів і знижуючи ймовірність перешкод між тестами.

Цей підхід добре узгоджується з принципами функціонального програмування та забезпечує структурований і організований спосіб написання зручних і надійних тестів.

Але зачекайте, є одна річ, яку ми ще не зробили. Для другого тесту потрібен інший модуль для сторінки «Почати», спробуйте реалізувати його самостійно

Висновок

Ключові висновки з цих двох публікацій:

  1. Принципи функціонального програмування:
  • Функціональне програмування сприяє використанню чистих функцій, незмінності та компонування, що призводить до більш надійного та придатного для обслуговування тестового коду автоматизації.
  1. Модульна структура тесту:
  • Структурування тестового коду за допомогою модульних компонентів, таких як кріплення та окремі модулі дій, покращує організацію коду та можливість повторного використання.
  1. fp-ts для обробки помилок:
  • Використання бібліотеки fp-ts, зокрема TaskEither, для обробки помилок забезпечує послідовне та передбачуване керування помилками у ваших тестових сценаріях.
  1. Пристосування та параметри пристосувань:
  • Механізм фікстури Playwright дозволяє створювати стандартизовані тестові налаштування, а параметри фікстур дозволяють передавати багаторазові дії та конфігурації до ваших тестів.
  1. Відокремлення концернів:
  • Відокремлення проблем у вашому тестовому коді, наприклад ізоляції тестових дій від тестової логіки, спрощує налагодження та сприяє співпраці у великих проектах.
  1. Статичний набір із TypeScript:
  • TypeScript забезпечує статичну типізацію, що покращує якість коду, запобігає помилкам, пов’язаним із типом, і підвищує загальну надійність ваших тестів.
  1. Повторне використання та ремонтопридатність:
  • Функціональне програмування та модульні структури коду спрощують повторне використання тестів, спрощуючи підтримку та розширення набору тестів у міру розвитку програми.
  1. Склад функціонального тесту:
  • Компонування чистих функцій для тестових дій гарантує, що ваші тестові сценарії будуються з менших багаторазово використовуваних компонентів, що забезпечує більш читабельні та ефективні тести.
  1. Обробка помилок і звітування:
  • Техніка функціонального програмування дозволяє структуровано обробляти помилки та звітувати, забезпечуючи чіткість та інформативність помилок тестування.
  1. Тестова ізоляція:
  • Використання кріплень і модульного підходу допомагає досягти ізоляції тестів, коли кожен тест починається з чистого стану, зменшуючи перешкоди між тестовими випадками.

Таким чином, застосування концепцій функціонального програмування, модульної організації коду та використання TypeScript і Playwright в автоматизованому тестуванні призводить до тестів, які є більш надійними, доступними для обслуговування та ефективними. Ці методи сприяють співпраці та узгодженості коду в командних середовищах, що призводить до високоякісного набору тестів для ваших веб-додатків.

Додаткові ресурси

Ось кілька додаткових ресурсів, книг і веб-сайтів, де ви можете розширити свої знання про функціональне програмування, TypeScript, fp-ts і Playwright:

Функціональне програмування:

  • "Функціональне програмування в JavaScript" Луїса Атенсіо: ця книга досліджує концепції функціонального програмування в JavaScript, які також мають велике відношення до TypeScript.
  • "Функціональне програмування в Scala" Пола К'юзано та Рунара Б'ярнасона: Хоча книга фокусується на Scala, забезпечує глибоке занурення в концепції функціонального програмування, які можна застосувати до TypeScript.
  • Функціональне програмування за допомогою TypeScript: цей онлайн-курс охоплює принципи функціонального програмування.

TypeScript:

  • Офіційний довідник з TypeScript: офіційний довідник містить повну документацію про TypeScript, включаючи ключові поняття та практичні приклади.
  • "Програмування TypeScript" Бориса Черного: ця книга є цінним ресурсом для вивчення TypeScript, який охоплює як основні, так і складні теми.
  • TypeScript Deep Dive (онлайн-книга): поглиблений посібник з TypeScript, доступний онлайн безкоштовно, охоплюючи розширені функції TypeScript і найкращі практики.

fp-ts (функціональне програмування на TypeScript):

  • fp-ts GitHub Repository: офіційне сховище містить документацію, приклади коду та ресурси для fp-ts.
  • "Функціональне програмування на TypeScript" на Medium: серія статей від творця fp -ts, Джуліо Канті, пояснюючи різні концепції та техніки в fp-ts.

Драматург:

  • Офіційна документація Playwright: офіційна документація — це повний ресурс для початку роботи з Playwright, включаючи навчальні посібники та посилання на API.
  • Playwright with TypeScript на Dev.to: Статті та навчальні посібники про використання Playwright з TypeScript, включаючи розширене тестування техніки.

Сховище GitHub

  • зразок проекту, який ми створили в цій публікації;

хожі публікації

🌟 Функціональне програмування в автоматизованому тестуванні за допомогою TypeScript і Playwright 🤖🚀 Частина I
13 хв читання

🌟 Функціональне програмування в автоматизованому тестуванні за допомогою TypeScript і Playwright 🤖🚀 Частина I

Функціональне програмування в автоматизованому тестуванні — це парадигма, яка використовує принципи функціонального програмування для розробки та написання тестових сценаріїв. На відміну від традиційних імперативних підходів до тестування, функціональне програмування зосереджується на створенні ...

🚀 Використання функціонального програмування для автоматизованого тестування: розкриття нових можливостей 🚀
3 хв читання

🚀 Використання функціонального програмування для автоматизованого тестування: розкриття нових можливостей 🚀

Як професіонали із забезпечення якості, наша місія полягає в забезпеченні надійності та продуктивності програмного забезпечення. Автоматизоване тестування є наріжним каменем цього процесу, і наш підхід до цього може змінити все. Сьогодні давайте заглибимося у світ функціонального програмування та то...

🤖 Використання ланцюжкових функцій для автоматизованого тестування за допомогою Playwright і TypeScript 🚀
7 хв читання

🤖 Використання ланцюжкових функцій для автоматизованого тестування за допомогою Playwright і TypeScript 🚀

Представляючи світ «Використання ланцюжкових функцій для автоматизованого тестування з Playwright і TypeScript», ми починаємо подорож, щоб ще більше покращити ваші навички автоматизованого тестування. Як розширення раніше дослідженого шаблону PageObject, ця тема пропонує потужний і ефективний спо...

Додому