Когда мы начали писать E2E-тесты пользовательского интерфейса для нашего продукта, мы использовали проверенный временем традиционный стек автоматизации пользовательского интерфейса — Selenium, Java и sadness.

Источник упомянутой грусти был связан со страшным F-словом, когда речь идет о наборах автоматизации пользовательского интерфейса — Flakinness.

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

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

Очень быстрый праймер:

  1. WebDriver определяет стандартизированный протокол API для программного взаимодействия с браузерами. Это обеспечивает такие возможности, как автоматическая навигация по страницам, пользовательский ввод, выполнение JavaScript и т. д. в браузерах.
  2. Браузеры реализуют вышеуказанный протокол с помощью серверов (называемых драйверами), которые запускаются в браузере. Каждый браузер имеет свой собственный драйвер, например. FirefoxDriver, ChromiumDriver и т. д.
  3. Эти драйверы принимают запросы, соответствующие протоколу (в основном запросы JSON через HTTP), и в ответ «заставляют» браузер выполнять действия в соответствии с запросом.
  4. Selenium делает привязки доступными для различных языков программирования, что позволяет взаимодействовать с API WebDriver с использованием этих языков.
  5. Таким образом, соединение языковой привязки с драйвером браузера позволяет автоматизировать этот браузер с помощью программ на выбранном языке.

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

Основная проблема с таким дизайном заключается в том, что он вынуждает использовать парадигму связи без сохранения состояния (множество HTTP-запросов) для взаимодействия с системами с все более отслеживаемым состоянием (современные одностраничные приложения на основе JS). Прошли безмятежные дни Интернета, когда практически каждое значительное действие пользователя вызывало запрос к серверу на загрузку новой страницы, отображаемой сервером. Большая часть интерактивности в современных веб-приложениях исходит из кода JS, который не только поддерживает состояние приложения в браузере, но и асинхронно обновляет это состояние в ответ на действия пользователя, данные с сервера и т. д.

Реагирование на эти непредсказуемые асинхронные изменения состояния приложения невозможно с использованием синхронного протокола без сохранения состояния. Вот почему вы обнаружите, что большинство наборов тестов Selenium засорены:

  • условия ожидания (с произвольными тайм-аутами) и/или
  • вызовы методов «ожидания, пока это не произойдет», которые опрашивают состояние браузера до тех пор, пока не будет выполнено определенное условие.

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

Войдите в Сайпарис.

Cypress — это инструмент тестирования на основе Javascript, который запускает тесты внутри браузера в том же цикле выполнения, что и код вашего приложения. Благодаря этому Cypress может получить доступ практически ко всему, что может сделать код вашего приложения. Это открывает довольно много интересных возможностей. Несколько примеров того, что вы можете сделать в Cypress НАМНОГО проще, чем в Selenium:

  • Вызовы API-заглушек и методы приложений
  • Доступ/манипулирование данными в памяти (например, ваше состояние Redux)
  • Выполнение пользовательского кода JS, управляемого событиями

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

Помимо уменьшения проблем с ненадежными тестами, Cypress также удивил нас тем, насколько легко он упрощает написание и отладку тестов. Некоторые из функций, которые нам понравились:

  • Сопутствующий пользовательский интерфейс при выполнении тестов в режиме пользовательского интерфейса, что значительно упрощает отладку.
  • Безголовый режим, который «просто работает». Настройка пакета на нашем CI-сервере стала НАМНОГО менее болезненной.
  • Концепция плагинов, которые позволяют выполнять код Node.js. Довольно полезно, когда вы хотите делать что-то вне браузера. Например. мы используем его для проверки доставки почты от нашего продукта.

Конечно, некоторые варианты выбора, которые делает Cypress, имеют свою цену:

  • Поскольку тесты Cypress выполняются внутри браузера, их можно писать только на JavaScript.
  • Поддержка отдельных браузеров должна быть написана с нуля. Cypress сейчас поддерживает только Chrome; хотя поддержка других уже в пути.
  • Ограничения на работу только с одной вкладкой и одним браузером одновременно.

Для более подробного описания компромиссов, связанных с использованием Cypress, взгляните на это.

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