Кроссбраузерность – одна из важнейших характеристик веб-приложения, подразумевающая его одинаково корректные отображение и функциональность в различных браузерах, а также их версиях. Современное многообразие браузеров определяется в том числе и различиями в механизмах рендеринга содержимого веб-приложения, когда разные движки браузеров (Blink, WebKit, Gecko, EdgeHTML) по-разному воспринимают и обрабатывают html-теги и css-стили, что закономерно влияет на внешний вид и поведение приложения. В связи с этим очевидна важность кросс-браузерного тестирования, цель которого состоит в том, чтобы при загрузке пользователем веб-приложения в различных браузерах и их версиях обеспечивалось корректное отображение его содержимого, сохранялась целостность его структуры, отсутствовали функциональные ошибки и несоответствия в производительности, развал верстки, наложение элементов друг на друга и т.д.

Кросс-браузерное тестирование с использованием Cypress

Cypress – это инструмент сквозного тестирования на основе JavaScript, разработанный для современной автоматизации веб-тестирования. Cypress позволяет проводить как полноценное end-to-end тестирование с прохождением пользовательских сценариев на реальном продукте, так и интеграционное тестирование отдельных компонентов фронтенда. Cypress стал популярным инструментом тестирования веб-приложений благодаря своим сравнительно мощным функциям, удобному интерфейсу и быстроте выполнения тестов.

Как известно, Cypress позволяет запускать тесты в нескольких браузерах. Согласно официальной документации в настоящее время Cypress поддерживает браузеры семейства Chrome (включая Microsoft Edge на основе Electron и Chromium), WebKit (движок браузера Safari) и Firefox. При этом за исключением Electron, любой браузер, в котором планируется запускать тесты Cypress, должен быть установлен в локальной системе или в среде CI. 

Очевидно то, что часто нет необходимости запускать все имеющиеся наборы тестов в различных браузерах с учетом увеличения времени на тестовый прогон и соответствующих затрат на необходимую инфраструктуру. В этой связи Cypress предусматривает различные стратегии развертывания кросс-браузерного тестирования в конвейерах CI в зависимости от потребностей конкретного проекта. 

Возможности Cypress по оптимизации кросс-браузерного тестирования

Для обеспечения баланса затрат и ресурсов, а также оптимального уровня достоверности Cypress предлагает следующие возможности для эффективной организации кросс-браузерного тестирования:

  1. Выбор конкретного набора тестов для определенного браузера. Например, иногда есть смысл в Chrome запускать все имеющиеся тесты, а в Firefox – передавать лишь spec файл со smoke-тестами, используя флаг --spec. В некоторых случаях приоритетными областями для внедрения кросс-браузерного тестирования могут быть критические функции или рабочие процессы приложения,  а также наиболее вероятные пользовательские сценарии. 

  2. Гибкая настройка периодичности запуска отдельных браузеров. Например, запуск тестов в Chrome может активироваться событиями в репозитории, в то время как в Firefox тесты будут запускаться по заданному расписанию с учетом частоты релизов. Современные конвейеры CI позволяют определять периодичность, задавая необходимое время и частоту запуска рабочих процессов.

  3. Параллельное выполнение тестовых файлов для каждой группы, где группы основаны на тестируемых браузерах. Так, использование Cypress Cloud позволяет запускать различные браузеры на разных уровнях распараллеливания, дифференцируя объем выделяемых ресурсов CI между браузерами в зависимости от важности каждого браузера в стратегии тестирования. Например, тесты в Chrome можно запускать в параллельном режиме условно на четырех машинах, в то время как в Firefox – на двух, минимизируя затраты на CI. 

  4. Возможность настройки запуска или исключения браузеров для конкретного теста/тестового набора. Иногда для сокращения продолжительности тестового запуска есть смысл запустить или проигнорировать один или несколько тестов в определенных браузерах. Для этого Cypress позволяет указать непосредственно в конфигурации теста или тестового набора конкретный браузер для запуска или исключения, например:  { browser: 'firefox' } или { browser: '!chrome' }.

  5. Определение окружения развертывания ПО. Так, в случаях, когда проект демонстрирует неизменно стабильное поведение в разных браузерах, целесообразно настроить кросс-браузерное тестирование лишь перед развертыванием изменений в production.

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

Зачем использовать Docker в кросс-браузерном тестировании

