opencode-config/docs/decisions/087-pr-197-decouple-draw-image-tests-from-cover.md
Sergey 66f0afa58b
refactor(draw-image): decouple tests from production cover.svg (#197)
* refactor(draw-image): add tests/fixtures/cover.svg and loadFixture helper

* feat(draw-image): add --template-dir flag to cli for test isolation

* refactor(draw-image): switch tests from templates/cover to fixtures

* chore(draw-image): simplify production cover.svg now decoupled from tests

* docs(handoff): add handoff + ADR for issue #196

* docs(handoff): set PR number

* docs(project-map): update after structural changes

---------

Co-authored-by: opencode-agent <agent@opencode.local>
2026-08-01 01:22:15 +03:00

4.6 KiB
Raw Permalink Blame History

ADR-087: Decouple draw-image tests from production cover.svg (PR#197)

Статус

Accepted (2026-07-31)

Контекст

10 из 15 тестов движка draw-image жёстко привязывались к продакшн-шаблону templates/cover.svg через loadTemplate(DRAW_IMAGE_DIR,"cover") и проверяли конкретные продакшн-значения: badge-слот x="780" y="780" width="180" height="180" (bg=surface, border=accent, radius=0.5) и subtitle-строку y="930". Любое визуальное изменение обложки (размер/позиция иконки, удаление subtitle) ломало тесты — PR#195 уже сталкивался с этим: пришлось сохранить subtitle-<text> и badge/sub-icon слоты в шаблоне, чтобы не сломать render.optional.test.ts / e2e.optional.test.ts (PR#144), хотя финальный PNG рендерился без subtitle. Это связывало эволюцию продакшн-обложки с тест-контрактами и заставляло держать мёртвые слоты в шаблоне.

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

Решение

  1. Каноничный fixturetests/fixtures/cover.svg со всеми типами слотов (icon 400×400 recolor=accent, sub-icon, badge с bg/border/radius, subtitle y=930). Стабильный тестовый контракт, не зависящий от продакшн-обложки.
  2. Helper loadFixture(name)tests/helpers/fixtures.ts, читает из tests/fixtures/, не дублирует логику loadTemplate.
  3. Параметризация CLI --template-dirloadTemplate(drawImageDir, name, templateDir?) в src/render.ts принимает опциональный templateDir (дефолт "templates", поддерживает относительный и абсолютный путь). cli.ts парсит --template-dir и пробрасывает в loadTemplate. Без флага → templates/ (обратная совместимость для продакшн). E2e-тесты передают --template-dir tests/fixtures. Это чистое решение (параметризация, а не копирование файлов во временный dir).
  4. 9 тестов переведены на fixture — unit/integration используют loadFixture("cover"), e2e (CLI) передают --template-dir tests/fixtures. e2e.bad-input.test.ts не тронут (тестирует несуществующий шаблон, не зависит от cover.svg).
  5. Продакшн templates/cover.svg упрощён — оставлен только icon-слот 520×520 и title y=830. Удалены sub-icon, badge, subtitle-<text>. Перерендеренный assets/cover.png побайтово идентичен предыдущему (cmp → IDENTICAL) — удалённые слоты в продакшн-рендере не использовались.

Альтернативы

  • Копировать fixture в templates/ во временный test-dir (через mkdtempSync + copyFileSync): отвергнуто — каждый e2e-тест должен настраивать tmp-окружение, дублирование, хрупкость. --template-dir параметризует существующий механизм loadTemplate без дублирования.
  • Оставить тесты на loadTemplate с fixture-путем напрямую (loadTemplate(DRAW_IMAGE_DIR,"cover","tests/fixtures")): отвергнуто для unit/integration — loadFixture чище и скрывает путь. Для e2e (CLI) loadTemplate напрямую недоступен (тест гоняет CLI процесс), поэтому --template-dir обязателен.
  • Не упрощать продакшн cover.svg: отвергнуто — issue явно просит упрощение как демонстрацию, что отвязка работает (критерий приёмки: зелёные тесты после упрощения). Упрощение убирает мёртвые слоты, которые продакшн-рендер не использовал.