* 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>
6.2 KiB
| pr | title |
|---|---|
| 197 | refactor(draw-image): decouple tests from production cover.svg |
Что сделано
Отвязал тесты движка draw-image от продакшн-шаблона templates/cover.svg (issue #196). Тесты теперь опираются на каноничный fixture, а продакшн-шаблон упрощён до чистой обложки — без badge/sub-icon/subtitle-слотов.
tests/fixtures/cover.svg— новый каноничный тестовый шаблон (1024×1024) со всеми типами слотов:icon(x=312,y=180,400×400,recolor=accent),sub-icon(x=412,y=600,200×200,recolor=accent),badge(x=780,y=780,180×180,bg=surface,border=accent,radius=0.5) и subtitle-строкаy="930". Стабильный контракт для тестов: badge x=780 y=780 w=180 h=180, subtitle y=930, icon recolor=accent.tests/helpers/fixtures.ts— helperloadFixture(name): читает изtests/fixtures/, не дублирует логикуloadTemplate. ЭкспортируетFIXTURES_DIR_ABS.--template-dirфлаг CLI —src/render.ts:loadTemplate(drawImageDir, name, templateDir?)принимает опциональныйtemplateDir(дефолт"templates"), поддерживает относительный (отdrawImageDir) и абсолютный путь.cli.ts: парсит--template-dir, пробрасывает вloadTemplate. Без флага →templates/(обратная совместимость, продакшн не сломан). Usage-сообщение обновлено.- 9 тестов переведены на fixture:
slot.test.ts,render.optional.test.ts,render.integration.test.ts,render.optional.integration.test.ts,e2e.test.ts,e2e.optional.test.ts,e2e.no-icon.test.ts,idempotency.test.ts,cleanup.test.ts. В unit/integration —loadTemplate(DRAW_IMAGE_DIR,"cover")→loadFixture("cover"). В e2e (CLI) — добавлен--template-dir tests/fixtures.e2e.bad-input.test.tsне тронут (проверяет несуществующий шаблон, не зависит от cover.svg). Вidempotency.test.tsубран неиспользуемый импортloadTemplate/loadBrand/buildSvg/computeHash/writeFileSync. templates/cover.svgупрощён — оставлен только icon-слот 520×520 (x=252,y=180) и title y=830. Удаленыsub-icon,badge, subtitle-<text>— чистая обложка. Перерендеренassets/cover.png(icon=opencode, title="opencode config", без subtitle): PNG побайтово идентичен предыдущему (cmp→ IDENTICAL, 18077 байт) — удалённые слоты в продакшн-рендере не использовались. Hash вcover.meta.jsonизменился (d052d8a9...vs646197c4...), т.к.computeHashхеширует весь templateSvg-контент, но пиксели идентичны.- Добавлен handoff + ADR-087.
Почему
10 из 15 тестов жёстко привязывались к продакшн templates/cover.svg через loadTemplate(DRAW_IMAGE_DIR,"cover") и проверяли конкретные продакшн-значения (badge x=780 y=780, subtitle y=930). Любое изменение обложки (размер/позиция иконки, удаление subtitle) ломало тесты — PR#195 уже сталкивался с этим (пришлось сохранить subtitle-слот в шаблоне, чтобы не сломать render.optional.test.ts). Отвязка даёт свободу менять продакшн-обложку без правок тестов: тесты получили стабильный fixture-контракт, а продакшн-шаблон упрощён до того, что реально нужно для обложки. Упрощение cover.svg и зелёные тесты после — прямое подтверждение, что отвязка работает (критерий приёмки issue).
Pending
— (после merge: fixture можно расширять новыми slot-типами без риска для продакшн-обложки)
Watch out
--template-dirотносительный путь —tests/fixturesв e2e-тестах резолвится отdrawImageDir(cwd CLI =DRAW_IMAGE_DIR), не от cwd запускающего. Абсолютный путь тоже поддерживается черезpath.isAbsolute. Продакшн-вызовы без флага используютtemplates/— обратно совместимо.- Hash
cover.meta.jsonизменился —computeHash(sha256) зависит от SVG-контента. Упрощённый шаблон короче → хеш другой (d052d8a9...), хотя PNG пиксели идентичны. Кэш-инвалидация ожидаема, на рендер не влияет. - ADR-087 / handoff файлы — созданы через scaffold-handoff.sh, переименованы в
pr-197-*/087-pr-197-*после create-pr (PR#197). Frontmatterpr: 197. e2e.bad-input.test.tsне переведён на--template-dir— он тестирует несуществующий шаблонnonexistent, который отсутствует в любом templateDir. Тест корректен для дефолтногоtemplates/и не зависит от cover.svg — оставлен как есть (соответствует контракту issue: «оставь как есть»).- PNG-идентичность — упрощение cover.svg не меняет пиксели, т.к.
render.tsдля пустых slots не вставляет SVG (нетslotSvgs), а conditional-regex ранее удалял subtitle-<text>при falsyargs.subtitle. Удаление этих элементов из шаблона = удаление мёртвого кода для продакшн-рендера.