Навигация по DOM-дереву

Навигация по DOM-дереву является одной из ключевых задач при написании тестов в Cypress. Умение корректно выбирать элементы, перемещаться между ними и взаимодействовать с различными узлами позволяет создавать надежные и устойчивые тесты для веб-приложений.


Основы поиска элементов

В Cypress поиск элементов осуществляется с помощью команды cy.get(). Эта команда использует селекторы CSS или XPath (через плагины) для поиска одного или нескольких элементов в DOM:

cy.get('button.submit')        // выбор всех кнопок с классом submit
cy.get('#username')             // выбор элемента по id
cy.get('form input[type="text"]') // выбор всех текстовых полей внутри формы

Ключевой момент: Cypress автоматически ожидает появления элементов в DOM до тайм-аута (по умолчанию 4 секунды). Это исключает необходимость ручного использования wait в большинстве случаев.

Для уточнения поиска можно применять фильтры cy.contains() и cy.find():

cy.contains('Отправить')       // находит элемент по тексту
cy.get('form').find('input')   // ищет input внутри формы

Навигация по родителям и детям

Для перемещения вверх и вниз по DOM используются команды children(), parent(), parents(), closest():

cy.get('.menu-item')
  .children('a')      // выбрать все дочерние ссылки
  .first()            // выбрать первый элемент
  .parent()           // перейти к родительскому элементу
  .closest('ul')      // найти ближайший ul в цепочке родителей
  • children(selector) — возвращает прямых потомков элемента, соответствующих селектору.
  • parent() — возвращает непосредственного родителя элемента.
  • parents(selector) — возвращает всех родителей до корня документа, соответствующих селектору.
  • closest(selector) — поднимается вверх по DOM до первого родителя, который соответствует селектору.

Навигация между соседними элементами

Для перехода к соседним узлам используются методы next(), nextAll(), prev(), prevAll(), siblings():

cy.get('.active-item')
  .next()            // следующий элемент на том же уровне
  .nextAll()         // все последующие элементы
  .prev()            // предыдущий элемент
  .siblings()        // все элементы на том же уровне

Особенность: Эти методы позволяют создавать цепочки навигации, комбинируя поиск соседей с фильтрацией по селекторам:

cy.get('.active-item')
  .nextAll('li.highlighted')  // все последующие li с классом highlighted
  .first()

Работа с вложенными элементами

Для работы с вложенными структурами удобно использовать комбинацию within() и find():

cy.get('form#login').within(() => {
  cy.get('input[name="username"]').type('admin')
  cy.get('input[name="password"]').type('123456')
  cy.get('button[type="submit"]').click()
})

Метод within() ограничивает область поиска указанным элементом, что повышает точность и предотвращает случайное взаимодействие с элементами вне контекста.


Фильтрация элементов

Cypress предоставляет методы для уточнения найденных элементов: filter(), first(), last(), eq(index):

cy.get('ul > li')
  .filter('.active') // оставляет только li с классом active
  .first()           // выбирает первый элемент из результата
  .eq(2)             // выбирает третий элемент из списка (0-based)

Эти методы полезны при динамических списках, где количество элементов и их порядок может меняться.


Асинхронность и ожидания

Навигация по DOM в Cypress всегда учитывает асинхронность. Команды автоматически повторяются до того момента, пока элемент не станет доступен или не истечет тайм-аут:

cy.get('.dynamic-item').should('exist')
cy.get('.dynamic-item').should('be.visible')

Комбинация навигации и проверок позволяет создавать надежные цепочки:

cy.get('ul#menu')
  .children('li')
  .contains('Настройки')
  .parent()
  .should('have.class', 'menu-group')

Практические советы

  1. Выбор селекторов: Предпочтение стоит отдавать уникальным идентификаторам (id) или атрибутам data-*. Это делает тесты более стабильными.
  2. Минимизировать цепочки DOM: Слишком длинные цепочки могут быть уязвимы к изменениям структуры страницы.
  3. Использование within: Для сложных форм или компонентов с повторяющимися элементами позволяет ограничить область поиска.
  4. Комбинирование фильтров: filter, eq, first помогают точечно выбрать нужный элемент, особенно в динамических списках.
  5. Проверка видимости: Перед взаимодействием стоит удостовериться, что элемент видим, используя should('be.visible').

Навигация в динамических интерфейсах

В современных приложениях часто используются динамически загружаемые компоненты. Cypress упрощает работу с ними за счет встроенных ожиданий:

cy.get('.load-more').click()
cy.get('.item').should('have.length.greaterThan', 10)
cy.get('.item').last().scrollIntoView()

Методы scrollIntoView() и проверка длины коллекций позволяют корректно работать с ленивой загрузкой элементов.


Итоговая структура команд навигации

Категория Команды Описание
Поиск элементов get(), contains(), find() Базовые методы поиска
Родительские/дочерние children(), parent(), parents(), closest() Навигация вверх и вниз по DOM
Соседние элементы next(), nextAll(), prev(), prevAll(), siblings() Переход между соседними узлами
Фильтрация filter(), first(), last(), eq() Уточнение результатов поиска
Контекст within() Ограничение области поиска
Проверки и ожидания should(), scrollIntoView() Устойчивость к динамическим изменениям DOM

Навигация по DOM в Cypress позволяет строить гибкие, устойчивые тесты, обеспечивая точное взаимодействие с элементами страницы и контроль над динамическими интерфейсами.