Существуют различные подходы к реализации кросс-браузерного тестирования с Cypress, один из которых состоит в настройке автоматического запуска тестов в выбранной среде CI с использованием Docker

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

Использование Docker Compose позволяет без особых усилий масштабировать инфраструктуру тестирования, распределяя рабочую нагрузку по нескольким контейнерам. Так, возможно определить несколько контейнеров для разных браузеров и одновременно запускать их с помощью одной команды, а точнее одного конфигурационного файла. Параллельное исполнение тестов в различных браузерах очевидно значительно ускоряет общий процесс тестирования.

Использование официальных Docker образов Cypress с предустановленными браузерами в качестве базового слоя освобождает от необходимости устанавливать браузеры на серверах, на которых запускаются Docker контейнеры. Более подробно ознакомиться с преимуществами использования Docker в тестировании вы можете в моей предыдущей статье о запуске тестов Cypress в Docker контейнерах. 

Переходя от теории к практике

В качестве среды непрерывной интеграции в данной статье я использую платформу GitHub Actions. Следует отметить, что Cypress предоставляет множество полезных примеров конфигурационных файлов для настройки рабочих процессов GitHub Actions, основываясь на которых довольно просто организовать различные варианты запуска тестов в нескольких браузерах. Например, можно создать рабочий процесс для каждого брузера в отдельности и активировать созданные процессы в зависимости от заданных триггерных событий в репозитории. 

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

Идея довольно проста – предположим необходимо обеспечить исполнение конкретного набора автотестов Cypress в четырех браузерах – Google Chrome, Firefox, Microsoft Edge и Electron. Триггерами запуска рабочего процесса в репозитории для примера должны быть push событие в ветку main, открытый или повторно открытый pull request, а также запуск по расписанию – например, каждую пятницу в 2 часа ночи. Также в ходе выполнения рабочего процесса необходимо получить артефакты с результатами прогона тестов в каждом из браузеров – видео и снимки экрана, в случае если какие-либо тесты потерпят неудачу. 

Один из возможных вариантов решения данной задачи состоит в создании “кастомного” Docker образа на основе одного из официальных образов Cypress, сборке и одновременном запуске четырех контейнеров из созданного образа, в каждом из которых имеющиеся тесты будут запущены в конкретном браузере.

Коротко о тестовом проекте

Для демонстрации кросс-браузерного запуска автотестов Cypress используется простейший проект Cypress-Docker для тестирования моего блога Testing with Cypress на Medium. В проекте уже установлены некоторые зависимости – Cypress 12.13.0 и Typescript 5.0.4, а также имеется spec.cy.ts файл с набором из трех тривиальных тестов для главной страницы блога:

Запустив в браузере Chrome локально убеждаемся, что все тесты проходят успешно:

Стоит отметить, что данные тесты очевидно являются лишь демонстрационным примером и не свидетельствуют о корректном отображении и функциональности веб-сайта в различных браузерах. 

Для запуска тестов на платформе GitHub Actions данный проект размещен на GitHub.

Сборка Docker образа

В качестве базового слоя для сборки образа взят официальный Docker образ Cypress/Browsers, включающий все зависимости операционной системы и некоторые браузеры. Наиболее актуальная на данный момент версия образа – node-18.16.0-chrome-113.0.5672.92-1-ff-113.0-edge-113.0.1774.35-1 включает в себя предустановленную Node.js 18.16.0,  а также три браузера – Google Chrome, Firefox и Microsoft Edge. С учетом того, что браузер Electron предустановлен в Cypress, в нашем распоряжении будут все необходимые браузеры для проведения кросс-браузрного запуска тестов в соответствии с поставленной задачей.

Итоговый Dockerfile для сборки необходимого образа будет иметь следующий вид:

Вначале в инструкции FROM определен базовый образ, все зависимости и конфигурации которого будут включены в создаваемый образ. На следующем шаге WORKDIR создается рабочая директория /e2e, в которой будут выполняться все последующие команды. Далее файлы package.json, cypress.config.ts, а также папка cypress, включающая spec файл, будут скопированы из репозитория в рабочую директорию внутри образа. 

В инструкции RUN задаются две команды для запуска, в частности npm i – для установки в рабочей директории образа необходимых зависимостей (Cypress 12.13.0 и Typescript 5.0.4) и npx cypress info – для вывода информации о Cypress и текущей среде, в частности об обнаруженных Cypress браузерах. На последнем шаге в инструкции ENTRYPOINT в exec форме определена команда по запуску Cypress в headless режиме в генерируемых из данного образа контейнерах.

