QA Interview Hub · База знань · Тести

Cypress

Основи й архітектура

як влаштований фреймворк

Що таке Cypress і чим він відрізняється від Selenium?

Cypress — фреймворк для end-to-end і компонентного тестування вебзастосунків на JavaScript або TypeScript.

Головна різниця в тому, де живе тест. Selenium керує браузером ззовні через WebDriver: кожна команда — окремий HTTP-запит до драйвера. Cypress виконує тест усередині браузера, в тій самій вкладці, що й застосунок.

Звідси переваги: прямий доступ до DOM і window, автоматичні очікування, time-travel по кроках у Test Runner і вбудований перехоплювач мережі. Під капотом Cypress використовує Mocha для структури тестів (describe, it, хуки), Chai для асертів і Sinon для cy.stub, cy.spy і cy.clock.

На співбесіді: Cypress — це фреймворк для e2e і компонентного тестування на JavaScript. Головна відмінність від Selenium в архітектурі: Selenium керує браузером ззовні через WebDriver, де кожна команда — окремий HTTP-запит, а Cypress виконує тести прямо в браузері, поруч із застосунком. Тому він має прямий доступ до DOM, сам чекає на елементи, дає time-travel для дебагу й уміє перехоплювати мережу. Всередині він побудований на Mocha, Chai і Sinon.
А в Playwright:

Playwright теж обходиться без WebDriver, але працює протилежно до Cypress: керує браузером ззовні через одне постійне з'єднання і рідний протокол браузера (CDP для Chromium, патчені протоколи для Firefox і WebKit). Тести можна писати не лише на JS/TS, а й на Python, Java і .NET.

Як влаштована архітектура Cypress під капотом?

Cypress складається з двох частин, які постійно спілкуються.

  • Node-процес. Запускає браузер, працює як проксі для всього HTTP-трафіку сторінки, виконує cy.task (файли, база даних), робить скріншоти й відео.
  • Браузер. Сторінка Cypress містить два iframe: spec iframe з твоїм тестовим кодом і app iframe із застосунком. Оскільки вони в одній вкладці, тест бачить DOM застосунку напряму, без протоколу посередині.

Між Node-процесом і браузером — WebSocket. Саме проксі в Node дає змогу cy.intercept бачити і підміняти кожен запит.

┌──────────── Браузер (одна вкладка) ────────────┐
│  spec iframe            │  app iframe           │
│  тест + черга cy        │  застосунок           │
│  прямий доступ до DOM ──┼──►                    │
└──────────────┬──────────────────────────────────┘
               │ WebSocket + HTTP через проксі
┌──────────────▼──────────────────────────────────┐
│  Node-процес Cypress                            │
│  проксі (cy.intercept) · cy.task · файли · відео│
└─────────────────────────────────────────────────┘
На співбесіді: Cypress працює як два процеси. Перший — Node-процес: він запускає браузер, пропускає через себе весь мережевий трафік як проксі й виконує все, чого не вміє браузер, наприклад роботу з файлами чи базою через cy.task. Другий — сам браузер, де в одній вкладці живуть два iframe: в одному мій тест, у другому застосунок. Тому тест має прямий доступ до DOM. Між Node і браузером — WebSocket, а саме проксі дає змогу перехоплювати запити через cy.intercept.
А в Playwright:

У Playwright немає iframe з тестом поруч із застосунком. Тест живе в Node, Playwright-сервер шле команди браузеру через протокол. Тому тест не має прямого доступу до DOM (лише через page.evaluate), зате без обмежень працює з кількома вкладками, доменами й контекстами.

Чим cypress open відрізняється від cypress run?

cypress open відкриває інтерактивний Test Runner: вибираєш спек, бачиш кожну команду, можеш повернутися до будь-якого кроку (time-travel), а тест перезапускається після збереження файлу. Це режим для написання й дебагу.

cypress run запускає тести без інтерфейсу, за замовчуванням headless в Electron, з виводом у консоль і скріншотами при падінні. Це режим для CI.

