= {}) {
+ 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(
+
,
+ );
+ // Заголовок секции виден, и внутри — честная нейтральная строка.
+ expect(
+ screen.getByText("Разрешения на строительство поблизости"),
+ ).toBeTruthy();
+ expect(
+ screen.getByText(/В радиусе 500 м новых разрешений не найдено/),
+ ).toBeTruthy();
+ });
+
+ it("не рендерит ничего, когда permits_nearby отсутствует / null (старый кэш)", () => {
+ const { container: c1 } = render(
+
,
+ );
+ expect(c1.firstChild).toBeNull();
+
+ const { container: c2 } = render(
+
,
+ );
+ expect(c2.firstChild).toBeNull();
+
+ // Объект без обязательного total_count → тоже не рендерим.
+ const { container: c3 } = render(
+
,
+ );
+ expect(c3.firstChild).toBeNull();
+ });
+
+ it("показывает человеко-читаемые подписи RS → «Разрешение на строительство», RV → «Ввод в эксплуатацию»", () => {
+ render(
+
,
+ );
+ expect(screen.getByText("Разрешение на строительство")).toBeTruthy();
+ expect(screen.getByText("Ввод в эксплуатацию")).toBeTruthy();
+ });
+
+ it("НЕ показывает truncated-приписку, когда items_truncated === false", () => {
+ render(
+
,
+ );
+ expect(screen.queryByText(/Показаны ближайшие/)).toBeNull();
+ });
+
+ it("показывает truncated-приписку «показаны ближайшие N из M», когда items_truncated === true", () => {
+ const items = Array.from({ length: 30 }, (_, i) =>
+ buildPermit({ doc_num: `66-${i}` }),
+ );
+ render(
+
,
+ );
+ // «Показаны ближайшие 30 из 42.»
+ expect(screen.getByText(/Показаны ближайшие 30 из 42/)).toBeTruthy();
+ });
+});
diff --git a/frontend/src/types/site-finder.ts b/frontend/src/types/site-finder.ts
index 3ed312de..758195c8 100644
--- a/frontend/src/types/site-finder.ts
+++ b/frontend/src/types/site-finder.ts
@@ -550,6 +550,11 @@ export interface ParcelAnalysis {
// это поле ТОЛЬКО при отрицательном фин-вердикте (program_optimizer.py);
// на позитивных участках null / отсутствует. Hand-typed (extra=allow на backend).
program_alternatives?: ProgramAlternatives | null;
+ // #2367 — разрешения на строительство (RS) и вводы в эксплуатацию (RV) в
+ // радиусе 500 м по реестру ГИСОГД. Backend держит блок как dict[str, Any] |
+ // None, поэтому здесь — generic-объект; строгую форму narrow'ит
+ // PermitsNearbyBlock в рантайме. Может отсутствовать/быть null (старый кэш).
+ permits_nearby?: Record
| null;
}
/**