From d541443a1a61d1dbc83b5d97254fea7ae95d8046 Mon Sep 17 00:00:00 2001 From: IK Date: Sun, 20 Sep 2026 18:42:33 +0700 Subject: [PATCH] test: cover tackle browser acceptance --- apps/web/tests/production-bootstrap.spec.ts | 4 ++++ apps/web/tests/tackle.spec.ts | 18 ++++++++++++++++++ docs/ROADMAP.md | 2 +- 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 apps/web/tests/tackle.spec.ts diff --git a/apps/web/tests/production-bootstrap.spec.ts b/apps/web/tests/production-bootstrap.spec.ts index eda87f1..88d53b8 100644 --- a/apps/web/tests/production-bootstrap.spec.ts +++ b/apps/web/tests/production-bootstrap.spec.ts @@ -1,6 +1,10 @@ import { expect, test } from "@playwright/test"; test("production bootstrap supports submission and moderation", async ({ page, request }) => { + test.skip( + !process.env.BOOTSTRAP_API_URL || !process.env.BOOTSTRAP_ADMIN_TOKEN, + "requires BOOTSTRAP_API_URL and BOOTSTRAP_ADMIN_TOKEN; run deploy/test-production-bootstrap.sh", + ); const player = `Bootstrap Player ${Date.now()}`; const x = 7000 + Date.now() % 1000; const y = x + 1; diff --git a/apps/web/tests/tackle.spec.ts b/apps/web/tests/tackle.spec.ts new file mode 100644 index 0000000..d7de6e3 --- /dev/null +++ b/apps/web/tests/tackle.spec.ts @@ -0,0 +1,18 @@ +import { expect, test } from "@playwright/test"; + +test("tackle catalog exposes an explicit empty state for unmatched filters", async ({ page }) => { + await page.setViewportSize({ width: 320, height: 800 }); + await page.goto("/tackle?category=lure&brand=NoSuchBrand&family=NoSuchFamily"); + + await expect(page.getByRole("heading", { name: "Подтверждённых карточек пока нет" })).toBeVisible(); + await expect(page.getByRole("link", { name: "Сбросить" })).toHaveAttribute("href", "/tackle"); + await expect(page.getByLabel("Категория")).toHaveValue("lure"); + await expect(page.getByLabel("Бренд")).toHaveValue("NoSuchBrand"); + await expect(page.getByLabel("Семейство")).toHaveValue("NoSuchFamily"); + + const dimensions = await page.evaluate(() => ({ + clientWidth: document.documentElement.clientWidth, + scrollWidth: document.documentElement.scrollWidth, + })); + expect(dimensions.scrollWidth).toBeLessThanOrEqual(dimensions.clientWidth); +}); diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 8c51d63..a32c1c3 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -74,7 +74,7 @@ - [ ] **G06 · API и публичный каталог.** Добавлены пагинированный `/api/v1/tackle/items` с фильтрами по категории, бренду, семейству и уровню, detail endpoints для предмета и монтажа, а также ordered `tackle_components` в ответе уловов точки. Ответы показывают только канонические характеристики, provenance, timestamp проверки и `missing_fields`; рейтинг эффективности не добавляется. Остаётся подключить публичные Astro-карточки и ссылки из всех нужных представлений улова. - [ ] **G07 · Аналитика сочетаний и рекомендации.** Добавлен `/api/v1/analytics/tackle`: approved-наблюдения группируются по роли и исходному компоненту с фильтрами водоёма, рыбы, метода и окна; дубликаты одного улова не увеличивают счётчик, а минимум наблюдений и независимых игроков отделяет факт использования от рекомендации. Пустая или малая выборка получает `insufficient_data`; decay по свежести и отдельные UI-состояния остаются следующим шагом. - [ ] **G08 · Медиа и качество.** Добавлены отдельные reviewed-роли `tackle_card`, `tackle_detail`, `rig_diagram`, `tackle_screenshot` для `tackle`, а также CLI-параметр `--media-role`; offline audit отклоняет неизвестную роль и несовпадение роли с entity type. Существующие dimensions, MIME, SHA-256, прозрачность, aspect ratio, provenance и атомарное продвижение сохраняются. Остаётся провести реальный contact-sheet review для будущих tackle-кандидатов без автоматической публикации. -- [ ] **G09 · Приёмка и эксплуатация.** Добавлены fixture/regression tests для crosswalk, media roles, идемпотентных компонентов, пустых результатов и многокомпонентных наблюдений; каталог `/tackle` включён в visual-matrix, narrow smoke и accessibility routes. Offline catalog/media audits и сохранение старых данных при сбое проходят. Добавлен TEMP-only query-plan gate для фильтра каталога и группировки сочетаний: production-фильтры должны использовать индексы и укладываться в 250 мс. Остаются HTTP/browser acceptance для пустых, неоднозначных и многокомпонентных комплектов. Сетевые тесты не выполнять; импорт оставить opt-in, последовательным и под общим cooldown/backoff. Закрывать пакет только после проверяемого счётчика по каждой категории либо явной фиксации `unknown`. +- [ ] **G09 · Приёмка и эксплуатация.** Добавлены fixture/regression tests для crosswalk, media roles, идемпотентных компонентов, пустых результатов и многокомпонентных наблюдений; каталог `/tackle` включён в visual-matrix, narrow smoke и accessibility routes. Offline catalog/media audits и сохранение старых данных при сбое импорта проходят. TEMP-only query-plan gate для фильтра каталога и группировки сочетаний использует индексы и укладывается в 250 мс. Chromium подтвердил empty-state публичного каталога и отсутствие overflow на 320 px; обычный E2E пропускает bootstrap без явных переменных, отдельный bootstrap с токеном проходит. Остаются HTTP/browser acceptance для неоднозначных и многокомпонентных комплектов, ручной visual review и проверяемый счётчик по категориям либо явный `unknown`. Сетевые тесты не выполнять; импорт оставить opt-in, последовательным и под общим cooldown/backoff. ### Тёмная тема