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

21 lines
No EOL
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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. **Каноничный fixture**`tests/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-dir`**`loadTemplate(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 явно просит упрощение как демонстрацию, что отвязка работает (критерий приёмки: зелёные тесты после упрощения). Упрощение убирает мёртвые слоты, которые продакшн-рендер не использовал.