* 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>
4.6 KiB
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. Это связывало эволюцию продакшн-обложки с тест-контрактами и заставляло держать мёртвые слоты в шаблоне.
Требовалось отвязать тесты от продакшн-шаблона: дать им стабильный контракт, а продакшн-обложку упростить до того, что реально нужно для рендера.
Решение
- Каноничный fixture —
tests/fixtures/cover.svgсо всеми типами слотов (icon 400×400 recolor=accent, sub-icon, badge с bg/border/radius, subtitle y=930). Стабильный тестовый контракт, не зависящий от продакшн-обложки. - Helper
loadFixture(name)—tests/helpers/fixtures.ts, читает изtests/fixtures/, не дублирует логикуloadTemplate. - Параметризация CLI
--template-dir—loadTemplate(drawImageDir, name, templateDir?)вsrc/render.tsпринимает опциональныйtemplateDir(дефолт"templates", поддерживает относительный и абсолютный путь).cli.tsпарсит--template-dirи пробрасывает вloadTemplate. Без флага →templates/(обратная совместимость для продакшн). E2e-тесты передают--template-dir tests/fixtures. Это чистое решение (параметризация, а не копирование файлов во временный dir). - 9 тестов переведены на fixture — unit/integration используют
loadFixture("cover"), e2e (CLI) передают--template-dir tests/fixtures.e2e.bad-input.test.tsне тронут (тестирует несуществующий шаблон, не зависит от cover.svg). - Продакшн
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 явно просит упрощение как демонстрацию, что отвязка работает (критерий приёмки: зелёные тесты после упрощения). Упрощение убирает мёртвые слоты, которые продакшн-рендер не использовал.