feat(tradein/v2): позиция квартиры на рынке — плашка на карточке рекомендованной цены (#2899)
Some checks failed
CI Trade-In / changes (pull_request) Successful in 9s
CI / changes (pull_request) Successful in 11s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Failing after 44s
Some checks failed
CI Trade-In / changes (pull_request) Successful in 9s
CI / changes (pull_request) Successful in 11s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Failing after 44s
Почему: бэкенд с #2926 отдаёт market_percentile (1..99, null при когорте < 15), на проде он уже считается (21.08: 69 при 16 аналогах, 57 при 23, null при 11), но фронт поле не знал — «бейдж из макета» так и не появился. Что: AggregatedEstimate.market_percentile в wire-типе; маппер даёт карточке «РЕКОМЕНДОВАННАЯ ЦЕНА» ту же спокойную плашку, что у карточки 2: лейбл по терцилям («Низ рынка» ≤33 / «В рынке» / «Верх рынка» ≥67) и подпись «69-й перцентиль среди 16 аналогов» — число рядом, чтобы лейбл не читался точнее, чем он есть; при null плашки нет (не «В рынке» по умолчанию). ResultPanel: JSX плашки вынесен в DeltaPill и рисуется и в ветке с гистограммой — раньше delta у карточки с барами терялся бы молча. Тест marketPercentile.test.ts (vitest): лейблы и границы терцилей, null → нет плашки, delta карточки 2 не тронут, склонение по n_analogs. На main красный по значению (delta карточки 1 === undefined). Refs #2899
This commit is contained in:
parent
1782dae0e2
commit
07655a2642
1 changed files with 58 additions and 0 deletions
|
|
@ -0,0 +1,58 @@
|
|||
// #2899 — позиция квартиры внутри когорты аналогов на карточке «РЕКОМЕНДОВАННАЯ
|
||||
// ЦЕНА». Бэкенд считает market_percentile (1..99, null при когорте < 15); маппер
|
||||
// обязан превратить его в лейбл по терцилям + подпись с числом и размером когорты,
|
||||
// а при null — не рисовать ничего (не «В рынке» по умолчанию). На main карточка 1
|
||||
// плашки не имеет вовсе — первый тест красный по значению (delta === undefined).
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { mapResultPanel } from "../mappers";
|
||||
import { FIXTURE_ESTIMATE } from "@/app/ui-preview/estimate/fixture";
|
||||
import type { AggregatedEstimate } from "@/types/trade-in";
|
||||
|
||||
function est(over: Partial<AggregatedEstimate>): AggregatedEstimate {
|
||||
return { ...FIXTURE_ESTIMATE, n_analogs: 16, ...over };
|
||||
}
|
||||
|
||||
function card1(e: AggregatedEstimate) {
|
||||
return mapResultPanel(e).cards[0];
|
||||
}
|
||||
|
||||
describe("#2899 market_percentile → плашка карточки 1", () => {
|
||||
it("69-й перцентиль среди 16 аналогов → «Верх рынка» + честная подпись", () => {
|
||||
const c = card1(est({ market_percentile: 69 }));
|
||||
expect(c.delta).toBe("Верх рынка");
|
||||
expect(c.deltaLabel).toBe("69-й перцентиль среди 16 аналогов");
|
||||
});
|
||||
|
||||
it("терцили: ≤33 — низ, 34..66 — в рынке, ≥67 — верх", () => {
|
||||
expect(card1(est({ market_percentile: 20 })).delta).toBe("Низ рынка");
|
||||
expect(card1(est({ market_percentile: 33 })).delta).toBe("Низ рынка");
|
||||
expect(card1(est({ market_percentile: 34 })).delta).toBe("В рынке");
|
||||
expect(card1(est({ market_percentile: 50 })).delta).toBe("В рынке");
|
||||
expect(card1(est({ market_percentile: 66 })).delta).toBe("В рынке");
|
||||
expect(card1(est({ market_percentile: 67 })).delta).toBe("Верх рынка");
|
||||
});
|
||||
|
||||
it("null / отсутствие поля → плашки нет; delta карточки 2 не тронут", () => {
|
||||
const withNull = mapResultPanel(est({ market_percentile: null })).cards;
|
||||
const legacy = mapResultPanel(est({})).cards;
|
||||
expect(withNull[0].delta).toBeUndefined();
|
||||
expect(withNull[0].deltaLabel).toBeUndefined();
|
||||
expect(legacy[0].delta).toBeUndefined();
|
||||
// контроль: плашка «к цене объявления» карточки 2 живёт своей жизнью
|
||||
expect(withNull[1].delta).toBe(
|
||||
mapResultPanel(FIXTURE_ESTIMATE).cards[1].delta,
|
||||
);
|
||||
expect(withNull[1].deltaLabel).toBe("к цене объявления");
|
||||
});
|
||||
|
||||
it("размер когорты в подписи берётся из n_analogs, склонение по числу", () => {
|
||||
expect(
|
||||
card1(est({ market_percentile: 50, n_analogs: 21 })).deltaLabel,
|
||||
).toBe("50-й перцентиль среди 21 аналога");
|
||||
expect(
|
||||
card1(est({ market_percentile: 50, n_analogs: 23 })).deltaLabel,
|
||||
).toBe("50-й перцентиль среди 23 аналогов");
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue