Мой опыт работы с визуальным тестированием и то, как вы можете реализовать его в своих проектах
В моем списке дел всегда было визуальное тестирование, пока несколько недель назад я наконец не решил отметить его как выполненное.
В этой статье я поделюсь своим опытом работы с этой стратегией тестирования (которая не заменяет другие) и интеграцией с моим текущим инструментом разработки: 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 в своем процессе разработки, вы можете провести один визуальный тест для всех историй без каких-либо реальных усилий.
- ❌ Визуальное тестирование не заменяет другие стратегии тестирования. Он просто добавляет еще один уровень тестирования в ваше приложение.
- ✅ Вы можете легко интегрировать его с текущими сквозными тестами.
Последние слова 👋
Еще кое-что, прежде чем вы уйдете, я решил начать рассылку новостей, поэтому, если вы хотите узнать о том, что я публикую, рассмотрите возможность подписки на нее! Никакого спама, никакого найма, никакого маркетинга приложений, только технические сообщения 👌