Настройка запуска контейнеров с помощью Docker Compose

Как указывалось ранее, после сборки образа на его основе планируется создать четыре контейнера, в каждом из которых автотесты Cypress будут запущены в конкретном браузере. Чтобы одновременно запустить контейнеры с помощью одной команды целесообразно использовать такой инструмент как Docker Сompose. Для описания процесса загрузки и настройки контейнеров конфигурационный YAML-файл должен включать следующее:

Как видно в конфигурации мы определяем четыре сервиса (контейнера) – e2e-chrome, e2e-firefox, e2e-edge и e2e-electron, каждый из которых использует вышеописанный образ, созданный на основе размещенного в той же директории Dockerfile (ключи build). 

Далее значениями ключей command задаются команды для запуска Cypress в браузерах с заданными именами. Здесь стоит отметить, что в сервисе e2e-firefox команда дополнена изменением конфигурации в связи с открытой проблемой с записью видео при использовании в Cypress браузера Firefox.

На следующем шаге для получения доступа к артефактам за пределами контейнеров для каждого сервиса монтируются тома (ключи volumes) и задаются соответствующие сопоставления. По сути это означает, что сгенерированные в ходе запуска Cypress и записанные в контейнеры видео и снимки экрана фактически будут сохраняться в виртуальной среде GitHub Actions по указанным путям относительно рабочей области запущенного рабочего процесса. Это позволит в случае, если какие-либо тесты не пройдут, извлекать артефакты из директории ./artifacts в ходе выполнения рабочего процесса GitHub Actions, что и требуется согласно условиям поставленной задачи.

Настройка рабочего процесса в GitHub Actions

Для определения рабочего процесса в директории .github/workflows проекта сформирован следующий e2e.yml файл:

Давайте разберем его чуть подробней. Так, с помощью ключа on определены события-триггеры, активирующие рабочий процесс согласно условиям задачи:

  • push – при отправке изменений в ветку main

  • pull_request – при открытии или повторном открытии pull request

  • schedule – запуск рабочего процесса по расписанию каждую пятницу в 2am

Далее определено одно задание (джоб), выполняемое в рабочем процессе, – cypress-run. Задание будет запускаться на виртуальной машине с установленной последней версией операционной системы Ubuntu Linux в пределах заданного тайм-аута в 5 минут, чтобы гарантировать, что случайное зависание не израсходует лишние минуты CI. 

Ключом steps объединены все необходимые шаги для выполнения задания. Вначале запускается уже готовое действие (экшн) – actions/checkout@v3, которое извлекает репозиторий в виртуальную машину, последовательно осуществляя необходимые действия, в т.ч. проверяет версию git, создает нужные папки, авторизуется и т.д.

Далее следует основной шаг задания – Run docker-compose, на котором выполняется команда docker-compose up для сборки и запуска четырех Docker контейнеров с указанными именами (e2e-chrome, e2e-firefox, e2e-edge и e2e-electron), определенных в конфигурации Docker Compose. Флаг -d в данном случае означает запуск контейнеров в фоновом режиме, чтобы позволить рабочему процессу продолжать выполнение последующих шагов. 

Цель следующего шага – обеспечить видимость журналов запущенных Docker контейнеров, чтобы отслеживать их логи и контролировать процесс запуска сервисов, прежде чем переходить к последующим шагам рабочего процесса. Команда docker-compose logs -f отображает журналы всех запущенных контейнеров в режиме реального времени. На данном шаге возможно пошагово отслеживать выполнение автотестов Cypress в каждом из четырех браузеров.  

Последующие четыре шага идентичны по своей сути и обеспечивают загрузку артефактов рабочего процесса из каждого контейнера для доступа к ним после его завершения. Действие actions/upload-artifact@v3 использует указанные в качестве входных данных пути path и загружает папки со сгенерированными Cypress видео и снимками экрана в случае неудачного исхода теста. В результате артефакты из каждого контейнера будут доступны на странице сводки рабочего процесса (summary). Кроме того, настроено поведение действия в случае, если файлы артефактов не найдены, а также задан срок хранения артефактов (5 дней). 

Запуск рабочего процесса

