From fd1affca8b5d57fe61299857e67a12b50557de1c Mon Sep 17 00:00:00 2001 From: bot-backend Date: Fri, 7 Aug 2026 14:48:01 +0500 Subject: [PATCH] =?UTF-8?q?test(tradein/frontend):=20=D0=BA=D0=BE=D0=BB?= =?UTF-8?q?=D0=BE=D0=BD=D0=BA=D0=B0=20=D1=81=D1=81=D1=8B=D0=BB=D0=BA=D0=B8?= =?UTF-8?q?=20=D0=B2=20=C2=AB05=20=D0=A0=D0=AB=D0=9D=D0=9E=D0=9A=C2=BB=20?= =?UTF-8?q?=E2=80=94=20=D0=BF=D1=80=D0=BE=D1=87=D0=B5=D1=80=D0=BA,=20?= =?UTF-8?q?=D0=B0=20=D0=BD=D0=B5=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA=D0=B0-?= =?UTF-8?q?=D0=BE=D0=B1=D0=BC=D0=B0=D0=BD=D0=BA=D0=B0=20(#2755)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Проверка на удалённую в предыдущем коммите ветку. Она была недостижима, но выглядела как рабочий элемент интерфейса — некликабельный , стилизованный под кнопку-ссылку «Росреестр ↗». Без проверки ничто не мешает ей вернуться: достаточно снова сделать поле опциональным. Три утверждения через настоящий mapSources: есть URL — ссылка именно на него; URL нет — прочерк и НИ ОДНОЙ ссылки; javascript:-схема отбрасывается safeUrl, и строка тоже получает прочерк, а не кнопку. Проверено, что тест краснеет: возврат «Росреестр ↗» на место прочерка роняет 2 утверждения из 3. Refs #2755 --- .../v2/__tests__/SourcesView.test.tsx | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 tradein-mvp/frontend/src/components/trade-in/v2/__tests__/SourcesView.test.tsx diff --git a/tradein-mvp/frontend/src/components/trade-in/v2/__tests__/SourcesView.test.tsx b/tradein-mvp/frontend/src/components/trade-in/v2/__tests__/SourcesView.test.tsx new file mode 100644 index 00000000..3ab3a05d --- /dev/null +++ b/tradein-mvp/frontend/src/components/trade-in/v2/__tests__/SourcesView.test.tsx @@ -0,0 +1,94 @@ +// #2755 — колонка ссылки в таблице аналогов «05 РЫНОК». +// +// Здесь до этого жила третья ветка: когда `url` приходил `undefined`, рисовался +// НЕкликабельный , стилизованный под кнопку-ссылку «Росреестр ↗». Ветка +// была недостижима (mapSources всегда ставит `string | null`), но выглядела как +// рабочий элемент интерфейса. Ветку убрали, поле сделали обязательным — этот +// тест держит обе половины: ссылка есть только там, где есть URL, а строка без +// URL получает прочерк, а не кнопку-обманку. + +import { render, screen } from "@testing-library/react"; +import { describe, expect, it } from "vitest"; + +import SourcesView from "../SourcesView"; +import { mapSources } from "../mappers"; +import { FIXTURE_ESTIMATE } from "@/app/ui-preview/estimate/fixture"; +import type { AggregatedEstimate, AnalogLot } from "@/types/trade-in"; + +function lot(over: Partial): AnalogLot { + return { + address: "ул. Репина, 73", + area_m2: 54, + rooms: 2, + floor: 7, + total_floors: 16, + price_rub: 9_700_000, + price_per_m2: 179_629, + listing_date: "2026-05-12", + days_on_market: 18, + photo_url: null, + source: "avito", + source_url: null, + distance_m: 120, + tier: null, + lat: 56.8401, + lon: 60.5702, + ...over, + }; +} + +// Оффлайн-фикстура оценки репозитория с подменёнными аналогами: остальные поля +// (sources_used, коридоры, KPI) настоящие, меняем ровно то, что проверяем. +function estimateWith(analogs: AnalogLot[]): AggregatedEstimate { + return { + ...FIXTURE_ESTIMATE, + analogs, + n_analogs: analogs.length, + actual_deals: [], + }; +} + +describe("SourcesView — колонка ссылки на оригинал", () => { + it("есть URL — кликабельная ссылка на него", () => { + const estimate = estimateWith([ + lot({ + address: "ул. Репина, 73", + source_url: "https://www.avito.ru/ekaterinburg/kvartiry/1", + }), + ]); + + render(); + + const link = screen.getByRole("link", { name: /Источник/ }); + expect(link).toHaveAttribute( + "href", + "https://www.avito.ru/ekaterinburg/kvartiry/1", + ); + }); + + it("URL нет — прочерк, а не кнопка-обманка «Росреестр ↗»", () => { + const estimate = estimateWith([ + lot({ address: "ул. Викулова, 33", source_url: null }), + ]); + + render(); + + expect(screen.queryByText(/Росреестр ↗/)).toBeNull(); + expect(screen.queryByRole("link", { name: /Источник/ })).toBeNull(); + // Прочерк — единственное содержимое ячейки ссылки в строке аналога. + const row = screen.getByText("ул. Викулова, 33").closest("div"); + expect(row?.textContent).toContain("—"); + }); + + it("javascript:-схема отбрасывается safeUrl — прочерк, а не ссылка", () => { + const estimate = estimateWith([ + lot({ address: "ул. Кирова, 28", source_url: "javascript:alert(1)" }), + ]); + + render(); + + expect(screen.queryByRole("link", { name: /Источник/ })).toBeNull(); + const row = screen.getByText("ул. Кирова, 28").closest("div"); + expect(row?.textContent).toContain("—"); + }); +});