All checks were successful
CI / changes (pull_request) Successful in 8s
CI Trade-In / changes (pull_request) Successful in 9s
CI Trade-In / backend-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 1m20s
CI / openapi-codegen-check (pull_request) Successful in 2m13s
Делает видимым backend-поле permits_nearby (PR #2401, ГИСОГД-66) на странице анализа участка: §6 «Риски и дефицит», сразу после блока будущего предложения. Рендерится независимо от статуса §22-прогноза (permits приходит быстро вместе с analyze, форсайт может считаться 30-180с) — блок первым в дереве §6 во всех трёх ветках pending/error/ready. Честный ноль (0 найдено — видимый нейтральный текст, не скрытие блока) отделён от отсутствия поля (старый кэш — блок молча не рендерится, не выдумывает «0»). items_truncated -> честная приписка «показаны ближайшие N из M». RS/RV — человеко-читаемые Badge-подписи, progressive disclosure (8 видимых + <details>) по паттерну ResourceReservesCard.
129 lines
4.5 KiB
TypeScript
129 lines
4.5 KiB
TypeScript
import { render, screen } from "@testing-library/react";
|
||
import { describe, expect, it } from "vitest";
|
||
|
||
import { PermitsNearbyBlock } from "../PermitsNearbyBlock";
|
||
|
||
// PermitsNearbyBlock — чистый компонент (нет useQuery), рендерим напрямую.
|
||
// Форму permits_nearby подаём как generic-объект (unknown на входе), как её
|
||
// отдаёт /analyze; проверяем honest-zero, RS/RV-подписи, truncated-приписку.
|
||
|
||
function buildPermit(overrides: Record<string, unknown> = {}) {
|
||
return {
|
||
doc_group: "RS",
|
||
doc_name: "Разрешение на строительство № 66-45-08-2026 от 02.06.2026",
|
||
doc_num: "66-45-08-2026",
|
||
date_doc: "2026-06-02",
|
||
approved_organization: "Комитет по архитектуре",
|
||
distance_m: 120.0,
|
||
...overrides,
|
||
};
|
||
}
|
||
|
||
describe("PermitsNearbyBlock", () => {
|
||
it("рендерит honest-zero строку при total_count === 0 (блок не скрыт)", () => {
|
||
render(
|
||
<PermitsNearbyBlock
|
||
permitsNearby={{
|
||
radius_m: 500,
|
||
total_count: 0,
|
||
rs_count: 0,
|
||
rv_count: 0,
|
||
nearest_distance_m: null,
|
||
items: [],
|
||
items_truncated: false,
|
||
source: "gisogd66",
|
||
}}
|
||
/>,
|
||
);
|
||
// Заголовок секции виден, и внутри — честная нейтральная строка.
|
||
expect(
|
||
screen.getByText("Разрешения на строительство поблизости"),
|
||
).toBeTruthy();
|
||
expect(
|
||
screen.getByText(/В радиусе 500 м новых разрешений не найдено/),
|
||
).toBeTruthy();
|
||
});
|
||
|
||
it("не рендерит ничего, когда permits_nearby отсутствует / null (старый кэш)", () => {
|
||
const { container: c1 } = render(
|
||
<PermitsNearbyBlock permitsNearby={null} />,
|
||
);
|
||
expect(c1.firstChild).toBeNull();
|
||
|
||
const { container: c2 } = render(
|
||
<PermitsNearbyBlock permitsNearby={undefined} />,
|
||
);
|
||
expect(c2.firstChild).toBeNull();
|
||
|
||
// Объект без обязательного total_count → тоже не рендерим.
|
||
const { container: c3 } = render(
|
||
<PermitsNearbyBlock permitsNearby={{ radius_m: 500 }} />,
|
||
);
|
||
expect(c3.firstChild).toBeNull();
|
||
});
|
||
|
||
it("показывает человеко-читаемые подписи RS → «Разрешение на строительство», RV → «Ввод в эксплуатацию»", () => {
|
||
render(
|
||
<PermitsNearbyBlock
|
||
permitsNearby={{
|
||
radius_m: 500,
|
||
total_count: 2,
|
||
rs_count: 1,
|
||
rv_count: 1,
|
||
nearest_distance_m: 0,
|
||
items: [
|
||
buildPermit({ doc_group: "RS" }),
|
||
buildPermit({
|
||
doc_group: "RV",
|
||
doc_name: "Разрешение на ввод объекта в эксплуатацию",
|
||
}),
|
||
],
|
||
items_truncated: false,
|
||
source: "gisogd66",
|
||
}}
|
||
/>,
|
||
);
|
||
expect(screen.getByText("Разрешение на строительство")).toBeTruthy();
|
||
expect(screen.getByText("Ввод в эксплуатацию")).toBeTruthy();
|
||
});
|
||
|
||
it("НЕ показывает truncated-приписку, когда items_truncated === false", () => {
|
||
render(
|
||
<PermitsNearbyBlock
|
||
permitsNearby={{
|
||
radius_m: 500,
|
||
total_count: 1,
|
||
rs_count: 1,
|
||
rv_count: 0,
|
||
nearest_distance_m: 120,
|
||
items: [buildPermit()],
|
||
items_truncated: false,
|
||
source: "gisogd66",
|
||
}}
|
||
/>,
|
||
);
|
||
expect(screen.queryByText(/Показаны ближайшие/)).toBeNull();
|
||
});
|
||
|
||
it("показывает truncated-приписку «показаны ближайшие N из M», когда items_truncated === true", () => {
|
||
const items = Array.from({ length: 30 }, (_, i) =>
|
||
buildPermit({ doc_num: `66-${i}` }),
|
||
);
|
||
render(
|
||
<PermitsNearbyBlock
|
||
permitsNearby={{
|
||
radius_m: 500,
|
||
total_count: 42,
|
||
rs_count: 20,
|
||
rv_count: 22,
|
||
nearest_distance_m: 0,
|
||
items,
|
||
items_truncated: true,
|
||
source: "gisogd66",
|
||
}}
|
||
/>,
|
||
);
|
||
// «Показаны ближайшие 30 из 42.»
|
||
expect(screen.getByText(/Показаны ближайшие 30 из 42/)).toBeTruthy();
|
||
});
|
||
});
|