Альтернативный способ хранения скриншотов в Playwright и способ их обновления
- понедельник, 4 августа 2025 г. в 00:00:04
 

Привет! Меня зовут Вячеслав, я инженер по автоматизации тестирования в компании ROWI.Tech.
В ходе автоматизации тестирования пользовательских интерфейсов зачастую используется такой подход как визуальное тестирование. Он позволяет поддерживать стабильность и отсутствие ошибок в отображении страниц.  
Одним из инструментов, предоставляющих возможность автоматизации данного вида тестирования, является Playwright.
В этой статье я расскажу о работе с визуальным тестированием в рамках упомянутого инструмента, как мы справились со сложностями хранения эталонных скриншотов и автоматизировали их обновление.
Визуальные проверки Playwright.
Облачное хранилище для эталонных скриншотов.
Обновление скриншотов.
Автоматизация обновления эталонных скриншотов.
Данный инструмент предоставляет утверждение из “коробки” для визуальных проверок -  toHaveScreenshot. Можно визуально сравнивать как страницы, так и отдельные элементы на ней. 
Возможные настройки утверждения:
Отключение анимаций.
Передача стилевых файлов.
Настройка маски для динамических элементов.
Также помимо настройки самого утверждения можно указать некоторые настройки глобально:
Максимальная разница в результатах по сравнению с эталоном в пикселях и долях.
Путь до скриншота
С полным списком настроек можно ознакомиться в официальной документации Playwright.

Playwright сохраняет скриншоты в установленной директории проекта. Мы можем определить необходимое расположение согласно установленной структуре с помощью указания шаблона пути до необходимой директории в конфигурационном файле (playwright.config.ts).
Это дает нам выбрать способ хранения скриншотов:
Сохранять скриншоты в проекте, публиковать их вместе с изменениями кодовой базы.
Хранить скриншоты в отдельном удалённом хранилище.
Первый подход имеет свои недостатки. Он увеличивает размер проекта и число изменяемых файлов. С ростом количества тестов увеличивается и размер репозитория.
Git LFS является расширением Git, которое применяется в работе с часто изменяющимися большими файлами, такими как изображения и наборы данных. Оно может решить проблему хранения эталонных скриншотов в проекте. Подробнее об использовании Playwright с Git LFS можно прочитать тут.

Альтернативой Git LFS являются отдельные удалённые хранилища, например облачные. Одним из таких хранилищ является объектный S3.

Мы решили использовать альтернативный подход, воспользовавшись S3 хранилищем, в котором были заведены отдельные bucket’ы для визуального тестирования и e2e-тестов.
В CI/CD мы реализовали отдельный этап, на котором в проект загружаются все необходимые файлы, используя MC образ.
screenshot-download:
  stage: screenshot-download
  allow_failure: true
  artifacts:
    paths:
      - screenshot
      - static-files
    reports:
      dotenv: screenshot-variables.env
    expire_in: 1 hour
  script:
    - |
      PROJECT_GROUP=$(echo ${CI_PROJECT_NAMESPACE} | grep -Eo '([^\/]+)[\/]?$')
    - echo "PROJECT_GROUP=${PROJECT_GROUP}" >> screenshot-variables.env
    - mc alias set bucket-alias https://path-to-storage.net $BUCKET_ROWI_TEST_SCREENSHOT_ACCESS_KEY $BUCKET_ROWI_TEST_SCREENSHOT_SECRET_KEY
    - mc cp --recursive bucket-alias/rowi-test-screenshot/${PROJECT_GROUP}/ screenshot
    - ls screenshot
    - |
      if [[ ! -z $(mc ls bucket-alias/rowi-test-static-files/${PROJECT_GROUP}/) ]]; then mc cp --recursive bucket-alias/rowi-test-static-files/${PROJECT_GROUP}/ static-files
      ls static-files;
	fiПосле перемещения эталонных скриншотов в облачное хранилище механизм обновления стал следующим:
Запустить Docker контейнер playwright.
Выполнить необходимые тесты с ключом update-snapshots.
В ручном режиме загрузить полученные скриншоты в S3 хранилище, используя клиент (например, s3 Browser).

