QA Interview Hub · База знань · Тести
Cypress
Додаткові питання з типових списків
хуки, асерти, Shadow DOM, дебаг
Які хуки є в Cypress і як вони працюють?
Хуки беруться з Mocha: before — один раз перед усіма тестами блоку, beforeEach — перед кожним тестом, afterEach — після кожного, after — один раз після всіх. Хуки в cypress/support/e2e.ts діють глобально на всі спеки.
Порада від самої команди Cypress: прибирання краще робити в beforeEach, а не в afterEach. Якщо тест упав або ти зупинив його в Test Runner, afterEach може не виконатися, і наступний тест стартує з брудним станом.
describe('Кошик', () => {
beforeEach(() => {
cy.request('DELETE', '/api/cart'); // чистий стан ДО тесту
cy.login();
cy.visit('/cart');
});
it('порожній кошик', () => {
cy.contains('Кошик порожній').should('be.visible');
});
});
На співбесіді: Хуки беруться з Mocha: before і after — один раз на блок, beforeEach і afterEach — для кожного тесту. Підготовку і прибирання стану я роблю в beforeEach, бо afterEach може не виконатися, якщо тест упав, і тоді наступний стартує з брудним станом.
А в Playwright:Є такі самі хуки (test.beforeEach, test.afterAll…), але підготовку й прибирання зазвичай виносять у фікстури: код після await use() виконується навіть при падінні тесту.
Які типи асертів підтримує Cypress?
- Chai BDD —
expect(x).to.eq(), .to.include(), .to.have.length().
- Chai TDD —
assert.equal(), assert.isTrue().
- Chai-jQuery — асерти стану DOM:
be.visible, have.class, have.text, be.checked.
- Sinon-Chai — для шпигунів і заглушок:
be.called, calledWith.
Два стилі використання: неявний через .should('have.text', 'X') — ретраїться; явний через expect усередині .then — виконується один раз, а всередині .should(cb) — ретраїться.
На співбесіді: Cypress використовує Chai у стилях BDD і TDD, Chai-jQuery для перевірок стану DOM і Sinon-Chai для стабів і шпигунів. Важливіше за перелік — різниця між неявними асертами через should, які ретраяться, і явними expect у then, які виконуються один раз.
Як працювати з Shadow DOM?
За замовчуванням cy.get не заходить усередину shadow root. Два способи:
- Точково — команда
.shadow(), яка переходить у shadow root елемента.
- Глобально —
includeShadowDom: true у конфігу, тоді всі запити проходять крізь shadow-межі.
cy.get('payment-widget').shadow().find('[data-cy=pay]').click();
// або в cypress.config.ts
// e2e: { includeShadowDom: true }
На співбесіді: За замовчуванням Cypress не бачить вміст shadow root. Точково я переходжу туди командою shadow, а якщо компонентів з Shadow DOM багато, вмикаю includeShadowDom у конфігу.
А в Playwright:У Playwright локатори проходять крізь відкритий Shadow DOM за замовчуванням — нічого вмикати не треба.
Як зробити hover і drag-and-drop?
Нативного hover у Cypress немає: .trigger('mouseover') викликає JS-подію, але не CSS-стан :hover. Якщо меню показується лише через CSS, допоможе .invoke('show') або плагін cypress-real-events, який генерує справжні події браузера.
Drag-and-drop — ланцюжок подій через .trigger. Якщо бібліотека працює на HTML5 drag API, потрібні dragstart, drop і dataTransfer, і тут теж часто беруть плагін.
cy.get('[data-cy=menu]').trigger('mouseover');
cy.get('[data-cy=card]')
.trigger('mousedown', { button: 0 })
.trigger('mousemove', { clientX: 400, clientY: 200 })
.trigger('mouseup');
На співбесіді: Hover і drag-and-drop робляться через trigger з потрібними подіями миші. Але trigger викликає лише JS-події, а не справжній CSS-стан hover, тому для таких випадків я використовую плагін cypress-real-events.
А в Playwright:Вбудовано і через справжні події браузера: locator.hover() і locator.dragTo(target).
Чим cy.exec відрізняється від cy.task?
Обидві команди виконують щось поза браузером, у Node-процесі.
cy.exec('команда') запускає shell-команду: скрипт сідування бази, міграцію, npm run. Повертає код виходу, stdout і stderr.
cy.task('назва') викликає Node-функцію, яку ти зареєстрував у setupNodeEvents: запит до БД через бібліотеку, роботу з файлами, генерацію даних. Повертає будь-яке значення.
Правило вибору: є готовий скрипт — cy.exec; потрібна логіка й повернення даних у тест — cy.task.
cy.exec('npm run db:seed').its('exitCode').should('eq', 0);
cy.task('db:query', 'SELECT count(*) FROM pets').its('0.count').should('eq', '5');
На співбесіді: Обидві працюють у Node. cy.exec запускає shell-команду, наприклад скрипт сідування бази, і повертає код виходу та вивід. cy.task викликає Node-функцію, яку я зареєстрував у конфігу, і повертає дані в тест — так я роблю запити до бази.
А в Playwright:Аналоги не потрібні: тест і так у Node, тож shell-команду запускають через child_process, а БД викликають напряму.
Які Node-події є в Cypress, наприклад after:run?
Це хуки рівня всього запуску, а не тесту. Вони реєструються в setupNodeEvents і виконуються в Node:
before:run / after:run — до і після всього cypress run; after:run отримує підсумки.
before:spec / after:spec — навколо кожного спек-файлу; after:spec часто використовують, щоб видалити відео тестів, які пройшли.
before:browser:launch — налаштувати браузер: прапорці, розширення, розмір вікна.
after:screenshot — обробити або перейменувати скріншот.
setupNodeEvents(on) {
on('after:run', (results) => {
if ('totalFailed' in results) {
console.log('Упало тестів:', results.totalFailed);
}
});
}
На співбесіді: Це події рівня запуску, які я реєструю в setupNodeEvents. After:run спрацьовує після всього прогону і отримує підсумки — зручно для звітів чи сповіщень. After:spec — після кожного файлу, before:browser:launch дозволяє налаштувати браузер.
А в Playwright:Аналоги — globalSetup / globalTeardown у конфігу або setup-проєкт; підсумки прогону — у власному репортері через onEnd.
Як контролювати порядок запуску спеків?
Через specPattern як масив шляхів у потрібному порядку, або через --spec у CLI. Але правильна частина відповіді — пояснити, що залежність тестів від порядку сама по собі проблема: такі тести ламаються при паралельному розбитті, перезапуску одного тесту або retries.
Якщо сценарію потрібні дані з попереднього кроку, їх готують через API в beforeEach, а не через інший тест.
specPattern: [
'cypress/e2e/login.cy.ts',
'cypress/e2e/checkout.cy.ts',
],
На співбесіді: Технічно порядок можна задати масивом у specPattern. Але я намагаюся, щоб тести від порядку не залежали, бо такі тести ламаються при паралельному запуску і повторах. Потрібні дані я створюю через API перед кожним тестом.
А в Playwright:Ті самі принципи, але порядок за замовчуванням ще менш передбачуваний через воркери; для свідомо послідовних сценаріїв є test.describe.configure({ mode: 'serial' }).
Які браузери й ОС підтримує Cypress?
Браузери: сімейство Chrome (Chrome, Chromium, Edge, вбудований Electron), Firefox і WebKit (рушій Safari) — експериментально. Офіційно підтримуються три останні мажорні версії. Internet Explorer, Opera і справжній Safari — ні, мобільні браузери й нативні застосунки — теж ні.
ОС: Windows, macOS і Linux з актуальними версіями; Node.js — підтримувані LTS-версії. Точні мінімальні версії перевіряй у документації перед співбесідою — вони змінюються з кожним великим релізом.
На співбесіді: Cypress працює з браузерами сімейства Chrome, включно з Edge і Electron, з Firefox і експериментально з WebKit. Справжнього Safari, мобільних браузерів і нативних застосунків немає — це одне з головних обмежень порівняно з Playwright чи Appium.
А в Playwright:Playwright підтримує Chromium, Firefox і WebKit повноцінно, плюс емуляцію мобільних пристроїв, але теж без нативних мобільних застосунків.
Як дебажити тести в Cypress?
- Time-travel: у
cypress open наведи на команду в Command Log — побачиш знімок DOM у той момент.
cy.pause() зупиняє виконання; далі можна крокувати по командах.
.debug() зупиняє в DevTools з поточним subject (DevTools мають бути відкриті).
cy.log() пише в Command Log; cy.task('log', ...) — у термінал CI.
- Клік по команді в Command Log виводить у консоль деталі: subject, елементи, запит і відповідь.
- У CI: скріншоти, відео (якщо ввімкнене) і Test Replay у Cloud.
cy.get('[data-cy=total]').debug();
cy.pause();
cy.get('[data-cy=checkout]').click();
На співбесіді: Локально я використовую time-travel у Command Log, cy.pause, щоб зупинити тест і йти покроково, і debug, щоб подивитися subject у DevTools. Клік по команді в лозі показує в консолі всі деталі. У CI дивлюся скріншоти, відео і логи, які виводжу через cy.task.
А в Playwright:Аналоги: page.pause(), npx playwright test --debug з інспектором, UI mode (--ui) і Trace Viewer для CI.
Як працювати з URL, навігацією і браузерною історією?
cy.url() — повний URL як рядок.
cy.location() — об'єкт з pathname, search, hash; зручно перевіряти частини.
cy.go('back') / cy.go('forward') — кнопки «назад» і «вперед».
cy.reload() — перезавантаження сторінки.
Усі вони — queries або команди з ретраями, тож асерти на URL самі чекають навігацію.
cy.location('pathname').should('eq', '/statistics');
cy.location('search').should('include', 'period=30d');
cy.go('back');
cy.url().should('include', '/dashboard');
На співбесіді: Для URL є cy.url і cy.location — другий зручніший, бо можна перевірити окремо шлях чи параметри. Для історії — cy.go back і forward, для оновлення — cy.reload. Асерти на URL ретраяться, тож вони самі дочекаються навігації.
А в Playwright:await expect(page).toHaveURL(/statistics/), page.goBack(), page.goForward(), page.reload().