>
← Повернутися на головну

End-to-End (E2E) Testing

Автоматизація UI тестування з Cypress, Playwright та Selenium

📅 Оновлено: 7 лютого 2026 ⏱️ Час читання: 45 хв 🎯 Рівень: Середній — Просунутий
📘 Що таке E2E Testing?

End-to-End тестування — це автоматизоване тестування повного user flow від початку до кінця, імітуючи реальні дії користувача в браузері:

  • 🖱️ Кліки, скрол, введення тексту
  • 📄 Навігація між сторінками
  • 📝 Заповнення форм та відправка
  • ✅ Перевірка результатів та UI елементів
  • 🔄 Взаємодія з API та базою даних

Частина 1: Порівняння E2E Frameworks

Характеристика Cypress Playwright Selenium WebDriver
Рік випуску 2017 2020 (Microsoft) 2004
Підтримка браузерів Chrome, Firefox, Edge, Electron Chrome, Firefox, Safari, Edge, WebKit Всі основні браузери
Паралельні тести Платно (Cypress Cloud) ✅ Вбудовано ✅ (з Selenium Grid)
Швидкість ⭐⭐⭐⭐ Швидко ⭐⭐⭐⭐⭐ Дуже швидко ⭐⭐⭐ Помірно
Налаштування ⭐⭐⭐⭐⭐ Дуже просто ⭐⭐⭐⭐ Просто ⭐⭐ Складно
Debugging ⭐⭐⭐⭐⭐ Відмінний UI ⭐⭐⭐⭐ DevTools, Trace Viewer ⭐⭐⭐ Стандартний
Auto-wait ✅ Вбудований ✅ Вбудований ❌ Потрібні explicit waits
Мова програмування JavaScript/TypeScript JS, TS, Python, Java, C# Java, Python, C#, Ruby, JS
API Testing ❌ (потрібні окремі інструменти)
Mobile Testing ✅ (через browsers) ✅ (Appium)

Частина 2: Cypress — швидкий старт

1 Встановлення Cypress
# Встановлення npm install --save-dev cypress # Відкрити Cypress Test Runner npx cypress open # Запуск тестів у headless режимі npx cypress run # Запуск конкретного файлу npx cypress run --spec "cypress/e2e/calculator.cy.js"

Структура проекту після ініціалізації:

cypress/ ├── e2e/ # Тестові файли ├── fixtures/ # Тестові дані (JSON) ├── support/ # Допоміжні команди │ ├── commands.js │ └── e2e.js └── videos/ # Записи тестів (автоматично) └── screenshots/ # Скріншоти при помилках
2 Перший тест: Calculator Test

Створіть cypress/e2e/calculator.cy.js:

