All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 10s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 1m4s
CI / openapi-codegen-check (pull_request) Successful in 2m7s
Follow-up #2451 (эпик #2445, B2/B3): тот же класс — object-literal lookup по значению, пришедшему из API, без runtime-guard. Значение вне закрытого union'а (schema drift / частичный деплой) даёт `undefined`, и дальше по-разному плохо: - `BestLayoutsBlock` (DataQualityCard) — обращение `.fg`/`.bg` к undefined РОНЯЕТ рендер всей карточки качества данных; - `ForecastChart.confidenceByHorizon` — подпись уверенности для горизонта пропадает МОЛЧА, при том что прогноз для него есть; - `compare/CompareTable` и `ptica/compare/PticaCompare` — рядом с процентом остаётся «73% · » и обрыв: число выглядит недосказанным, а не неизвестным. Везде нейтральный fallback по образцу VelocityBlock/ParcelDrawer: серый + «—», намеренно НЕ семантический цвет — неизвестное качество не должно читаться ни как хорошее, ни как плохое. Фон бейджа взят из существующего `--border-soft`: список токенов закрыт (ui-tokens.md — «НЕ выдумывать новые»), нейтральной заливки в нём нет. `DataQualityCard`, `confidenceByHorizon` и `METRIC_ROWS` (ptica) экспортированы ради тестов — тем же приёмом, что уже применён к `isDeficitDegenerate`. Тесты: 12 новых в 4 файлах. Проверены на слом — снял все четыре fallback'а, упало ровно 5 проверок out-of-union, остальные 7 (известные значения, отсутствующие данные) остались зелёными. `vitest run src/components/site-finder` — 145 passed, `tsc --noEmit` чисто. Closes #2452 Refs #2445, #2451
63 lines
2.8 KiB
TypeScript
63 lines
2.8 KiB
TypeScript
/**
|
||
* #2452 (follow-up #2445-B2/B3) — `CONFIDENCE_STYLES[dq.confidence]` не имел
|
||
* fallback'а: значение вне закрытого union'а (schema drift / частичный деплой)
|
||
* давало `undefined`, и следующее обращение `.fg`/`.bg` роняло рендер всей
|
||
* карточки качества данных.
|
||
*
|
||
* Тесты фиксируют нейтральный fallback (тот же паттерн, что VelocityBlock и
|
||
* ParcelDrawer): неизвестное качество рисуется серым и «—», а не падает и не
|
||
* выдаёт себя за хорошее или плохое.
|
||
*/
|
||
import { render, screen } from "@testing-library/react";
|
||
import { describe, expect, it } from "vitest";
|
||
|
||
import { DataQualityCard } from "../BestLayoutsBlock";
|
||
import type { BestLayoutsResponse } from "@/types/best-layouts";
|
||
|
||
type DataQuality = BestLayoutsResponse["data_quality"];
|
||
|
||
function makeDq(overrides: Partial<DataQuality> = {}): DataQuality {
|
||
return {
|
||
objects_with_velocity_data: 18,
|
||
objects_total_in_radius: 25,
|
||
raw_objects_total: 31,
|
||
groups_matched_by_core: 12,
|
||
groups_with_supply_only: 3,
|
||
velocity_coverage_pct: 72,
|
||
confidence: "high",
|
||
...overrides,
|
||
};
|
||
}
|
||
|
||
describe("DataQualityCard — нейтральный fallback (#2452)", () => {
|
||
it("известное значение рисуется своей меткой", () => {
|
||
render(<DataQualityCard dq={makeDq({ confidence: "low" })} />);
|
||
expect(screen.getByText("Низкое")).toBeInTheDocument();
|
||
});
|
||
|
||
it("значение вне union'а не роняет рендер и даёт «—»", () => {
|
||
const drifted = makeDq({
|
||
// Имитация schema drift: backend прислал значение вне
|
||
// "high"|"medium"|"low". Приведение через unknown, не через any.
|
||
confidence: "unverified" as unknown as DataQuality["confidence"],
|
||
});
|
||
|
||
expect(() => render(<DataQualityCard dq={drifted} />)).not.toThrow();
|
||
expect(screen.getByText("—")).toBeInTheDocument();
|
||
// Покрытие продолжает рисоваться — падает только метка, не вся карточка.
|
||
expect(screen.getByText(/покрытие 72%/)).toBeInTheDocument();
|
||
});
|
||
|
||
it("fallback не выглядит семантически (не зелёный и не красный)", () => {
|
||
const drifted = makeDq({
|
||
confidence: "unverified" as unknown as DataQuality["confidence"],
|
||
});
|
||
render(<DataQualityCard dq={drifted} />);
|
||
|
||
const badge = screen.getByText("—");
|
||
const style = badge.getAttribute("style") ?? "";
|
||
expect(style).not.toContain("--success");
|
||
expect(style).not.toContain("--danger");
|
||
expect(style).not.toContain("--warn");
|
||
});
|
||
});
|