Переключение контекста

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


Работа с iframe

iframe часто используется для встраивания стороннего контента. Cypress по умолчанию не поддерживает прямой доступ к содержимому iframe, поэтому требуется дополнительная обработка.

Пример доступа к iframe:

cy.get('iframe#my-frame').then($iframe => {
    const $body = $iframe.contents().find('body');
    cy.wrap($body).find('button.submit').click();
});

Ключевые моменты:

  • Метод cy.get() находит сам iframe.
  • $iframe.contents() возвращает объект DOM, внутри которого можно искать элементы.
  • cy.wrap() создаёт цепочку Cypress-команд для работы с элементами iframe.
  • Все действия внутри iframe должны выполняться после cy.wrap, иначе Cypress не сможет корректно синхронизировать команды.

Для повторного использования рекомендуется создать кастомную команду:

Cypress.Commands.add('getIframeBody', (selector) => {
    return cy.get(selector)
        .its('0.contentDocument.body')
        .should('not.be.empty')
        .then(cy.wrap);
});

Теперь переключение контекста сводится к:

cy.getIframeBody('iframe#my-frame').find('input[name="email"]').type('test@example.com');

Работа с множественными окнами (tabs)

Cypress не открывает новые вкладки браузера по умолчанию, поэтому тестирование многовкладочных сценариев требует обходных подходов.

Решение через изменение атрибута target:

cy.get('a[target="_blank"]').invoke('removeAttr', 'target').click();
cy.url().should('include', '/new-page');
  • invoke('removeAttr', 'target') предотвращает открытие новой вкладки.
  • После клика контекст остается в текущем окне, что позволяет продолжать работу с новой страницей.
  • Метод cy.url() используется для проверки успешного перехода.

Если требуется взаимодействие с внешними вкладками через window.open, используется перехват:

cy.window().then(win => {
    cy.stub(win, 'open').as('windowOpen');
});
cy.get('button.open-popup').click();
cy.get('@windowOpen').should('be.called');

Работа с Shadow DOM

Элементы внутри Shadow DOM требуют явного указания опции includeShadowDom:

cy.get('custom-element', { includeShadowDom: true })
  .shadow()
  .find('button.submit')
  .click();
  • Метод .shadow() позволяет перейти внутрь Shadow DOM.
  • Использование { includeShadowDom: true } в cy.get() упрощает выбор элементов внутри вложенных теневых корней.
  • Cypress поддерживает цепочку команд с Shadow DOM без необходимости сложных обходных манипуляций с чистым DOM.

Переключение между фокусом и активными элементами

Cypress автоматически управляет фокусом на элементах, но иногда требуется явная проверка или изменение контекста.

cy.get('input[name="username"]').focus().type('admin');
cy.focused().should('have.attr', 'name', 'username');
  • Метод .focus() устанавливает фокус на элемент.
  • .focused() возвращает текущий активный элемент страницы.
  • Позволяет проверять корректность переключения между элементами формы.

Работа с динамическим DOM

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

cy.get('#dynamic-container')
  .find('button.load-more')
  .should('be.visible')
  .click();
cy.get('.new-item').should('have.length.greaterThan', 0);
  • Cypress автоматически повторяет поиск элементов до истечения таймаута.
  • Это позволяет избегать явного ожидания через setTimeout или cy.wait().
  • Комбинирование с should('exist') или should('be.visible') гарантирует, что переключение контекста происходит только после появления элемента.

Рекомендации по надежности тестов

  • Использовать кастомные команды для повторяющихся переключений контекста (iframe, Shadow DOM, динамический DOM).
  • Минимизировать использование cy.wait() — полагаться на встроенные ожидания Cypress.
  • Проверять состояние элементов перед взаимодействием (should('be.visible'), should('exist'), should('not.be.disabled')).
  • Для фреймов и Shadow DOM всегда оборачивать элементы через cy.wrap() для правильной синхронизации с цепочкой Cypress.

Эти методы обеспечивают стабильное и детерминированное тестирование, позволяя безопасно переключать контекст между различными областями веб-приложения, независимо от сложности DOM или использования сторонних компонентов.