describe('Scientific Calculator', () => { beforeEach(() => { // Відкрити сторінку перед кожним тестом cy.visit('https://scientific-calculators.com/calculators/quadratic-calculator.html'); }); it('should calculate quadratic equation roots', () => { // Перевірка заголовка cy.get('h1').should('contain', 'Квадратне рівняння'); // Введення коефіцієнтів: x² - 5x + 6 = 0 cy.get('input[name="a"]').clear().type('1'); cy.get('input[name="b"]').clear().type('-5'); cy.get('input[name="c"]').clear().type('6'); // Натиснути кнопку "Обчислити" cy.get('button[type="submit"]').click(); // Перевірка результатів cy.get('#result').should('be.visible'); cy.get('#root1').should('contain', '3'); cy.get('#root2').should('contain', '2'); // Перевірка дискримінанту cy.get('#discriminant').should('contain', '1'); }); it('should show error for discriminant < 0', () => { cy.get('input[name="a"]').type('1'); cy.get('input[name="b"]').type('2'); cy.get('input[name="c"]').type('5'); cy.get('button[type="submit"]').click(); // Перевірка повідомлення про помилку cy.get('.error-message') .should('be.visible') .and('contain', 'Дискримінант менше нуля'); }); it('should reset form on Clear button', () => { cy.get('input[name="a"]').type('1'); cy.get('input[name="b"]').type('2'); cy.get('input[name="c"]').type('3'); cy.get('button#clear').click(); // Перевірка, що всі поля очищені cy.get('input[name="a"]').should('have.value', ''); cy.get('input[name="b"]').should('have.value', ''); cy.get('input[name="c"]').should('have.value', ''); }); });

Cypress Commands Cheat Sheet

// 🔍 Selectors cy.get('.class') // По класу cy.get('#id') // По ID cy.get('[data-test="btn"]') // По data атрибуту (рекомендовано) cy.contains('Text') // По тексту // 🖱️ Actions cy.click() // Клік cy.dblclick() // Подвійний клік cy.type('text') // Введення тексту cy.clear() // Очистити поле cy.check() // Вибрати checkbox/radio cy.select('option') // Вибрати option у select cy.scrollIntoView() // Прокрутити до елемента cy.trigger('mouseover') // Викликати подію // ✅ Assertions .should('be.visible') // Елемент видимий .should('exist') // Елемент існує в DOM .should('have.value', 'text') // Значення input .should('have.text', 'text') // Текст елемента .should('have.class', 'active') .should('have.attr', 'href', '/page') .should('contain', 'text') // Містить текст // Navigation cy.visit('/page') // Відкрити сторінку cy.go('back') // Назад cy.go('forward') // Вперед cy.reload() // Перезавантажити // ⏱️ Waits cy.wait(1000) // Чекати 1 сек cy.wait('@apiCall') // Чекати на API запит // 📸 Debugging cy.pause() // Пауза (тільки в Test Runner) cy.debug() // Debugger cy.screenshot('name') // Скріншот

Custom Commands

Створіть cypress/support/commands.js:

// Команда для логіну Cypress.Commands.add('login', (email, password) => { cy.visit('/login'); cy.get('input[name="email"]').type(email); cy.get('input[name="password"]').type(password); cy.get('button[type="submit"]').click(); cy.url().should('include', '/dashboard'); }); // Команда для перевірки toast повідомлення Cypress.Commands.add('checkToast', (message, type = 'success') => { cy.get(`.toast.${type}`) .should('be.visible') .and('contain', message); }); // Використання: // cy.login('user@example.com', 'password123'); // cy.checkToast('Login successful', 'success');

Частина 3: Playwright — сучасна альтернатива

1 Встановлення Playwright
# Встановлення з браузерами npm init playwright@latest # Вибрати: # - TypeScript або JavaScript # - Папка для тестів: tests # - GitHub Actions workflow: Yes # Запуск тестів npx playwright test # Запуск з UI mode npx playwright test --ui # Запуск у конкретному браузері npx playwright test --project=chromium # Debug mode npx playwright test --debug
2 Playwright Test Example

Створіть tests/calculator.spec.ts:

import { test, expect } from '@playwright/test'; test.describe('Scientific Calculator', () => { test.beforeEach(async ({ page }) => { await page.goto('https://scientific-calculators.com/calculators/quadratic-calculator.html'); }); test('solves quadratic equation', async ({ page }) => { // Fill form await page.fill('input[name="a"]', '1'); await page.fill('input[name="b"]', '-5'); await page.fill('input[name="c"]', '6'); // Submit await page.click('button[type="submit"]'); // Check results await expect(page.locator('#result')).toBeVisible(); await expect(page.locator('#root1')).toContainText('3'); await expect(page.locator('#root2')).toContainText('2'); }); test('shows error for negative discriminant', async ({ page }) => { await page.fill('input[name="a"]', '1'); await page.fill('input[name="b"]', '2'); await page.fill('input[name="c"]', '5'); await page.click('button[type="submit"]'); await expect(page.locator('.error-message')).toBeVisible(); await expect(page.locator('.error-message')).toContainText('Дискримінант менше нуля'); }); test('takes screenshot on failure', async ({ page }, testInfo) => { await page.fill('input[name="a"]', 'invalid'); await page.click('button[type="submit"]'); // Auto screenshot on failure await testInfo.attach('screenshot', { body: await page.screenshot(), contentType: 'image/png', }); }); });

Playwright Configuration

playwright.config.ts:

import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ testDir: './tests', fullyParallel: true, // Паралельні тести forbidOnly: !!process.env.CI, // Заборонити .only() в CI retries: process.env.CI ? 2 : 0, // 2 retry в CI workers: process.env.CI ? 1 : undefined, reporter: [ ['html'], ['junit', { outputFile: 'results.xml' }], ['json', { outputFile: 'results.json' }] ], use: { baseURL: 'https://scientific-calculators.com', trace: 'on-first-retry', // Trace при першому retry screenshot: 'only-on-failure', video: 'retain-on-failure', }, projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] }, }, { name: 'firefox', use: { ...devices['Desktop Firefox'] }, }, { name: 'webkit', use: { ...devices['Desktop Safari'] }, }, { name: 'Mobile Chrome', use: { ...devices['Pixel 5'] }, }, { name: 'Mobile Safari', use: { ...devices['iPhone 12'] }, }, ], });

Частина 4: CI/CD Integration

GitHub Actions для Cypress

name: Cypress E2E Tests on: push: branches: [main] pull_request: branches: [main] jobs: cypress-run: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Cypress run uses: cypress-io/github-action@v6 with: build: npm run build start: npm start wait-on: 'http://localhost:3000' wait-on-timeout: 120 browser: chrome record: true env: CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} - name: Upload screenshots uses: actions/upload-artifact@v3 if: failure() with: name: cypress-screenshots path: cypress/screenshots - name: Upload videos uses: actions/upload-artifact@v3 if: always() with: name: cypress-videos path: cypress/videos

GitHub Actions для Playwright

name: Playwright Tests on: push: branches: [main] pull_request: branches: [main] jobs: test: timeout-minutes: 60 runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - name: Install dependencies run: npm ci - name: Install Playwright Browsers run: npx playwright install --with-deps - name: Run Playwright tests run: npx playwright test - uses: actions/upload-artifact@v3 if: always() with: name: playwright-report path: playwright-report/ retention-days: 30

Частина 5: Best Practices

✅ Рекомендації для E2E тестів:
  1. Використовуйте data-test атрибути замість класів/ID:
    <button data-test="submit-btn">Send</button>
    cy.get('[data-test="submit-btn"]').click();
  2. Не використовуйте cy.wait(5000) — замість цього чекайте на елементи
  3. Тестуйте user flows, а не окремі функції
  4. Ізолюйте тести — кожен тест має бути незалежним
  5. Cleanup після тестів — видаляйте створені дані
  6. Page Object Model — використовуйте для великих проектів
  7. Паралельні тести — пришвидшують виконання
⚠️ Чого уникати:
  • ❌ Не тестуйте третійсторонні сервіси (mocкайте API)
  • ❌ Не робіть тести занадто деталізованими
  • ❌ Не забувайте про accessibility testing
  • ❌ Не ігноруйте flaky tests

Частина 6: Page Object Model (POM)

Що таке Page Object Model?

Page Object Model (POM) — це design pattern, де кожна сторінка/компонент представлений як JavaScript клас із методами для взаємодії з елементами.
  • DRY principle — уникання дублювання коду
  • Maintainability — легше оновлювати селектори в одному місці
  • Readability — тести стають більш читабельними

POM для Playwright

// pages/LoginPage.js export class LoginPage { constructor(page) { this.page = page; this.emailInput = page.locator('[data-test="email"]'); this.passwordInput = page.locator('[data-test="password"]'); this.loginButton = page.locator('[data-test="login-btn"]'); this.errorMessage = page.locator('.error-message'); } async goto() { await this.page.goto('/login'); } async login(email, password) { await this.emailInput.fill(email); await this.passwordInput.fill(password); await this.loginButton.click(); } async getErrorText() { return await this.errorMessage.textContent(); } } // tests/login.spec.js import { test, expect } from '@playwright/test'; import { LoginPage } from '../pages/LoginPage'; test('Successful login', async ({ page }) => { const loginPage = new LoginPage(page); await loginPage.goto(); await loginPage.login('user@test.com', 'password123'); await expect(page).toHaveURL('/dashboard'); });

POM для Cypress

// cypress/pages/CalculatorPage.js class CalculatorPage { visit() { cy.visit('/calculator'); } enterNumber(value) { cy.get('[data-test="number-input"]').type(value); return this; // Method chaining } selectOperation(operation) { cy.get(`[data-test="op-${operation}"]`).click(); return this; } calculate() { cy.get('[data-test="calc-btn"]').click(); return this; } getResult() { return cy.get('[data-test="result"]'); } } export default new CalculatorPage(); // cypress/e2e/calculator.cy.js import calculatorPage from '../pages/CalculatorPage'; describe('Calculator Tests', () => { it('Addition works', () => { calculatorPage .visit() .enterNumber('5') .selectOperation('add') .enterNumber('3') .calculate(); calculatorPage.getResult().should('have.text', '8'); }); });

Частина 7: Visual Regression Testing

Percy.io інтеграція

1 Налаштування Percy
  1. Signup на Percy.io
  2. Встановіть Percy SDK:
    npm install --save-dev @percy/cli @percy/cypress
  3. Додайте до cypress/support/e2e.js:
    import '@percy/cypress';
  4. Використовуйте cy.percySnapshot():
    it('Homepage visual test', () => { cy.visit('/'); cy.percySnapshot('Homepage'); });
  5. Запустіть з Percy:
    export PERCY_TOKEN=your_token npx percy exec -- cypress run

Playwright Built-in Screenshot Testing

// tests/visual.spec.js import { test, expect } from '@playwright/test'; test('Calculator visual regression', async ({ page }) => { await page.goto('/calculator'); // Перший запуск створює baseline screenshot await expect(page).toHaveScreenshot('calculator.png'); }); test('Button hover state', async ({ page }) => { await page.goto('/calculator'); await page.locator('[data-test="calc-btn"]').hover(); await expect(page).toHaveScreenshot('button-hover.png'); });
# Оновити baseline screenshots npx playwright test --update-snapshots
Інструмент Ціна Cross-browser AI diff detection
Percy $149-999/міс ✅ Chrome, Firefox, Safari, Edge ✅ Так
Playwright Screenshots Безкоштовно ✅ Chromium, Firefox, WebKit ⚠️ Pixel-perfect
Chromatic $149-499/міс ✅ Chrome-based ✅ Так
Applitools Custom pricing ✅ Всі браузери ✅ AI Visual AI

Частина 8: API Testing в E2E

Cypress API Testing

// cypress/e2e/api.cy.js describe('API Tests', () => { it('GET /api/calculator/:id', () => { cy.request('GET', '/api/calculator/123').then((response) => { expect(response.status).to.eq(200); expect(response.body).to.have.property('result'); expect(response.body.result).to.be.a('number'); }); }); it('POST /api/calculate', () => { cy.request({ method: 'POST', url: '/api/calculate', body: { operation: 'add', numbers: [5, 3] } }).then((response) => { expect(response.status).to.eq(200); expect(response.body.result).to.eq(8); }); }); it('API error handling', () => { cy.request({ method: 'POST', url: '/api/calculate', body: { invalid: 'data' }, failOnStatusCode: false // Не падати на 4xx/5xx }).then((response) => { expect(response.status).to.eq(400); expect(response.body.error).to.exist; }); }); });

Playwright API Context

// tests/api.spec.js import { test, expect } from '@playwright/test'; test('API request before page load', async ({ request }) => { // Створити дані через API const response = await request.post('/api/calculator', { data: { name: 'Test Calculator', value: 42 } }); expect(response.ok()).toBeTruthy(); const data = await response.json(); const calculatorId = data.id; // Тепер відкрити сторінку з цим ID await page.goto(`/calculator/${calculatorId}`); await expect(page.locator('h1')).toHaveText('Test Calculator'); }); test('Mock API response', async ({ page, route }) => { // Перехоплити API запити await route('**/api/calculator/**', route => { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ result: 999, mocked: true }) }); }); await page.goto('/calculator'); await page.click('[data-test="calc-btn"]'); await expect(page.locator('[data-test="result"]')).toHaveText('999'); });

Частина 9: Mobile Testing

Playwright Mobile Emulation

// playwright.config.js import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ projects: [ { name: 'Mobile Chrome', use: { ...devices['Pixel 5'] } }, { name: 'Mobile Safari', use: { ...devices['iPhone 13'] } }, { name: 'Tablet', use: { ...devices['iPad Pro'] } } ] }); // tests/mobile.spec.js test('Mobile menu works', async ({ page }) => { // Цей тест запуститься на Pixel 5, iPhone 13, iPad Pro await page.goto('/'); // Mobile hamburger menu await page.locator('[data-test="mobile-menu-btn"]').click(); await expect(page.locator('nav')).toBeVisible(); });

Cypress Viewport Testing

describe('Responsive Tests', () => { const sizes = [ [320, 568], // iPhone SE [375, 667], // iPhone 8 [414, 896], // iPhone 11 Pro Max [768, 1024], // iPad [1920, 1080] // Desktop ]; sizes.forEach((size) => { it(`Should work on ${size[0]}x${size[1]}`, () => { cy.viewport(size[0], size[1]); cy.visit('/calculator'); cy.get('[data-test="calc-btn"]').should('be.visible'); cy.get('[data-test="calc-btn"]').click(); }); }); });

Частина 10: Debugging Flaky Tests

Причини flaky tests

⚠️ Топ-5 причин нестабільних тестів:
  1. Race conditions — елемент з'являється пізніше ніж очікується
  2. Hardcoded timeoutscy.wait(5000) замість cy.get()
  3. Shared state — тести впливають один на одного
  4. External dependencies — API третіх сторін недоступний
  5. Non-deterministic data — випадкові дані або дати

Рішення для Flaky Tests

// ❌ ПОГАНО — hardcoded wait cy.wait(3000); // Може бути недостатньо або занадто багато cy.get('[data-test="result"]').should('have.text', '8'); // ✅ ДОБРЕ — чекати на елемент cy.get('[data-test="result"]', { timeout: 10000 }) .should('be.visible') .and('have.text', '8'); // ❌ ПОГАНО — залежність від попереднього тесту it('Create calculator', () => { cy.visit('/'); cy.get('[data-test="create"]').click(); // calculatorId зберігається в global scope }); it('Delete calculator', () => { // Використовує calculatorId з попереднього тесту cy.request('DELETE', `/api/calculator/${calculatorId}`); }); // ✅ ДОБРЕ — кожен тест незалежний beforeEach(() => { // Створити calculator перед кожним тестом cy.request('POST', '/api/calculator').then((response) => { cy.wrap(response.body.id).as('calculatorId'); }); }); it('Delete calculator', function() { cy.request('DELETE', `/api/calculator/${this.calculatorId}`); });

Playwright Trace Viewer

// playwright.config.js export default defineConfig({ use: { trace: 'retain-on-failure', // Зберігати trace тільки для failed tests screenshot: 'only-on-failure', video: 'retain-on-failure' } });
# Після failed test переглянути trace npx playwright show-trace test-results/example-spec-ts-example-test-chromium/trace.zip

Частина 11: Performance Testing в E2E

Lighthouse CI

1 Інтеграція Lighthouse CI
  1. Встановіть Lighthouse CI:
    npm install --save-dev @lhci/cli
  2. Створіть lighthouserc.json:
    { "ci": { "collect": { "url": ["http://localhost:3000"], "numberOfRuns": 3 }, "assert": { "assertions": { "categories:performance": ["error", {"minScore": 0.9}], "categories:accessibility": ["error", {"minScore": 0.9}], "categories:best-practices": ["error", {"minScore": 0.9}], "categories:seo": ["error", {"minScore": 0.9}] } } } }
  3. Запустіть у CI:
    # .github/workflows/ci.yml - name: Run Lighthouse CI run: | npm run build npm run start & npx lhci autorun

Playwright Performance Metrics

test('Page load performance', async ({ page }) => { await page.goto('/calculator'); const metrics = await page.evaluate(() => { const navigation = performance.getEntriesByType('navigation')[0]; return { domContentLoaded: navigation.domContentLoadedEventEnd - navigation.domContentLoadedEventStart, load: navigation.loadEventEnd - navigation.loadEventStart, firstPaint: performance.getEntriesByName('first-paint')[0]?.startTime || 0, firstContentfulPaint: performance.getEntriesByName('first-contentful-paint')[0]?.startTime || 0 }; }); console.log('Performance Metrics:', metrics); expect(metrics.firstContentfulPaint).toBeLessThan(2000); // < 2s expect(metrics.load).toBeLessThan(5000); // < 5s });

Частина 12: Advanced Reporting

Allure Report для Playwright

npm install --save-dev @playwright/test allure-playwright allure-commandline
// playwright.config.js export default defineConfig({ reporter: [ ['list'], ['allure-playwright', { resultsDir: 'allure-results', detail: true }] ] });
// tests/example.spec.js import { test, expect } from '@playwright/test'; import { allure } from 'allure-playwright'; test('Calculator with Allure', async ({ page }) => { await allure.description('Тестування калькулятора додавання'); await allure.owner('QA Team'); await allure.tags('calculator', 'math', 'smoke'); await allure.severity('critical'); await allure.step('Open calculator page', async () => { await page.goto('/calculator'); }); await allure.step('Enter numbers', async () => { await page.fill('[data-test="num1"]', '5'); await page.fill('[data-test="num2"]', '3'); }); await allure.step('Calculate result', async () => { await page.click('[data-test="calc-btn"]'); }); await allure.step('Verify result', async () => { await expect(page.locator('[data-test="result"]')).toHaveText('8'); }); await allure.attachment('Screenshot', await page.screenshot(), 'image/png'); });
# Генерувати та відкрити Allure report npx playwright test npx allure generate allure-results --clean -o allure-report npx allure open allure-report

Mochawesome для Cypress

npm install --save-dev mochawesome mochawesome-merge mochawesome-report-generator
// cypress.config.js module.exports = { reporter: 'mochawesome', reporterOptions: { reportDir: 'cypress/results', overwrite: false, html: true, json: true } };
// package.json { "scripts": { "test:e2e": "cypress run", "test:report": "mochawesome-merge cypress/results/*.json -o cypress/results/merged.json && marge cypress/results/merged.json --reportDir cypress/reports" } }

Висновок

E2E тестування — обов'язковий елемент якісного веб-додатку:

🚀 Рекомендований workflow:
  1. Почніть з Cypress для швидкого прототипування
  2. Переходьте на Playwright для production
  3. Інтегруйте E2E у CI/CD pipeline
  4. Налаштуйте паралельне виконання
  5. Додайте визуальне регресійне тестування

Як користуватися шпаргалкою

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

Ефективне використання

Використовуйте шпаргалку поряд з розв'язуванням задач — не для списування, а як довідник формул. Спершу спробуйте пригадати формулу самостійно, потім звіртеся з довідником. Регулярне повторення формує стійку пам'ять.

Часті запитання (FAQ)

Які ключові формули та правила містить шпаргалка з end-to-end (e2e) testing?
Ця шпаргалка з 'End-to-End (E2E) Testing' включає: основні означення, головні формули у компактному вигляді, правила обчислень, типові підстановки та приклади застосування. Все систематизовано для швидкого пошуку.
Для кого призначена ця шпаргалка з end-to-end (e2e) testing?
Шпаргалка з 'End-to-End (E2E) Testing' орієнтована на студентів університетів та учнів старшої школи, а також на всіх, хто хоче швидко освіжити знання перед іспитом або при вирішенні практичних задач.
Як використовувати шпаргалку з end-to-end (e2e) testing при підготовці до іспиту?
Оптимальна стратегія: спершу вивчіть теорію, потім використовуйте шпаргалку як довідник при розв'язанні задач. За 1–2 дні до іспиту перегляньте шпаргалку цілком, звертаючи увагу на формули, які ви плутаєте.
Чи охоплює ця шпаргалка всю програму курсу з end-to-end (e2e) testing?
Шпаргалка з 'End-to-End (E2E) Testing' охоплює стандартну університетську програму: всі ключові теореми, формули та методи. Матеріал структурований від базових понять до просунутих результатів.
Де ще можна попрактикуватися з end-to-end (e2e) testing після вивчення шпаргалки?
Після роботи зі шпаргалкою рекомендуємо: тренажери вправ на calculator.party (миттєвий зворотний зв'язок), розв'язані задачі (показують метод покроково) та онлайн-калькулятори для перевірки власних результатів.