Согласно их домашней странице, Cypress — это

Быстрое, простое и надежное тестирование всего, что запускается в браузере.

Он предлагает способ написания автоматизированных тестов пользовательского интерфейса на JavaScript и запускать их либо во время разработки, либо во время тестов непрерывной интеграции (CI). Он может генерировать скриншоты и даже видео тестовых прогонов и сообщать о результатах тестов в нескольких форматах.

Присматриваюсь к Cypress больше года. Когда он стал открытым исходным кодом и общедоступным в октябре 2017 года, мы были очень заняты, чтобы попробовать его в наших проектах. Сегодня я написал первый end-to-end (e2e) тест с помощью Cypress. Заставить его работать было относительно легко, это заняло у меня несколько часов. Я опишу процесс и трудности, с которыми я столкнулся на этом пути.

Приложение

Я выбрал наше приложение для регистрации, чтобы попробовать Cypress. Это одностраничное приложение React, написанное на TypeScript. Он связан с использованием webpack, и мы используем webpack-dev-server для его разработки. Мы также запускаем очень простой фиктивный сервер на основе Express для имитации нашего API.

Не так давно в приложении была ошибка, из-за которой в некоторых случаях пользователи не могли зарегистрироваться. Ошибка была обнаружена с помощью ручного тестирования перед выпуском. Однако ручное тестирование было сосредоточено на чем-то другом, и обнаружение ошибки было для нас каким-то везением. Это сделало приложение Registration идеальным кандидатом для e2e-тестирования.

Установка Кипариса

Добавить Cypress было так же просто, как запустить yarn add -D cypress. После завершения установки мы можем просто запустить yarn cypress open, чтобы запустить пользовательский интерфейс Cypress. При установке в проект добавляется несколько папок, содержащих пример набора тестов и файлы конфигурации. Это означает, что вы можете убедиться, что Cypress работает, не записывая ни одного тестового файла, поскольку тесты выполняются для https://example.cypress.io.

Базовая конфигурация также проста. Единственное, что мне нужно было изменить, это файл конфигурации cypress.json. Необходимо было объявить базовый URL экземпляра webpack-dev-server:

Написание теста

Используя предоставленный пример тестового файла, довольно легко написать тест для нашего приложения. Исходный код теста (названный registration_spec.js) указан ниже:

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

Идентификация элементов

Элементы идентифицируются с помощью атрибута data-testid. Это рекомендуемый путь. Добавить эти атрибуты в приложение так же просто, как кажется, вот, например, обновленный компонент сообщения результатов:

Мы добавляем эти атрибуты, чтобы предотвратить поломку тестов при изменении макета или классов CSS.

Пока все кажется очень простым, однако было несколько проблем.

Задача 1: reCAPTCHA

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

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

Задача 2: заглушить ответы сервера

Cypress предоставляет способ заглушить ответы сервера. Теоретически это означает, что вы можете указать ответы сервера для каждого теста в самой спецификации теста. Это была одна из причин, по которой нас привлекла компания Cypress. К сожалению, с этой функцией есть очень серьезная проблема — Cypress умеет заглушать только ответы на вызовы XHR. Это означает, что запросы, сделанные с помощью Fetch API, в данный момент не могут быть заглушены. Это действительно трудно найти в официальных документах, поэтому я потратил больше часа, пытаясь заставить его работать, но позже обнаружил, что это действительно невозможно сделать. Существует открытый вопрос по добавлению правильной заглушки для Fetch API.

Существует также обходной путь, который позволяет нам все-таки имитировать вызовы fetch. Это основано на том факте, что полифил Fetch API, который мы используем, использует XHR в браузерах без Fetch API. Код обходного пути показан ниже:

В следующем примере показаны фиктивные определения для теста:

Определения, вероятно, покажутся вам знакомыми, если вы когда-либо писали сервер Express. Единственная загвоздка - это когда вы хотите получить пустой ответ. В этом случае в качестве ответа необходимо указать пустую строку (null или undefined не подойдет).

Задача 3: организация тестовых прогонов в CI

Выполнение тестового прогона вручную состоит из запуска двух отдельных скриптов npm:

  1. npm run webpack для запуска webpack-dev-server
  2. cypress run для запуска тестового прогона Cypress

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

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

Команда использует concurrently для параллельного запуска трех упомянутых команд. Параметры -k -s first гарантируют, что как только Cypress завершит работу, оба сервера будут немедленно уничтожены, а выполнение завершится кодом возврата запуска Cypress. Он работает npm run webpack как есть. Сложнее всего было заставить cypress run ждать, пока веб-пакет не свяжет приложение. Решение намекается в документах:

Вместо произвольных ожиданий, таких как sleep 20, вы можете использовать гораздо лучший вариант, например модуль wait-on.

Используя wait-on прямолинейно, вот так:

однако оказалось малоэффективным. Причина в том, что webpack-dev-server возвращает ответ 200 OK с сообщением «Подождите, пока пакет не завершится», как только он будет запущен (т.е. слишком рано).

Решение состоит в том, чтобы дождаться определенного файла из процесса сборки веб-пакета. В нашем случае один из пакетов находится по адресу /bundles/registration/vendors.js, поэтому мы используем схему http-get:// для его ожидания. Это гарантирует, что все пакеты готовы и приложение действительно работает. Если бы мы использовали http://, wait-on использовало бы HTTP HEAD, которое никогда не вернуло бы 200 OK, то есть мы ждали бы вечно.

Вывод

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