test: cover unavailable public states

This commit is contained in:
ik
2026-09-21 08:12:04 +07:00
parent c84ec1eced
commit c5f9aa85a0
3 changed files with 27 additions and 1 deletions
+5
View File
@@ -9,6 +9,11 @@ const requested = Astro.url.searchParams.get("type") ?? "fish";
const type = allowed.has(requested) ? requested : "fish";
let assets: MediaAsset[] = [], unavailable = false;
try { assets = await api<MediaAsset[]>(`/api/v1/media/catalog?entity_type=${type}`); } catch { unavailable = true; }
if (unavailable) {
Astro.response.status = 503;
Astro.response.headers.set("Retry-After", "60");
Astro.response.headers.set("Cache-Control", "no-store");
}
const labels: Record<string,string> = {fish:"Рыбы",waterbody:"Водоёмы",tackle:"Снасти и приманки",reference:"Справочные материалы"};
---
<Layout title={`${labels[type]} RF4 — медиатека RF4 Spotter`} description="Изображения рыб, водоёмов и снастей Russian Fishing 4 с обязательной атрибуцией каждого источника.">
+21
View File
@@ -0,0 +1,21 @@
import { expect, test } from "@playwright/test";
for (const path of [
"/waterbodies",
"/waterbodies/vyunok",
"/waterbodies/vyunok/pike",
"/fish",
"/media?type=waterbody",
"/tackle",
"/tackle/analytics",
"/tackle/items/00000000-0000-0000-0000-000000000000",
]) {
test(`${path} exposes a cache-safe unavailable state`, async ({ page }) => {
const response = await page.goto(path);
expect(response?.status(), `${path} status`).toBe(503);
expect(response?.headers()["retry-after"], `${path} retry header`).toBe("60");
expect(response?.headers()["cache-control"], `${path} cache header`).toBe("no-store");
await expect(page.getByRole("alert")).toContainText(/временно недоступ|недоступен/i);
await expect(page.locator("body")).not.toContainText(/Traceback|localhost:8000|API \d+/i);
});
}
+1 -1
View File
@@ -56,7 +56,7 @@
- [ ] **W05 · Crosswalk источников.** Добавлен offline-конструктор консервативных предложений: нормализуются только точные имена/алиасы, неоднозначные и unmatched строки не получают canonical key; отсутствие ID выдаётся лишь диагностикой и не считается удалением. RF4MAP/RF4-STAT directory parsers теперь преобразуются в crosswalk identities без переноса метрик или автоматической привязки. Осталось подать полный набор реальных RF4DB/RF4MAP/RF4 Posts identities и вручную подтвердить результаты, включая три ранее отмеченных отсутствующих RF4MAP объекта.
- [ ] **W06 · Координаты и точность.** В `ExternalObservation`, staging, provenance опубликованного улова и публичных activity/spot-ответах добавлены `coordinate_raw`, `coordinate_precision = exact | approximate | area | missing` и список источников; RF4DB/RF4-STAT/RF4MAP/RF4 Posts parsers теперь протягивают исходную строку, включая строки без доступных числовых координат. Исправлена spot detail: точность (`точные`/`приблизительные`/`район`/`не указаны`) теперь видна рядом с координатами и покрыта smoke regression. In-app Chromium и focused smoke подтвердили `/spots/vyunok-321x654` на desktop/mobile без overflow; browser regression для отсутствующей точки проверяет недоступное состояние без ложных координат, а API regression параметризован по всем четырём precision-состояниям. Осталась полная browser QA матрица для всех precision/error-состояний.
- [ ] **W07 · Публичный API и страницы.** API и detail-страница теперь выводят подтверждённые detail-факты водоёма: описание, уровень, количество видов, алиасы, число ссылок на точки и отдельный счётчик изображений-кандидатов; источники и непроверенные media не смешиваются. Public media API теперь передаёт reviewed `media_role`, waterbody detail принимает только `waterbody_cover`/`waterbody_map`/`waterbody_depth_map`, а UI подписывает карту/заставку/скриншот текстом. Осталось завершить browser QA для реальных role-вариантов и не показывать abstract fingerprint как внешнее изображение.
- [ ] **W08 · Приёмка и эксплуатация.** Fixture-based parser tests, offline catalog/media audit и повторный idempotent import подтверждены: `created=0 updated=19`, в PostgreSQL ровно `19` RF4DB waterbodies плюс `2` legacy-записи, media audit сообщает `issues=[]` и `orphaned_files=[]`. In-app Chromium и focused smoke покрывают desktop/mobile основные страницы; 20.09 targeted waterbody E2E подтвердил detail с пустой активностью, not-found waterbody и not-found waterbody/fish pair, а spot regression — unavailable state без ложной координаты; полный web E2E прошёл `27 passed, 1 skipped`, visual-matrix также прошёл. Остаются полная browser QA error/empty matrix и закрытие внешних detail-данных. Сетевые тесты не выполнять; регулярный импорт оставить opt-in и под общим cooldown/backoff.
- [ ] **W08 · Приёмка и эксплуатация.** Fixture-based parser tests, offline catalog/media audit и повторный idempotent import подтверждены: `created=0 updated=19`, в PostgreSQL ровно `19` RF4DB waterbodies плюс `2` legacy-записи, media audit сообщает `issues=[]` и `orphaned_files=[]`. In-app Chromium и focused smoke покрывают desktop/mobile основные страницы; 20.09 targeted waterbody E2E подтвердил detail с пустой активностью, not-found waterbody и not-found waterbody/fish pair, а spot regression — unavailable state без ложной координаты; каталоги, media, analytics и tackle detail теперь имеют regression для `503` + `Retry-After` + `no-store` без утечки внутренних ошибок. Полный web E2E и visual-matrix остаются обязательным финальным прогоном; внешние detail-данные закрываются отдельно. Сетевые тесты не выполнять; регулярный импорт оставить opt-in и под общим cooldown/backoff.
### Каталог снастей, наживок и прочей оснастки