Cypress елементи

Підтримка 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:

  1. 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'); // Перевірка видимості кожного елемента
});

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

Додаткові методи роботи з множинними елементами

  1. 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();
});

Ці практики допомагають утримувати ваш код тестів зрозумілим, підтримуваним та менш залежним від внутрішньої реалізації сторінки.

Додатково можна знайти інформацію у документації.

Додаткові матеріали

Introduction to Cypress

Table of Contents

Best Practices