Чтобы активировать рабочий процесс, создадим событие-триггер. Для этого внесем небольшое изменение в один из имеющихся тестов, например добавим “.” в конце ожидаемого текста заголовка (выделено) для того, чтобы тест не прошел:

Далее сделаем коммит и отправим изменение в ветку main:

Рабочий процесс запущен. Перейдем в репозиторий проекта на GitHub, во вкладке Actions откроем сводку последнего рабочего процeсса:

В журнале выполненного задания (джоба) cypress-run убеждаемся, что все шаги выполнены успешно:

В частности, на шаге Run docker-compose на основе вышеописанного Dockerfile был собран Docker образ, из которого были сгенерированы четыре контейнера. В ходе сборки образа по команде npx cypress info в журнал выведена информация об обнаруженных браузерах, а также других характеристиках тестовой среды – операционной системе, версиях Node.js, Cypress и т.д.:

На следующем шаге в созданных контейнерах одновременно были запущены процессы:

а именно запущено параллельное выполнение автотестов Cypress в четырех браузерах:

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

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

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

Загрузив артефакты со страницы сводки в формате ZIP-файлов, убеждаемся в наличии видео и снимков экрана для неудачного теста в каждом из браузеров (за исключением видео в Firefox):

Проверим ради эксперимента, что в случае успешного выполнения всех тестов, артефакты рабочего процесса не будут загружены. Для этого исправим ошибку в первом тесте, сделаем коммит и снова отправим изменение в ветку main:

По завершению рабочего процесса убеждаемся, что ни из одного контейнера артефакты загружены не были в связи с их отсутствием:

Заключение

В заключение стоит отметить, что оптимизация кроссбраузерного тестирования с Cypress на основе описанного в данной статье подхода имеет ряд очевидных преимуществ. В частности, гарантируется одновременный запуск и параллельное выполнение тестов в нескольких браузерах. Контейнеризация обеспечивает согласованность и воспроизводимость тестовой среды при запуске автотестов Cypress в различных браузерах. Более того, упрощается настройка и поддержка среды выполнения тестов на основе одного конфигурационного файла. Инфраструктура тестирования легко масштабируется в зависимости от желаемого уровня параллелизма или количества тестируемых браузеров и т.д. В целом все это позволяет повысить эффективность использования доступных ресурсов CI, сократить общее время на выполнение тестов, расширить тестовое покрытие в нескольких браузерах, обеспечивая оптимальный уровень достоверности с учетом особенностей конкретного проекта.

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

Спасибо за внимание и удачного тестирования!

Комментарии (9)


  1. alena00
    30.05.2023 22:17
    +1

    Интересная, полезная статья, спасибо. Остался вопрос по артефактам, а именно как настроили чтобы не грузилось видео, если все тесты успешно проходят?


    1. alex_sanzh Автор
      30.05.2023 22:17

      благодарю за вопрос. Это настроено в config-файле исходного проекта, где Cypress позволяет прописать Node-событие, которое срабатывает после прогона каждой спеки и удаляет видео при выполнении определенных условий. В частности в случае спек, у которых не было повторных попыток запуска теста. Код события можно просмотреть здесь.


      1. alena00
        30.05.2023 22:17
        +1

        понятно, спасибо за ответ!


  1. afomchenko
    30.05.2023 22:17
    +1

    освежил в памяти некоторые моменты, в целом годный кейс, благодарю


    1. alex_sanzh Автор
      30.05.2023 22:17

      Благодарю за комментарий


  1. petr_zakharov
    30.05.2023 22:17
    +1

    не проще ли добавить в workflow условие if: failure() чтобы загружать артефакты только в случае если тесты завалятся?


    1. alex_sanzh Автор
      30.05.2023 22:17

      благодарю за комментарий. if: failure() сработал бы если предыдущий степ джоба завершился бы неудачей, чего не произойдет поскольку команда по сборке и запуску контейнеров пройдет успешно даже если во всех контейнерах тесты упадут. в данном случае проще настроить загрузку артефактов непосредственно в самом проекте (что касается в основном видео), экшн проверит указанные папки и заберет все их содержимое в случае, если найдет там что-либо.


  1. rutester
    30.05.2023 22:17
    +1

    полезный кейс, спасибо за детальное изложение!


    1. alex_sanzh Автор
      30.05.2023 22:17

      Благодарю за комментарий