npx cypress open                        # інтерактивно
npx cypress run                         # headless, Electron
npx cypress run --browser chrome        # конкретний браузер
npx cypress run --spec "cypress/e2e/login.cy.ts"
npx cypress run --headed                # з вікном браузера
На співбесіді: Open — це інтерактивний режим для розробки: я бачу кожну команду, можу повернутися до будь-якого кроку і тест перезапускається при збереженні. Run — це headless-запуск для CI: без інтерфейсу, з виводом у консоль і скріншотами при падінні. У run можна вказати браузер, конкретний спек або запустити в headed-режимі.
А в Playwright:

Аналог — npx playwright test, headless за замовчуванням. Замість Test Runner є --ui (UI mode з таймлайном і DOM-знімками), --debug з інспектором і --headed. Браузери обирають через --project, а не --browser.

Як виглядає структура проєкту і конфіг Cypress?

З версії 10 конфіг живе у файлі cypress.config.js або .ts. Старий cypress.json більше не використовується — якщо згадаєш його як поточний, це видасть застарілі знання.

Типова структура: cypress/e2e для тестів, cypress/fixtures для тестових даних, cypress/support для кастомних команд і глобальних налаштувань.

// cypress.config.ts
import { defineConfig } from 'cypress';

export default defineConfig({
  e2e: {
    baseUrl: 'https://staging.example.com',
    specPattern: 'cypress/e2e/**/*.cy.ts',
    defaultCommandTimeout: 6000,
    retries: { runMode: 2, openMode: 0 },
    setupNodeEvents(on, config) {
      // cy.task, плагіни, звіти
      return config;
    },
  },
});

// cypress/
//   e2e/          тести *.cy.ts
//   fixtures/     JSON з тестовими даними
//   support/
//     e2e.ts      виконується перед кожним спеком
//     commands.ts кастомні команди
На співбесіді: Починаючи з десятої версії конфіг пишеться у cypress.config.ts через defineConfig, з окремими блоками для e2e і component testing. Там задаються baseUrl, шаблон пошуку спеків, таймаути, retries і setupNodeEvents для Node-логіки. Тести лежать у папці e2e, тестові дані — у fixtures, а кастомні команди й глобальні налаштування — у support.
А в Playwright:

Конфіг — playwright.config.ts. Замість окремих блоків e2e і component там projects: різні браузери, девайси, setup-проєкт для логіну. Папки support немає: спільна логіка живе у фікстурах через test.extend.

Чим e2e-тести відрізняються від component testing у Cypress?

E2E відкриває весь застосунок через cy.visit і проходить сценарій як користувач, з реальним бекендом або моками мережі.

Component testing монтує один компонент React, Vue чи Angular через cy.mount у справжньому браузері, без решти застосунку. Це швидко й ізольовано: зручно перевіряти стани кнопки, форми чи таблиці з різними props, не піднімаючи весь фронтенд.

// component test
import { PriceTag } from './PriceTag';

it('показує знижку', () => {
  cy.mount(<PriceTag price={100} discount={20} />);
  cy.get('[data-cy=final-price]').should('have.text', '80');
});
На співбесіді: E2E-тест відкриває весь застосунок і проходить сценарій як користувач. Component testing монтує окремий компонент через cy.mount у справжньому браузері, без решти застосунку і без бекенду. Це набагато швидше і зручно для перевірки різних станів компонента, а e2e лишається для ключових наскрізних сценаріїв.
А в Playwright:

У Playwright component testing досі експериментальний (@playwright/experimental-ct-react та аналоги). Для компонентних тестів Cypress зараз зріліший.

Архітектура Cypress і порівняння

Cypress виконує тести всередині браузера, в тому ж run loop, що й застосунок, а поруч працює Node.js-процес для задач поза браузером. Selenium і Playwright керують браузером ззовні: Selenium через WebDriver, Playwright через CDP та власні протоколи. Через таку архітектуру Cypress має прямий доступ до DOM, window і мережевих запитів застосунку.

Переваги: зручний інтерактивний раннер з time-travel знімками кожного кроку, вбудовані ретраї й очікування, простий старт, cy.intercept для мережі, component testing. Обмеження: лише JavaScript/TypeScript, одна вкладка, складніша робота з iframe та кількома доменами, немає підтримки Safari (лише експериментальний WebKit).

Playwright швидший, має вбудовану паралелізацію без платного сервісу, кілька вкладок і контекстів, мови крім JS. Паралелізація в Cypress можлива, але зазвичай через Cypress Cloud або сторонні рішення на кшталт шардингу в CI.