fix(ptica): «Риск: Низкий» больше не выглядит вердиктом (#2934) #2939
4 changed files with 110 additions and 7 deletions
|
|
@ -80,11 +80,14 @@ export function InvestScoreBlock({
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.statLine}>
|
<div className={styles.statLine}>
|
||||||
<span className={styles.k}>Риск</span>
|
<span className={styles.k}>Риск</span>
|
||||||
<span
|
<span className={`${styles.v} ${toneClass(inv.riskTone)}`}>
|
||||||
className={`${styles.v} ${toneClass(inv.riskTone)}`}
|
|
||||||
title={inv.risk.caption}
|
|
||||||
>
|
|
||||||
{inv.risk.value}
|
{inv.risk.value}
|
||||||
|
{/* #2934: «предв.» было только в атрибуте title — на экране его не
|
||||||
|
видно, а на печати и подавно. Пометка о том, что оценка
|
||||||
|
предварительная, должна читаться там же, где значение. */}
|
||||||
|
{inv.risk.caption && (
|
||||||
|
<span className={styles.fieldCaption}> {inv.risk.caption}</span>
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
/**
|
||||||
|
* #2934: пометка «предв.» у строки «Риск» должна читаться на экране.
|
||||||
|
*
|
||||||
|
* Значение берётся из adaptRiskGauge = `100 - buildability`, то есть обратной
|
||||||
|
* застраиваемости. К природным опасностям (затопление, оползни, карст) оно
|
||||||
|
* отношения не имеет, а источники природного риска пусты: cad_risk_zones 0 строк,
|
||||||
|
* слои risk_* НСПД 0 объектов на 669 дампов (замер 19.08.2026).
|
||||||
|
*
|
||||||
|
* До правки «предв.» лежало ТОЛЬКО в атрибуте title — на экране невидимо, при
|
||||||
|
* печати тем более, а значение при этом красилось зелёным.
|
||||||
|
*/
|
||||||
|
import { render, screen } from "@testing-library/react";
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
import { InvestScoreBlock } from "../InvestScoreBlock";
|
||||||
|
import analyzeFixture from "@/lib/mocks/parcel-analyze.json";
|
||||||
|
import type { ParcelAnalysis } from "@/types/site-finder";
|
||||||
|
|
||||||
|
/** Участок с gate_verdict — иначе застраиваемость null и строка «Риск» пуста. */
|
||||||
|
function analysisWithGate(): ParcelAnalysis {
|
||||||
|
return {
|
||||||
|
...(analyzeFixture as unknown as ParcelAnalysis),
|
||||||
|
gate_verdict: {
|
||||||
|
can_build_mkd: true,
|
||||||
|
verdict_label: "Можно",
|
||||||
|
blockers: [],
|
||||||
|
warnings: [],
|
||||||
|
checks_performed: [],
|
||||||
|
source: "nspd_dump",
|
||||||
|
},
|
||||||
|
} as unknown as ParcelAnalysis;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("InvestScoreBlock — строка «Риск» (#2934)", () => {
|
||||||
|
it("показывает пометку «предв.» видимым текстом", () => {
|
||||||
|
render(
|
||||||
|
<InvestScoreBlock
|
||||||
|
analysis={analysisWithGate()}
|
||||||
|
onOpenDrawer={() => {}}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Предусловие: строка «Риск» вообще отрисована со значением.
|
||||||
|
expect(screen.getByText("Риск")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("Низкий")).toBeInTheDocument();
|
||||||
|
|
||||||
|
// На origin/main «предв.» живёт только в атрибуте title — getByText не найдёт.
|
||||||
|
expect(screen.getByText("предв.")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -17,6 +17,8 @@ import { describe, expect, it } from "vitest";
|
||||||
import {
|
import {
|
||||||
adaptBuySignalGauge,
|
adaptBuySignalGauge,
|
||||||
adaptEconomyCard,
|
adaptEconomyCard,
|
||||||
|
adaptInvestScore,
|
||||||
|
adaptRiskGauge,
|
||||||
adaptFinanceDrawer,
|
adaptFinanceDrawer,
|
||||||
adaptInvestmentClearance,
|
adaptInvestmentClearance,
|
||||||
adaptLegalDrawer,
|
adaptLegalDrawer,
|
||||||
|
|
@ -352,3 +354,44 @@ describe("ptica-adapt gate (#1892 ЗОУИТ area-gate)", () => {
|
||||||
expect(v.tone).toBe("good");
|
expect(v.tone).toBe("good");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("ptica-adapt risk placeholder (#2934)", () => {
|
||||||
|
/** Участок, у которого застраиваемость СЧИТАЕТСЯ: без gate_verdict она null,
|
||||||
|
* и тон был бы "none" просто из-за отсутствия данных — проверка прошла бы
|
||||||
|
* вхолостую и на неисправленном коде тоже. */
|
||||||
|
function analysisWithGate(): ParcelAnalysis {
|
||||||
|
return {
|
||||||
|
...analysis,
|
||||||
|
gate_verdict: {
|
||||||
|
can_build_mkd: true,
|
||||||
|
verdict_label: "Можно",
|
||||||
|
blockers: [],
|
||||||
|
warnings: [],
|
||||||
|
checks_performed: [],
|
||||||
|
source: "nspd_dump",
|
||||||
|
},
|
||||||
|
} as unknown as ParcelAnalysis;
|
||||||
|
}
|
||||||
|
|
||||||
|
it("«Риск» не окрашивается как вердикт, пока значение не настоящее", () => {
|
||||||
|
const a = analysisWithGate();
|
||||||
|
const gauge = adaptRiskGauge(a);
|
||||||
|
// Предусловие: значение реально посчитано, иначе тон был бы "none" по другой
|
||||||
|
// причине и проверка ничего бы не доказывала.
|
||||||
|
expect(gauge.value).not.toBeNull();
|
||||||
|
expect(gauge.tone).toBe("good"); // именно тот случай, что красился зелёным
|
||||||
|
expect(gauge.isReal).toBe(false);
|
||||||
|
|
||||||
|
expect(adaptInvestScore(a).riskTone).toBe("none");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("подпись «предв.» доезжает до поля, а не только до тултипа", () => {
|
||||||
|
const inv = adaptInvestScore(analysisWithGate());
|
||||||
|
expect(inv.risk.caption).toBe("предв.");
|
||||||
|
expect(inv.risk.isReal).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("контроль: «Потенциал» приглушён как и раньше", () => {
|
||||||
|
expect(adaptInvestScore(analysis).potentialTone).toBe("none");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -353,9 +353,16 @@ export function adaptInvestScore(
|
||||||
risk.value != null
|
risk.value != null
|
||||||
? { value: risk.label, isReal: false, caption: "предв." }
|
? { value: risk.label, isReal: false, caption: "предв." }
|
||||||
: placeholder("предв.");
|
: placeholder("предв.");
|
||||||
// Hero «Риск» value color (prototype .v.warn): green when low, yellow otherwise.
|
// #2934: плейсхолдер не красим как вердикт. `adaptRiskGauge` считает риск как
|
||||||
const riskTone: PticaValueTone =
|
// `100 - buildability`, то есть обратную застраиваемость — к природным опасностям
|
||||||
risk.value == null ? "none" : risk.tone === "good" ? "good" : "warn";
|
// (затопление, оползни, карст) он отношения не имеет, и сам помечен
|
||||||
|
// `isReal: false`. Зелёное «Низкий» читалось как «рисков нет», хотя источники
|
||||||
|
// природного риска пусты: cad_risk_zones 0 строк, слои risk_* НСПД 0 объектов на
|
||||||
|
// 669 дампов (замер 19.08).
|
||||||
|
//
|
||||||
|
// Приглушаем так же, как уже приглушён `potentialTone` — соглашение в этом же
|
||||||
|
// файле: пока значение не настоящее, цвета-вердикта у него нет.
|
||||||
|
const riskTone: PticaValueTone = "none";
|
||||||
|
|
||||||
const overall =
|
const overall =
|
||||||
report?.scoring?.overall ?? report?.exec_summary.key_numbers.overall_score;
|
report?.scoring?.overall ?? report?.exec_summary.key_numbers.overall_score;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue