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