Підтримка CSS та XPATH у Cypress
Фреймворк Cypress має розширений набір можливостей для вибору елементів за допомогою CSS селекторів. Ці можливості дозволяють зручно та ефективно здійснювати вибір елементів на веб-сторінці для подальших дій (наприклад, клік, введення тексту, перевірка стану тощо). Ось деякі з основних методів вибору елементів за допомогою CSS селекторів у Cypress:
cy.get()
Цей метод використовується для отримання елементів на сторінці.
Використання CSS селекторів:
cy.get('.my-class'); // Вибір за класом
cy.get('#myId'); // Вибір за ідентифікатором
cy.get('button'); // Вибір кнопки
cy.get('[data-testid=myTestId]'); // Вибір за атрибутом
cy.get('ul li'); // Вибір вкладеного елементу
cy.contains()
Цей метод шукає елемент з текстовим вмістом, що відповідає вказаному шаблону.
Використання CSS селекторів з текстом:
cy.contains('.my-class', 'Text'); // Елемент з вказаним текстом та класом
cy.contains('a', 'Link Text'); // Посилання з вказаним текстом
cy.contains('[data-testid=myTestId]', 'Content'); // Елемент за атрибутом та текстом
Комбінування CSS селекторів
За допомогою комбінації CSS селекторів ви можете використовувати більш складні вирази для вибору конкретних елементів.
Приклади комбінованого вибору:
cy.get('.parent-class .child-class'); // Вибір вкладеного елементу
cy.get('.parent-class > .child-class'); // Вибір прямого дочірнього елементу
cy.get('.my-class, #myId'); // Вибір за декількома селекторами
cy.get('ul li:nth-child(2)'); // Вибір другого елементу списку ul
Ці методи дозволяють ефективно вибирати елементи за допомогою CSS селекторів у Cypress, надаючи можливість шукати та взаємодіяти з елементами на сторінці для тестування вашого веб-додатку.
Фреймворк Cypress не надає вбудованої підтримки для використання XPath-селекторів напряму для вибору елементів на веб-сторінці. Однак, багато засобів вибору елементів, доступних у CSS, також можуть бути використані в Cypress. Враховуючи це, найбільш рекомендованим методом для вибору елементів в Cypress є використання CSS-селекторів, оскільки вони є основним інструментом для вибору елементів в цьому фреймворку.
Якщо ви хочете використовувати XPath-селектори, ви можете скористатися сторонніми бібліотеками для цього. Одним з прикладів є cypress-xpath, плагін для Cypress, який надає підтримку для використання XPath-селекторів у ваших тестах. Цей плагін дозволяє вам використовувати XPath для вибору елементів у вашому Cypress-коді. Однак слід зазначити, що цей плагін є deprecated, тобто більше не підтримується розробниками.
Щоб використати cypress-xpath, встановіть його у ваш проект Cypress, використовуючи npm:
npm install -D cypress-xpath
Після встановлення додайте наступний код у вашому cypress/support/e2e.js файлі для налаштування плагіну:
import 'cypress-xpath';
Документація: https://docs.cypress.io/app/core-concepts/writing-and-organizing-tests#Support-file
Тепер ви зможете використовувати функції, які надає cypress-xpath, для вибору елементів за допомогою XPath-селекторів у ваших тестах Cypress. Наприклад:
cy.xpath('//button[contains(text(),"Submit")]').click();
Однак, слід зауважити, що використання XPath може бути менш ефективним порівняно з CSS-селекторами у Cypress, тому рекомендується використовувати XPath лише у випадках, коли ви не можете досягти потрібного елемента за допомогою CSS-селекторів.
Пошук елементів у Cypress
У фреймворку Cypress для пошуку та взаємодії з елементами на веб-сторінці існують різні методи (querying). Ось основні методи, які ви можете використовувати для пошуку елементів в Cypress:
- get – обирає один або кілька елементів DOM за допомогою селектора або аліаса.
Ситнаксис:
cy.get(селектор)
cy.get(аліас)
cy.get(селектор, опції)
cy.get(аліас, опції)
Коректне використання:
cy.get('.list > li') // знайде елементи <li> у елементі з класом .list
Детальну інформацію про варіанти застосування та опціі можна знайти тут.
2.find – обирає нащадкові елементи DOM певного селектора.
Ситнаксис:
.find(селектор)
.find(селектор, опції)
Коректне використання:
cy.get('.article').find('footer') // знаходить'footer', який є нащадком елемента з класом '.article'
Детальну інформацію про варіанти застосування та опціі можна знайти тут.
3.contains – обирає елемент DOM, що містить текст (співпадіння враховується за частиною тексту також, тобто універсальний метод). Додатково може бути викликаний на батьківському елементі, по аналогії з find. Важливо вказати, що буде знайдено не всі елементи (як у випадку з get або find), а тільки перший, який буде задовольняти критерії пошуку.
Ситнаксис:
cy.contains(контент)
cy.contains(контент, опції)
cy.contains(селектор, контент)
cy.contains(селектор, контент, опції)
// ---або---
.contains(контент)
.contains(контент, опції)
.contains(селектор, контент)
.contains(селектор, контент, опції)
Коректне використання:
cy.get('.nav').contains('About') // Знаходить елемент з текстом 'About', який є дочірнім елементу з класом .nav
cy.contains('Hello') // Знаходить перший елемент з текстом 'Hello'
Детальну інформацію про варіанти застосування та опціі можна знайти тут.
4.children – обирає дочірні елементи кожного елемента DOM, який задовольняє критерії пошуку.
Ситнаксис:
.children()
.children(селектор)
.children(опції)
.children(селектор, опції)
Коректне використання:
cy.get('nav').children() // знаходить елементи, які є дочірніми для елемента nav
Детальну інформацію про варіанти застосування та опціі можна знайти тут.
5.closest – обирає перший елемент DOM, який відповідає селектору (незалежно від того, чи він сам, чи один із його предків).
Ситнаксис:
.closest(селектор)
.closest(селектор, опції)
Коректне використання:
cy.get('td').closest('.filled') // знайде найближчий до td елемент з классом .filled
Детальну інформацію про варіанти застосування та опціі можна знайти тут.
6.focused – обирає елемент DOM, який зараз у фокусі.
Ситнаксис:
cy.focused()
cy.focused(опції)
Коректне використання:
cy.focused() // знаходить фокусований елемент
Детальну інформацію про варіанти застосування та опціі можна знайти тут.
7.invoke – викликає функцію для попередньо отриманого елемента (якщо в ньому є функціональні вирази).
Ситнаксис:
.invoke(функція)
.invoke(опції, функція)
.invoke(функція, args...)
.invoke(опції, функція, args...)
Коректне використання:
cy.get('.input').invoke('val').should('eq', 'foo') // викликає 'val' функцію елемента з классом .input
cy.get('.modal').invoke('show') // викликає jQuery 'show' функцію елемента з классом .modal
cy.wrap({ animate: fn }).invoke('animate') // викликає 'animate' функцію
Детальну інформацію про варіанти застосування та опціі можна знайти тут.
8.its – викликає значення властивості отриманого елементу.
Ситнаксис:
.its(властивість)
.its(властивість, опції)
Коректне використання:
cy.wrap({ width: '50' }).its('width') // повертає властивість 'width'
cy.window().its('sessionStorage') // повертає властивість 'sessionStorage'
Детальну інформацію про варіанти застосування та опціі можна знайти тут.
9.parent – обирає батьківський елемент.
Ситнаксис:
.parent()
.parent(селектор)
.parent(опції)
.parent(селектор, опції)
Коректне використання:
cy.get('header').parent() // обирає елемент, який є батьківським для елементу `header`
Детальну інформацію про варіанти застосування та опціі можна знайти тут.
10.prev – обирає безпосередньо попередній “братський” елемент.
Ситнаксис:
.prev()
.prev(селектор)
.prev(опції)
.prev(селектор, опції)
Коректне використання:
cy.get('tr.highlight').prev() // обирає попередній братьский елемент до елементу 'tr'
Детальну інформацію про варіанти застосування та опціі можна знайти тут.
11.siblings – обирає “споріднені” елементи.
Ситнаксис:
.siblings()
.siblings(селектор)
.siblings(опції)
.siblings(селектор, опції)
Коректне використання:
cy.get('td').siblings() // обирає всі споріднені елементи до елементу td
cy.get('li').siblings('.active') // обирає всі споріднені елементи до елементу li з класом '.active'
Детальну інформацію про варіанти застосування та опціі можна знайти тут.
12.title – отримує властивість document.title сторінки, яка зараз активна.
Ситнаксис:
cy.title()
cy.title(опції)
Коректне використання:
cy.title() // повертає document.title як string
Детальну інформацію про варіанти застосування та опціі можна знайти тут.
Фільтрація елементів у Cypress
Фільтрація елементів у Cypress дозволяє вам вибирати певні елементи на сторінці за допомогою різних умов або критеріїв. В Cypress використовуються методи, такі як filter(), find(), та інші, щоб вибрати конкретні елементи для подальших взаємодій або перевірок.
Ось декілька прикладів реалізації фільтрації елементів у Cypress:
1. Використання filter()
:
// Вибрати всі елементи з класом 'my-class'
cy.get('.my-class').filter(':visible').click(); // Натискання на видимий елемент
2. Використання find() для фільтрації вкладених елементів:
// Знайти батьківський елемент та вибрати вкладені елементи за умовою
cy.get('.parent-element').find('.child-element').should('have.length', 3);
3. Фільтрація за текстом елемента:
// Вибрати елемент за текстом
cy.contains('Кнопка').click();
4. Фільтрація за індексом елемента:
// Вибрати елемент за індексом
cy.get('ul li').eq(2).should('have.text', 'Третій елемент');
5. Використання фільтрації за атрибутом:
// Вибрати елемент з певним значенням атрибуту
cy.get('[data-testid="submit-button"]').click();
6. Фільтрація за станом елемента:
// Вибрати вимкнений елемент
cy.get('input').filter(':disabled').should('have.length', 1);
7.Використання not():
// Приклад: вибрати всі елементи з класом 'item', які НЕ мають класу 'hidden'
cy.get('.item').not('.hidden').should('exist');
// Вибрати всі чекбокси, які НЕ є вибраними
cy.get('input[type="checkbox"]').not(':checked').check();
Ці приклади показують різні способи фільтрації елементів у Cypress в залежності від ваших потреб та вимог тесту.
Важливо пам’ятати, що Cypress робить автоматичне очікування, тому вам не потрібно вручну додавати затримки або чекати на завантаження елементів.
Аліаси
В Cypress, аліаси (aliases) є потужним інструментом для покращення читабельності та підтримки вашого коду тестів. Аліаси дозволяють вам надавати імена елементам і секціям вашого тесту, щоб потім легко посилатися на них в інших частинах тесту без повторення коду.
Ось як використовувати аліаси у Cypress:
1. Створення аліасу:
Ви можете створити аліас за допомогою методу as() при використанні команди cy.get():
// Створення аліасу для елементу
cy.get('.login-button').as('loginButton');
2. Використання аліасу:
Тепер ви можете використовувати цей аліас у інших частинах вашого тесту:
// Використання аліасу для кліку
cy.get('@loginButton').click();
3. Використання аліасу в команді should:
Аліас також можна використовувати в командах should, щоб виконати перевірки на елементі:
// Використання аліасу в команді should
cy.get('@loginButton').should('be.visible');
4. Повторне використання аліасу в різних частинах тесту:
Аліаси зручно використовувати в тих випадках, коли вам потрібно взаємодіяти з одним і тим же елементом в різних частинах тесту. Наприклад:
// Створення аліасу для поля вводу
cy.get('.username-input').as('usernameInput');
// Введення тексту в поле вводу
cy.get('@usernameInput').type('john_doe');
// Використання аліасу при очікуванні
cy.get('@usernameInput').should('have.value', 'john_doe');
5. Перевірка багаторазового використання аліасів:
Можна створювати багаторазові аліаси та використовувати їх для різних елементів:
// Створення аліасу для кнопки "Вхід"
cy.get('.login-button').as('loginButton');
// Створення аліасу для поля вводу ім'я користувача
cy.get('.username-input').as('usernameInput');
// Використання аліасів у різних частинах тесту
cy.get('@usernameInput').type('john_doe');
cy.get('@loginButton').click();
Використання аліасів в тестах Cypress може робити ваш код більш зрозумілим, покращувати його підтримку та робити тести менш залежними від конкретної реалізації сторінки.
Тут більш детальний опис роботи з аліасами.
Робота з множинними елементами, ітерації
Робота з множинними елементами на сторінці в Cypress може включати в себе ітерацію по цим елементам та взаємодію з кожним елементом окремо. Для цього можна використовувати методи Cypress, такі як each(), its(), та інші. Ось детальний опис роботи з множинними елементами:
1. Використання each()
:
Метод each() використовується для ітерації по всіх елементах у виборі та виконання деякої дії для кожного елемента.
cy.get('.list-item').each(($item, index, $list) => {
// $item - поточний елемент
// index - індекс поточного елемента
// $list - список всіх елементів
cy.wrap($item).click(); // Наприклад, натискання на кожен елемент
});
2. Використання its()
:
Метод its() використовується для витягування значень властивостей з об’єктів із вибору та подальшої роботи з цими значеннями.
cy.get('.list-item').its('text').should('include', 'ExpectedText');
3. Використання invoke()
:
Метод invoke() використовується для виклику методів на кожному елементі у виборі.
cy.get('.list-item').invoke('text').should('include', 'ExpectedText');
4. Використання filter()
:
Метод filter() використовується для вибору підмножини елементів, які задовольняють певний критерій.
cy.get('.list-item').filter(':contains("FilterText")').should('have.length', 2);
5. Використання find()
:
Метод find() використовується для пошуку вкладених елементів всередині кожного елемента у виборі.
cy.get('.parent-element').find('.child-element').should('exist');
6. Використання інших методів:
Ви також можете комбінувати різні методи для досягнення конкретного функціоналу. Наприклад, використовуйте each() для ітерації та подальшої взаємодії з кожним елементом.
cy.get('.list-item').each(($item) => {
cy.wrap($item).click(); // Натискання на кожен елемент
cy.wrap($item).should('be.visible'); // Перевірка видимості кожного елемента
});
Ці методи дозволяють ефективно взаємодіяти з множиною елементів на сторінці та виконувати різні дії для кожного з них. Зручність використання того чи іншого методу залежить від конкретних потреб та умов вашого тесту.
Додаткові методи роботи з множинними елементами
- first – обирає перший елемент у наборі DOM елементів.
Ситнаксис:
.first()
.first(опції)
Коректне використання:
cy.get('nav a').first() // поверне перше посилання з множини
Детальну інформацію про варіанти застосування та опціі можна знайти тут.
2.last – обирає останній елемент у наборі DOM елементів.
Ситнаксис:
.last()
.last(опції)
Коректне використання:
cy.get('nav a').last() // поверне останнє посилання з множини
Детальну інформацію про варіанти застосування та опціі можна знайти тут.
3.nextAll – обирає всіх наступних “братніх” елементів у наборі.
Ситнаксис:
.nextAll()
.nextAll(селектор)
.nextAll(опції)
.nextAll(селектор, опції)
Коректне використання:
cy.get('.active').nextAll() // Поверне всі братні елементи після `.active`
Детальну інформацію про варіанти застосування та опціі можна знайти тут.
4.nextUntil – обирає всі наступні “братні” елементи у наборі відповідних елементів DOM після наданого елемента, але не включаючи його.
Ситнаксис:
.nextUntil(селектор)
.nextUntil(селектор, фільтр)
.nextUntil(селектор, фільтр, опції)
.nextUntil(елемент)
.nextUntil(елемент, фільтр)
.nextUntil(елемент, фільтр, опції)
Коректне використання:
cy.get('div').nextUntil('.warning') // поверне "братні" елементи після 'div' до '.warning'
Детальну інформацію про варіанти застосування та опціі можна знайти тут.
5.parents – обирає всі батьківські елементи знайденого раніше.
Ситнаксис:
.parents()
.parents(селектор)
.parents(опції)
.parents(селектор, опції)
Коректне використання:
Детальну інформацію про варіанти застосування та опціі можна знайти тут.
6.prevAll – обирає всі попередні “братні” елементи у наборі.
Ситнаксис:
.prevAll()
.prevAll(селектор)
.prevAll(опції)
.prevAll(селектор, опції)
Коректне використання:
cy.get('.active').prevAll() // Поверне всі братні елементи перед `.active`
Детальну інформацію про варіанти застосування та опціі можна знайти тут.
7.prevUntil – обирає всі наступні “братні” елементи у наборі відповідних елементів DOM перед наданим елементом, але не включаючи його.
Ситнаксис:
.prevUntil(селектор)
.prevUntil(селектор, фільтр)
.prevUntil(селектор, фільтр, опції)
.prevUntil(елемент)
.prevUntil(елемент, фільтр)
.prevUntil(елемент, фільтр, опції)
Коректне використання:
cy.get('p').prevUntil('.intro') // поверне "братні" елементи перед'div' до '.intro'
Детальну інформацію про варіанти застосування та опціі можна знайти тут.
Приклад роботи з множинними елементами – отримання тексту з масиву кнопок та порівняння масивів:
cy.get('nb-card[size="small"]').first().find('button.status-danger').then(($elements)=>{
const buttonsText = []
cy.wrap($elements).each(($el)=>{
const text = $el.text()
buttonsText.push(text)
}).then(()=>{
cy.log(`Buttons text : ${JSON.stringify(buttonsText)}`)
expect(buttonsText).to.deep.equal(['Left','Top', 'Bottom', 'Right'])
})
})
Best Practices для роботи з елементами у Cypress
Робота з елементами в Cypress може бути більш ефективною та підтримуваною, якщо дотримуватися кращих практик. Ось деякі з них:
1. Використовуйте cy.get()
з атрибутами, класами або ідентифікаторами:
Замість використання складних селекторів, які можуть змінюватися, краще використовувати атрибути, класи або ідентифікатори для вибору елементів:
Робота з елементами в Cypress може бути більш ефективною та підтримуваною, якщо дотримуватися кращих практик. Ось деякі з них:
1. Використовуйте `cy.get()` з атрибутами, класами або ідентифікаторами:
Замість використання складних селекторів, які можуть змінюватися, краще використовувати атрибути, класи або ідентифікатори для вибору елементів:
2. Використовуйте фіксовані дані атрибутів для селекторів:
Додайте атрибути data-cy або подібні для елементів, які використовуються тільки в тестах:
<button data-cy="submitButton">Відправити</button>
3. Використовуйте cy.contains()
замість конкретного селектора:
cy.contains() дозволяє вибрати елемент на основі текстового вмісту, що робить тест менш залежним від конкретної структури DOM:
// Погано
cy.get('.menu li:nth-child(3)')
// Краще
cy.contains('.menu li', 'Опція 3')
4. Створюйте аліаси для елементів:
Використання аліасів полегшує читання і підтримку тестів:
cy.get('.username-input').as('usernameInput');
cy.get('@usernameInput').type('user123');
5. Розділяйте тестові випадки:
Розділяйте тести на окремі випадки для кращої читабельності і підтримки:
describe('Логін', () => {
it('повинен вивести помилку при невірних облікових даних', () => {
// ваш код тесту
});
it('повинен вхідити користувача з правильними обліковими даними', () => {
// ваш код тесту
});
});
6. Використовуйте команду .find()
для вкладених елементів:
Якщо вам потрібно звертатися до вкладених елементів всередині іншого елемента, використовуйте .find():
cy.get('.parent-element').find('.child-element').should('exist');
7. Використовуйте атрибути елементів, які не змінюються:
Віддавайте перевагу використанню атрибутів, які менше схильні до змін, наприклад, data-testid або data-cy.
8. Використовуйте cy.get()
зі змінними:
Використовуйте змінні для зберігання селекторів та використовуйте їх у командах cy.get():
const submitButton = '.submit-button';
cy.get(submitButton).click();
cy.get(submitButton).should('be.disabled');
9. Використовуйте .first()
та .last()
для роботи з першим і останнім елементами:
Якщо вам потрібно взаємодіяти з першим або останнім елементом, використовуйте .first() або .last():
cy.get('.list-item').first().should('have.class', 'first-item');
cy.get('.list-item').last().click();
10. Уникайте використання force
без необхідності:
Метод .force() застосовується для примусового виконання дій, але використовуйте його обережно, оскільки це може призвести до некоректного введення.
11. Використовуйте .within()
для взаємодії з групою елементів:
Метод .within() дозволяє обмежити дії лише в середині обраного елемента:
cy.get('.form-container').within(() => {
cy.get('.username-input').type('user123');
cy.get('.password-input').type('password123');
cy.get('.submit-button').click();
});
Ці практики допомагають утримувати ваш код тестів зрозумілим, підтримуваним та менш залежним від внутрішньої реалізації сторінки.
Додатково можна знайти інформацію у документації.