Но по мере увеличения таких тестов увеличиваются и трудозатраты на актуализацию ожидаемых результатов.
Мы приняли решение реализовать механизм, с помощью которого можно было бы обновлять скриншоты прямо из отчёта о тестировании. Вдохновением для реализации послужила статья, в которой был разработан артефакт, содержащий запись теста.
Мы остановились на HTML с кнопкой обновления скриншота, загружаемый в качестве артефакта.
Требования
Реализуемая страница должна обладать следующими качествами:
Кнопка должна относиться к конкретному скриншоту.
Кнопка появляется только в случае несоответствия скриншотов.
Загрузка скриншотов должна осуществляться в S3 хранилище по одному нажатию кнопки.
Актуальный скриншот должен стать эталонным.
Должна быть индикация успешной загрузки скриншота.
Реализация
Флагом несоответствия с эталонным скриншотом является наличие актуального скриншота. Это можно использовать для начала формирования артефакта.
if (matcherResult["actual"]) await attachHtmlButton(matcherResult); После того, как стала понятна отправная точка для формирования артефакта, нужно определить зависимости, необходимые для его реализации. Такими зависимостями стали:
AWS SDK для взаимодействия с удалённым хранилищем.
Buffer для преобразования base64 строки в объект Buffer.
Allure предлагает широкий выбор типов приложений, одним из которых является HTML, в котором можно разместить кнопку.
Для записи артефакта используется TestInfo объект, содержащий информацию о выполняемом тесте. 
Создание артефакта представлено следующим образом:
//генерируется случайный uuid для уникального названия артефакта
//получение пути до артефакта в контексте текущего теста
const file = testInfo.outputPath(`${faker.string.uuid()}.html`);
//запись HTML-артефакта
await fs.writeFile(file,prepareHtml((await fs.readFile(matcherResult.actual, { encoding: "base64" })).toString(),`path/to/s3/expected.png`),"utf8");
//приложение HTML к артефактам текущего теста
await testInfo.attach("Upload:" + matcherResult.actual.split(/\//).at(-1).replace(".png", ""), {path: file, contentType: "text/html"});В HTML-артефакте была создана кнопка, нажатие на которую обрабатывается с помощью функции uploadSnapshot.
 
<html>
  <head>
     <script src="https://sdk.amazonaws.com/js/aws-sdk-2.742.0.min.js"></script>
	 <script src=" https://bundle.run/buffer@6.0.3"></script>
   </head>
   <body>
		<button onclick="uploadSnapshot()">Send to S3</button>
		<div id="Notification">Click button to upload</div>
		<script>
			async function uploadSnapshot(){
			<!-- настройка подключения к S3 -->
			AWS.config.update({
			<!-- здесь ключи доступа к S3 -->
			});
			<!-- создание S3 объекта с настроенным подключением -->
			var s3 = new AWS.S3({
			sslEnabled: true,
			});
			<!-- создание Buffer объекта -->
			var base64Data =
			buffer.Buffer.from("${buffer}","base64");
			<!-- оглашение параметров PUT запроса в S3-->
			var params = {
			Bucket: "название bucket’a",
			Key: "путь до эталонного скриншота",
			Body: base64Data,
			ContentEncoding: "base64",
			ContentType: "image/png",
		};
		try {
			<!-- отправка  PUT запроса в S3-->
			await s3.upload(params).promise();
			<!-- уведомление об успешном завершении загрузки -->
			document.getElementById("Notification").textContent = "Uploaded";
		} catch (error) {
		console.log(error);
}		
        </script>
   </body>
</html>
Используемые CDN были добавлены в Allure-образ, чтобы сократить время на их загрузку и обеспечить их доступность.
Визуальное тестирование является одним из популярных видов тестирования, встречающихся в автоматизации. Правильный подход к хранению и обновлению эталонных скриншотов может значительно сократить затрачиваемые ресурсы на поддержку данных тестов.
Перемещение скриншотов в облачное хранилище позволило уменьшить размер репозитория и исключить лишние коммиты в репозиторий, связанные с обновлением скриншотов.
Реализованная кнопка позволила упростить обновление эталонных скриншотов и сделала данный процесс доступным для всех участников команды. Теперь вместо поднятия Docker контейнера с образом Playwright или скачивания с Allure отчёта и последующей ручной отправки в S3 формируется артефакт, автоматизирующий рутинные действия