gendesign/frontend/src/components/site-finder/analysis/__tests__/PermitsNearbyBlock.test.tsx
bot-backend b76bb4f7ea
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
feat(site-finder): PermitsNearbyBlock — разрешения на строительство в §6 (#2367 PR-2, frontend-half)
Делает видимым 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.
2026-07-04 15:21:16 +05:00

129 lines
4.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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();
});
});