Мой опыт работы с визуальным тестированием и то, как вы можете реализовать его в своих проектах

В моем списке дел всегда было визуальное тестирование, пока несколько недель назад я наконец не решил отметить его как выполненное.

В этой статье я поделюсь своим опытом работы с этой стратегией тестирования (которая не заменяет другие) и интеграцией с моим текущим инструментом разработки: Storybook.

Если вы не знаете, что такое Storybook, на официальном сайте они дают следующее определение:

Storybook - это инструмент с открытым исходным кодом для разработки компонентов пользовательского интерфейса изолированно для React, Vue и Angular. Это делает создание потрясающих пользовательских интерфейсов организованным и эффективным.

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

Если вы уже понимаете концепцию Snapshot testing; это тоже самое. Разница в том, что вы сравниваете картинку, а не результирующий код.

Если вы думаете: «Как эти две концепции связаны?», Storybook настаивает на разработке ваших компонентов изолированно, что является лучшим сценарием для визуального тестирования, чтобы избежать нежелательных различий в наших изображениях.

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

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

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

Давайте начнем с нового проекта, загрузив его с помощью create-react-app и установив Storybook с помощью его интерфейса командной строки.

$ npx create-react-app visual-testing-with-storybook
$ cd visual-testing-with-storybook
$ npx -p @storybook/cli sb init

Когда установка будет завершена, вы можете проверить, все ли настроено правильно, запустив yarn storybook, и вы должны увидеть домашнюю страницу с двумя историями, которые были созданы по умолчанию.

Теперь давайте создадим простой компонент для тестирования. Я решил создать простую кнопку с именем DuplicationButton, чтобы каждый раз, когда пользователь нажимает на нее, children, предоставленный реквизитами, дублировался.

Не очень полезно, но послужит отличным примером.

Давайте добавим истории для компонента.

И вот как это выглядит в Storybook.

Создание тестов на основе историй

Чтобы реализовать один тест для каждой истории, в Storybook есть действительно полезное дополнение под названием storyshots.

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

$ yarn add -D @storybook/addon-storyshots react-test-renderer

Затем создайте тестовый файл, в котором вы инициализируете storyshots. Назовем его storyshots.test.js.

// src/storyshots.test.js
import initStoryshots from '@storybook/addon-storyshots';  
initStoryshots({ /* configuration options */ });

Чтобы запустить его, выполните yarn test. Теперь для каждой истории есть тест с snapshot, где вы можете проверить, каков результат (визуализированный компонент) истории.

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

Получение визуального

В приведенном выше коде функция initStoryshots принимает объект конфигурации с параметром test, который позволяет нам изменять метод сравнения для каждой истории / теста.

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

Чтобы установить его:

$ yarn add -D @storybook/addon-storyshots-puppeteer

Затем внутри файла storyshots вам нужно переопределить сравнение test с imageSnapshot из надстройки кукловода. Также необходимо указать URL-адрес, по которому будет работать сборник рассказов, чтобы знать, куда двигаться.

Следует упомянуть, что теперь наши тесты зависят от запущенного экземпляра Storybook. Для такого сценария я рекомендую управлять двумя терминалами одновременно. В одном терминале вы запускаете yarn storybook, а в другом yarn test.

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

В следующем сравнении я изменил border-color кнопки с pink на blue. Исходное изображение будет слева, новое - справа, а посередине будет разница между обоими, с изменениями красного цвета.

Работает на CI

Одновременное открытие двух терминалов - это то, что мы можем сделать только в процессе разработки. Но когда дело доходит до автоматизации этой задачи, все может быть немного сложно.

К счастью, кто-то подумал об этой проблеме и создал пакет npm под названием start-server-and-test, который делает именно это.

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

yarn add start-server-and-test

Внутри package.json вам нужно создать новый скрипт, который запустит сборник рассказов, затем будет ждать, пока http: // localhost: 9009 не будет запущен, и выполнить тесты.

"scripts": {
  "test": "react-scripts test --coverage",
  "storybook": "start-storybook -p 9009 -s public",
  "test:ci": "start-server-and-test storybook http://localhost:9009 test",
},

Интерактивное визуальное тестирование

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

Для этого вам нужно придерживаться другого подхода, чем тот, который был показан ранее. Вы можете добиться этого, используя jest сопоставитель клиентов под названием jest-image-snapshot и любую сквозную структуру. В данном случае я выбрал puppeteer.

yarn add -D jest-image-snapshot puppeteer

Чтобы включить jest-image-snapshot, вам необходимо расширить функцию expect с jest.

Рекомендуемый способ добиться этого с помощью create-react-app - создать файл внутри src с именем setupTests.js. Этот файл будет загружен перед запуском всех тестов, что позволит нам использовать этот настраиваемый сопоставитель.

// src/setupTests.js
import { toMatchImageSnapshot } from 'jest-image-snapshot';
expect.extend({ toMatchImageSnapshot });

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

Чтобы запустить этот тест, нам нужно запустить Storybook, или вы можете использовать yarn test:ci, который сделает это за вас. Вот как выглядит скриншот:

Мой опыт работы с визуальным тестированием

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

Сам проект представлял собой набор иконок погоды, созданных с помощью React и styled-components, названный weather-styled-icon.

В первом выпуске этой библиотеки я написал все тесты с помощью Enzyme, следуя стратегии структурного тестирования.

Проще говоря, я рендерил значок с mount, а затем выполнял проверки, чтобы увидеть, существует ли узел. Чтобы проверить, как это выглядит, я запустил expect.toMatchSnapshot полученных стилей.

Как вы понимаете, этот способ тестирования занимает очень много времени, но, тем не менее, я смог их все пройти.

Проблема возникла, когда я решил обновить версию styled-components с v3 до v4, потому что я хотел начать использовать некоторые из интересных новых API, таких как ThemeProvider, или стилизованные API для стилизации существующих styled-component компонентов.

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

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

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

Я выполнил те же шаги, которые уже объяснял выше, и в итоге получил лучший набор тестов с гораздо меньшим количеством кода. В этом разница строк объединенного запроса на слияние.

Что можно и чего нельзя

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

Тем не менее, я хотел бы выделить несколько важных вещей, которые следует и не следует делать по этой теме:

  • ❌ Не проверяйте стили компонентов с помощью кода. Вместо этого возьмите реальное изображение компонента.
  • ✅ Если вы используете Storybook в своем процессе разработки, вы можете провести один визуальный тест для всех историй без каких-либо реальных усилий.
  • ❌ Визуальное тестирование не заменяет другие стратегии тестирования. Он просто добавляет еще один уровень тестирования в ваше приложение.
  • ✅ Вы можете легко интегрировать его с текущими сквозными тестами.

Последние слова 👋

Еще кое-что, прежде чем вы уйдете, я решил начать рассылку новостей, поэтому, если вы хотите узнать о том, что я публикую, рассмотрите возможность подписки на нее! Никакого спама, никакого найма, никакого маркетинга приложений, только технические сообщения 👌



Ресурсы