test(decor): путь загрузки картинки под автотестом

`src/backdrop-pick.ts` и `src/decor-image-editor.ts` не входили в
tsconfig.test.json — юнитов у них не было вовсе. Смок при этом подменял
`hass.callWS` целиком и до `uploadFromInput`, `upload`, `delete` не
доходил; в шапке файла это было честно написано. AC1 #51 обещал
доказательство «component unit + smoke» — не было ни того, ни другого.

Цена известна: #427 — файл тяжелее 2 МиБ нельзя было добавить ничем,
гасли обе кнопки диалога, включая «уменьшить копию», — прожил четыре
круга ревью именно потому, что этот путь не проверяло ничто.

Оба файла теперь в tsconfig.test.json (компиляция +6 с, без правок
продуктового кода) и покрыты 13 юнитами:

- классификация: проходной файл, тяжелее лимита источника (guard с
  probe.kind='safe' — предупреждение о размере, не об отказе), warn,
  hard, unknown, неподдерживаемый формат;
- состав кнопок диалога на трёх случаях. Декор свыше лимита: «Отмена» и
  «уменьшить копию», без «оставить оригинал» — это и есть #427. Подложка
  на том же файле сохраняет обе кнопки, hard остаётся с одной «Отмена»,
  unknown предупреждает, а не проходит тихо;
- uploadFromInput: сброс input.value, молчание на занятом, отказ формата,
  исключение классификации, передача флага замены в оба слота;
- upload: multipart-поле и URL, порядок каталога, палитра против замены
  ссылки в диалоге, восемь ответов бэкенда с разными текстами, отпускание
  busy на отказе, запрет второго запроса поверх незакончившегося;
- delete: ссылки на ассет, отказ в подтверждении, чистка каталога, карты
  и палитры, различение in_use, сохранность каталога на отказе сервера;
- loadCatalog: отбор валидных строк и тост на отказе.

Смок `smoke_decor_images.mjs` получил последний блок, который проходит
настоящие uploadFromInput → upload → delete в собранном бандле, подменяя
только транспорт: fetchWithAuth и одну ветку callWS.

Свидетели (§2.7, #435). Девять мутаций прогнаны на собранном дереве,
каждая краснит свой тест: условие #427 → тест состава кнобок; снятие
лимита источника; input.value; флаг замены; too_large; busy в upload;
подтверждение удаления; used_by; проглоченный отказ каталога. Мутация
busy сначала вешала прогон и уносила пять тестов cancelledByParent —
тест переписан так, чтобы падать на сравнении, а не по таймауту.

В реестр добавлены три мутанта на продуктовый код: условие #427, потеря
флага замены, схлопывание кодов ошибок.

Гейты: npm test 1806 tests, 1805 pass, 0 fail (было 1791);
mutation-gate --check зелёный. Смок локально не прогнать — Chromium в
песочнице нет, проверит CI.

Issue: #433
User-Visible: no
This commit is contained in:
Claude
2026-09-03 13:21:08 +03:00
parent a6a9757b6d
commit d1091b6d47
4 changed files with 521 additions and 1 deletions
+36
View File
@@ -4849,6 +4849,42 @@ const MUTANT_DEFINITIONS = [
replace: ' stable = True\n',
}],
},
{
id: 'decor-oversize-hides-the-downscale-action',
guard: 'node --test test/decor-image-upload.test.mjs',
because: 'a decor source above the 2 MiB asset limit must still be offered as a reduced '
+ 'copy: the flag forbids keeping the ORIGINAL, and gating the whole action block on it '
+ 'is #427 — a bug that survived four review rounds because this path had no test at all',
patches: [{
file: 'src/backdrop-pick.ts',
find: ' ${hard ? null : html`',
replace: ' ${hard || !allowOriginal ? null : html`',
}],
},
{
id: 'decor-upload-loses-the-replace-flag',
guard: 'node --test test/decor-image-upload.test.mjs',
because: 'the guard dialog must upload into whichever slot the caller asked for: losing the '
+ 'replaceSelection flag silently turns "replace this image" into "arm the palette" and '
+ 'leaves the selected shape pointing at the old asset (#51 AC1, #433)',
patches: [{
file: 'src/decor-image-editor.ts',
find: ' this.hooks.setGuardReplace(replaceSelection);',
replace: ' this.hooks.setGuardReplace(false);',
}],
},
{
id: 'decor-upload-error-codes-collapse',
guard: 'node --test test/decor-image-upload.test.mjs',
because: 'each backend refusal code carries its own message: collapsing too_large into the '
+ 'generic io_error tells the user "something went wrong" where the product knows exactly '
+ 'what went wrong and how to fix it (#433)',
patches: [{
file: 'src/decor-image-editor.ts',
find: " too_large: 'backdrop.too_large_title',\n",
replace: '',
}],
},
{
id: 'pure-backend-test-pulls-home-assistant',
guard: 'python3 -m pytest tests_backend/test_backend_quality.py -q -p no:cacheprovider',