diff --git a/tradein-mvp/frontend/src/app/mera-public/__tests__/backtest-window-labels.test.tsx b/tradein-mvp/frontend/src/app/mera-public/__tests__/backtest-window-labels.test.tsx new file mode 100644 index 00000000..27235f9f --- /dev/null +++ b/tradein-mvp/frontend/src/app/mera-public/__tests__/backtest-window-labels.test.tsx @@ -0,0 +1,68 @@ +/** + * Подписи бэктеста обязаны описывать ТО окно, по которому числа посчитаны. + * + * 31.08.2026 числа перевели на представительную выборку (медиана трёх + * пересборок), но подписи остались от прежнего прогона: «сделки II квартала + * 2026 года» и знаменатель 5 954 (только этот квартал). Замер показал, что + * пересборка покрывает ЧЕТЫРЕ квартала и II квартал 2026 — лишь 24 % её + * сделок. Доля выборки при старом знаменателе выходила 5,5 % вместо 1,3 %, + * то есть вчетверо льстила. + * + * Отдельно: плитка «уверенность низкая» показывалась БЕЗ своей оговорки — + * `AccuracyV3` собирал оговорки только двух величин из трёх. + */ +import { render, screen } from "@testing-library/react"; +import { describe, expect, it } from "vitest"; + +import { AccuracyV3 } from "../_components/v3/AccuracyV3"; +import { + BACKTEST, + BACKTEST_PERIOD_LABEL, + BACKTEST_POPULATION, + BACKTEST_SHARE_LABEL, +} from "../landing-facts"; + +describe("подписи окна бэктеста", () => { + it("окно названо целиком, а не одним кварталом из четырёх", () => { + // Прежняя подпись называла II квартал 2026 — в представительной выборке + // это 24 % сделок, а не все. + expect(BACKTEST_PERIOD_LABEL).not.toMatch(/^сделки II квартала/u); + expect(BACKTEST_PERIOD_LABEL).toMatch(/четыре квартала/u); + }); + + it("знаменатель — того же окна, что и выборка", () => { + // 5 954 — только II квартал 2026; окно целиком — 24 333 (замер 31.08.2026). + expect(BACKTEST_POPULATION).toBe(24_333); + }); + + it("доля выборки выводится и получается около 1,3 %, а не 5,5 %", () => { + const share = (BACKTEST.priceError.sampleN / BACKTEST_POPULATION) * 100; + expect(share).toBeGreaterThan(1.0); + expect(share).toBeLessThan(2.0); + expect(BACKTEST_SHARE_LABEL).toBe("1,3 %"); + }); + + it("уверенность посчитана на том же прогоне, что и остальные числа", () => { + // «325 из 327» было из прогона 29.08 и под общей подписью «замер 31.08» + // приписывало старому числу новую дату. + expect(BACKTEST.confidenceLow.text).not.toMatch(/327/u); + }); +}); + +describe("оговорки в интерфейсе", () => { + it("на экране есть оговорки ВСЕХ ТРЁХ величин блока", () => { + render(); + for (const набор of [ + BACKTEST.priceError.caveats, + BACKTEST.coverage.caveats, + BACKTEST.confidenceLow.caveats, + ]) { + for (const line of набор) { + expect( + screen.queryByText(line), + `оговорка не выводится: ${line.slice(0, 48)}…`, + ).not.toBeNull(); + } + } + }); +}); diff --git a/tradein-mvp/frontend/src/app/mera-public/_components/v3/AccuracyV3.tsx b/tradein-mvp/frontend/src/app/mera-public/_components/v3/AccuracyV3.tsx index 2be7c7d8..418fff0b 100644 --- a/tradein-mvp/frontend/src/app/mera-public/_components/v3/AccuracyV3.tsx +++ b/tradein-mvp/frontend/src/app/mera-public/_components/v3/AccuracyV3.tsx @@ -114,9 +114,14 @@ export function AccuracyV3({ }); } + // Оговорки ВСЕХ ТРЁХ величин блока, а не двух. `confidenceLow` показывается + // отдельной плиткой, но её оговорка сюда не попадала — то есть на экране + // стояло «400 из 400 — уверенность низкая» без единого слова о том, почему. + // Плитка без своей оговорки — ровно то, что этот блок и не должен делать. const caveats = [ ...BACKTEST.priceError.caveats, ...BACKTEST.coverage.caveats, + ...BACKTEST.confidenceLow.caveats, ]; const deals = showcase?.deals ?? []; diff --git a/tradein-mvp/frontend/src/app/mera-public/landing-facts.ts b/tradein-mvp/frontend/src/app/mera-public/landing-facts.ts index 9b0aef3a..d0688d7c 100644 --- a/tradein-mvp/frontend/src/app/mera-public/landing-facts.ts +++ b/tradein-mvp/frontend/src/app/mera-public/landing-facts.ts @@ -97,14 +97,20 @@ export const BACKTEST: Readonly 0, + * `deal_date >= 2025-06-01`, город Екатеринбург): **24 333** сделки. + * + * ЗНАМЕНАТЕЛЬ БЕРЁТСЯ ИЗ ТОГО ЖЕ ОКНА, ЧТО И ВЫБОРКА — правило не изменилось, + * изменилось окно. Раньше здесь стояло 5 954 (только II квартал 2026), и это + * было верно для прогона 29.08, который в один квартал и укладывался. Для + * пересборок вразброс, покрывающих четыре квартала, тот же знаменатель дал бы + * долю вчетверо больше реальной — 5,5 % вместо 1,3 %. + * + * Обе величины проверены одним запросом: в окне 24 333, из них с + * `deal_date = 2026-04-01` — 5 954. */ -export const BACKTEST_POPULATION = 5_954; +export const BACKTEST_POPULATION = 24_333; /** * Доля выборки. ВЫВОДИТСЯ, а не вписывается: разъехаться с `sampleN` не может.