TGViewer
Виталий и Платформа Виталий и Платформа @web_platform · 1.81K subscribers
Post #223 2K
Скриншот-тестирование компонентов в Docker

В нескольких проектах, где я работал, пробовали внедрить скриншот-тестирование компонентов. Принцип работы такой:

1) меняем компонент
2) делаем эталонный скриншот, сохраняем в репе
3) повторяем на всех компонентах
4) при повторных изменениях запускаем тесты, в которых сравниваются эталонные скриншоты и текущее отображение компонентов
5) если все расхождения запланированные, меняем эталонные скрины; если есть незапланированные расхождения, поздравляю, тесты нашли регресс!

Такие тесты хорошо подходят для теста вёрстки элементов ui-kit-а (многочисленные состояниях ховера, фокуса, разные режимы компонента) или же каких-то критичных компонентов (форма логина, чекаут), которые никак нельзя случайно поломать.

Снепшотные тесты, юниты, e2e тут не помогут, нужно именно сравнение скринов.
Звучит хорошо, но есть одно НО. Во всех случаях на моей практике дело упиралось в то, что скриншоты снимаются разными разработчиками на разных машинах с разными ОС. И в зависимости от этого скриншоты начинают расходиться. Шрифты другие. Субпиксельный рендеринг другой. Антиалиасинг другой. Также отличаются элементы форм. И тест падает, хотя визуально всё ок. Вместо помощи тесты начинают мешать и бесить.

Логично было бы предположить делать скриншоты на одной машине, например, вынести этот процесс на CI/CD или на отдельный сервер, но обычно с этим в компаниях сложно, нужно всё согласовывать, заводить, что есть заморочь.

И тут изучая Docker открыл для себя идеально подходящую под кейс фичу! Через Docker можно связать файловую систему хоста (ваша машина) с файловой системой запущенного контейнера. То есть храним скрины по прежнему в репо (развёрнутом у каждого разработчика), монтируем папку с ними внутрь Docker-контейнера, снимаем скриншоты, сравниваем, при необходимости обновляем. Внутри контейнера один и тот же образ с фиксированной ОС, фиксированной версией браузера, фиксированными шрифтами. И соотвественно таким же макаром запускается в CI.

Собрал пруф оф концепт.

Что там вкратце, происходит: Storybook изолирует компоненты, Playwright делает скриншоты, Docker обеспечивает одинаковый рендеринг.

Оркестрация через docker-compose.yml (именно там указывается, какие локальные папки монтируются в контейнер):


services:
visual-tests:
build: .
volumes:
# Persist screenshots - accessible from host
- ./__screenshots__:/app/__screenshots__
# HTML report for visual diff
- ./html-report:/app/html-report
# Test results (traces, screenshots on failure)
- ./test-results:/app/test-results
# Source files for quick iteration (read-only)
- ./src:/app/src:ro
environment:
- CI=true
command: sh -c "npm run storybook -- --host 0.0.0.0 & sleep 15 && npx playwright test --project=visual"


Docker-образ с Playwright официальный от Microsoft уже содержит браузеры и все зависимости.


FROM mcr.microsoft.com/playwright:v1.48.0-noble


Каждый визуальный тест — это три действия: открыть стори, дождаться рендера, сравнить скриншот. Storybook рендерит в статическом режиме каждый отдельный компонент по адресу /iframe.html?id=${storyId}&viewMode=story, ждём пока загрузятся картинки и шрифты, можно снимать скриншот Playwright-ом и сравнивать тоже им.

Пример теста кнопки:


test.describe('Button', () => {
test('hover', async ({ page }) => {
const component = await gotoStory(page, 'design-system-button--primary');
const button = component.locator('button.button').first();
await button.hover();
await expect(component).toHaveScreenshot();
});
});


Особенности настройки Playwright: можно оставить небольшой задел на случайные расхождения, выключить анимации, спрятать каретку в инпутах.


toHaveScreenshot: {
maxDiffPixels: 100,
animations: "disabled",
caret: "hide",
},


После прогона тестов формируется HTML-репорт: интерактивный diff, где можно посмотреть, что именно изменилось (приложил скрин, как это выглядит в комментах).

#Лаборатория_веб_платформы

@web_platform | Поддержать платформу ⭐️
  • 👍 20
  • 🔥 9
  • ❤ 2
  • 🥰 1
More from @web_platform
  1. Aug 14, 2026Мой воркфлоу с ИИшками сейчас У меня счас несколько подписок: • антропик 20$ (для разработ…
  2. Jul 13, 2026Hermes vs OpenClaw В комметах к прошлому посту @fogrew спросил, чем Hermes отличается от O…
  3. Jul 8, 2026Недавний инцидент с ДЦ сподвиг меня причесать всё на VPS с ботом-дайджестёром. Раньше было…
  4. Jul 2, 2026вчера мой ботик @web_platform_pulse_bot не прислал новости, а всё потому что кукольный теа…
  5. Jun 22, 2026btw там интересная система в репе, используются git submodules: в .gitmodules указывается…
  6. Jun 22, 20264 мая -> 20 июня, столько провисел мой pr в zed до мерджа зато теперь тема superset доступ…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →