Обработка browser-specific багов

Browser-specific баги — это проблемы, которые проявляются только в определённых браузерах или версиях браузеров. В тестировании веб-приложений такие баги встречаются регулярно, особенно при использовании сложных JavaScript-фреймворков, нестандартных CSS-свойств или специфических API браузеров. Cypress предоставляет инструменты для выявления, локализации и обхода этих проблем, что позволяет поддерживать стабильность тестового покрытия в разных средах.


Определение браузера в тестах

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

console.log(Cypress.browser);
/*
{
  name: 'chrome',
  family: 'chromium',
  channel: 'stable',
  displayName: 'Chrome',
  version: '116.0.5845.96',
  majorVersion: '116'
}
*/

На основе этих данных можно условно выполнять тесты или изменять поведение:

if (Cypress.browser.family === 'firefox') {
  // обход специфичного бага в Firefox
  cy.get('.element').click({ force: true });
} else {
  cy.get('.element').click();
}

Ключевой момент: использование условий по Cypress.browser.family или Cypress.browser.name позволяет изолировать browser-specific баги, не нарушая общий поток тестов.


Игнорирование flaky-элементов

Некоторые баги проявляются только в определённом браузере при асинхронных операциях или при рендеринге динамических компонентов. Cypress предоставляет команды для стабилизации тестов:

  • cy.wait() — задержка для ожидания стабильного состояния элемента.
  • { force: true } в cy.click() или cy.type() — обход ограничений видимости.
  • { timeout: X } — увеличение времени ожидания для элементов, медленно загружающихся в специфических браузерах.

Пример:

if (Cypress.browser.name === 'firefox') {
  cy.get('#dynamic-element', { timeout: 10000 }).should('be.visible');
  cy.get('#dynamic-element').click({ force: true });
} else {
  cy.get('#dynamic-element').click();
}

Использование Cypress.on для глобальной обработки ошибок

Некоторые баги проявляются в виде неожиданных исключений, которые прерывают тест. Для их обработки используется глобальный обработчик:

Cypress.on('uncaught:exception', (err, runnable) => {
  if (Cypress.browser.name === 'chrome' && err.message.includes('ResizeObserver loop limit exceeded')) {
    return false; // игнорирование специфичной ошибки
  }
});

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


Разделение тестов по браузерам

Для сложных сценариев полезно создавать отдельные файлы тестов под разные браузеры:

cypress/e2e/
├── chrome/
│   └── main.spec.js
├── firefox/
│   └── main.spec.js

В каждом файле можно применять специфичные обходы багов. Это особенно актуально для CI/CD, когда сборка тестов запускается параллельно в нескольких браузерах.


Снижение влияния браузерных багов на flakiness

  • Явные ожидания (.should) вместо имплицитных действий уменьшают зависимость от скорости рендеринга.
  • Отложенные ассерты (cy.then) помогают дождаться завершения нестабильных операций.
  • Мокинг сетевых запросов (cy.intercept) позволяет изолировать баги, связанные с задержками или некорректными ответами API в конкретном браузере.

Пример использования:

cy.intercept('GET', '/api/data', { fixture: 'data.json' }).as('getData');

cy.visit('/dashboard');
cy.wait('@getData');

cy.get('.data-item').should('have.length', 5);

Даже если в Firefox рендеринг элементов медленнее, тест остаётся стабильным.


Локализация багов

Для точного определения browser-specific багов применяются техники:

  1. Сравнение рендеринга — проверка DOM и CSS в разных браузерах.
  2. Снимки состояния элементов (.snapshot()) — использование Cypress с плагинами визуального тестирования.
  3. Логирование в консоль браузера — вывод console.log(Cypress.browser) и состояния элементов перед каждой критической операцией.

Эти методы помогают быстро выявить, где именно проявляется баг, и выбрать подходящий обход.


Практика использования cy.skip и условного выполнения

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

if (Cypress.browser.name === 'firefox') {
  it.skip('тест пропускается в Firefox', () => {
    cy.get('#buggy-element').click();
  });
} else {
  it('тест выполняется в остальных браузерах', () => {
    cy.get('#buggy-element').click();
  });
}

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


Совмещение стратегий

Эффективная обработка browser-specific багов сочетает:

  • условное выполнение тестов,
  • глобальные обработчики ошибок,
  • использование моков и фикстур,
  • явные ожидания и расширенные таймауты,
  • разделение тестов по браузерам.

Такой подход позволяет поддерживать стабильное тестирование без потери покрытия, даже если приложение активно использует нестандартные API или новые функции браузеров.


Хотите, я могу подготовить вторую часть, подробно разобрав обход багов с Shadow DOM и iframe, где часто возникают специфичные баги в разных браузерах?