test(tradein): гейт «снять noindex можно только вместе с плейсхолдерами» (#2904) (#2948)
All checks were successful
Deploy Trade-In / changes (push) Successful in 14s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 3m18s
Deploy Trade-In / deploy (push) Successful in 1m6s
Deploy Trade-In / deploy-status (push) Successful in 1s
Deploy Trade-In / perimeter-smoke (push) Successful in 10s
All checks were successful
Deploy Trade-In / changes (push) Successful in 14s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 3m18s
Deploy Trade-In / deploy (push) Successful in 1m6s
Deploy Trade-In / deploy-status (push) Successful in 1s
Deploy Trade-In / perimeter-smoke (push) Successful in 10s
This commit is contained in:
parent
6bca4f7ead
commit
8db357ef30
1 changed files with 105 additions and 0 deletions
|
|
@ -0,0 +1,105 @@
|
||||||
|
/**
|
||||||
|
* Гейт #2904: снять `noindex` можно только вместе с плейсхолдерными числами.
|
||||||
|
*
|
||||||
|
* В `marketing-v3.ts` лежат величины из дизайн-макета, НЕ подтверждённые замером:
|
||||||
|
*
|
||||||
|
* | здесь | факт по замеру |
|
||||||
|
* | ошибка 1,8% | 13,2% медиана |%| (бэктест n=277), held-out 16,1% |
|
||||||
|
* | 83% в диапазон | 81,95%, но коридор шириной 74% от точки |
|
||||||
|
* | ±6 дн по сроку | сверки срока с фактом НЕ СУЩЕСТВУЕТ |
|
||||||
|
* | 42 700 проверок за год | 1 084 оценки всего (база живёт 2,5 месяца) |
|
||||||
|
* | 42 города РФ | 6 городов области, полное покрытие — 1 (ЕКБ) |
|
||||||
|
*
|
||||||
|
* Пока страница закрыта `robots: { index: false }`, эти строки никому не видны, и
|
||||||
|
* держать их допустимо. Публикация же недостоверных характеристик ПЛАТНОЙ услуги
|
||||||
|
* подпадает под ст. 5 ФЗ «О рекламе» и ЗоЗПП.
|
||||||
|
*
|
||||||
|
* До сих пор это правило жило ТОЛЬКО в комментарии модуля. Правило, записанное
|
||||||
|
* словами, не мешает снять одну строку в layout.tsx и выкатить страницу — поэтому
|
||||||
|
* гейт здесь механический: он краснеет ровно в тот момент, когда noindex исчезает,
|
||||||
|
* а плейсхолдеры остаются.
|
||||||
|
*
|
||||||
|
* Тест НЕ запрещает открывать страницу. Он требует, чтобы открытие шло вместе с
|
||||||
|
* заменой чисел на вычисляемые (или их снятием) — то есть чтобы решение было
|
||||||
|
* осознанным, а не побочным следствием правки метаданных.
|
||||||
|
*/
|
||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
import { join } from "node:path";
|
||||||
|
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
const ROOT = join(__dirname, "..");
|
||||||
|
|
||||||
|
function read(rel: string): string {
|
||||||
|
return readFileSync(join(ROOT, rel), "utf8");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Компоненты лэндинга v3, которые могут ссылаться на плейсхолдеры. */
|
||||||
|
const V3_SOURCES = [
|
||||||
|
"v3/page.tsx",
|
||||||
|
"_components/v3/HeroV3.tsx",
|
||||||
|
"_components/v3/AccuracyV3.tsx",
|
||||||
|
"_components/v3/FreeCheckCard.tsx",
|
||||||
|
"_components/v3/FreeResultV3.tsx",
|
||||||
|
];
|
||||||
|
|
||||||
|
const PLACEHOLDER_EXPORTS = [
|
||||||
|
"ACCURACY_PLACEHOLDER",
|
||||||
|
"COST_OF_ERROR_PLACEHOLDER",
|
||||||
|
"FREE_SAMPLE_PLACEHOLDER",
|
||||||
|
"PROOF_ROWS_PLACEHOLDER",
|
||||||
|
];
|
||||||
|
|
||||||
|
function placeholdersInUse(): string[] {
|
||||||
|
const used: string[] = [];
|
||||||
|
for (const rel of V3_SOURCES) {
|
||||||
|
let src: string;
|
||||||
|
try {
|
||||||
|
src = read(rel);
|
||||||
|
} catch {
|
||||||
|
continue; // файл переименован/удалён — не повод падать
|
||||||
|
}
|
||||||
|
for (const name of PLACEHOLDER_EXPORTS) {
|
||||||
|
if (src.includes(name) && !used.includes(name)) used.push(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return used;
|
||||||
|
}
|
||||||
|
|
||||||
|
function noindexIsOn(): boolean {
|
||||||
|
const layout = read("layout.tsx").replace(/\s+/g, " ");
|
||||||
|
return layout.includes("robots: { index: false");
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("гейт noindex ↔ плейсхолдерные числа (#2904)", () => {
|
||||||
|
it("пока плейсхолдеры на странице — noindex обязан стоять", () => {
|
||||||
|
const used = placeholdersInUse();
|
||||||
|
if (used.length === 0) {
|
||||||
|
// Числа заменены вычисляемыми — гейт больше не нужен, открывать можно.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
expect(noindexIsOn(), [
|
||||||
|
`лэндинг v3 всё ещё использует непроверенные величины: ${used.join(", ")},`,
|
||||||
|
"но `robots: { index: false }` в layout.tsx снят.",
|
||||||
|
"Перед открытием страницы наружу каждая цифра обязана быть заменена",
|
||||||
|
"вычисляемой либо снята — см. шапку marketing-v3.ts и issue #2904.",
|
||||||
|
].join(" ")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("сам гейт видит и плейсхолдеры, и noindex — иначе он проходил бы вхолостую", () => {
|
||||||
|
// Контроль на инструмент: если оба зонда перестанут находить своё
|
||||||
|
// (переименование файлов, смена формы записи), проверка выше станет
|
||||||
|
// зелёной по построению и перестанет что-либо охранять.
|
||||||
|
expect(placeholdersInUse().length, "ни один плейсхолдер не найден в компонентах v3 — зонд сломан").toBeGreaterThan(0);
|
||||||
|
expect(read("layout.tsx"), "layout.tsx не содержит блока robots — зонд сломан").toContain("robots");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("расхождение «заявлено против замера» остаётся в шапке модуля", () => {
|
||||||
|
// Таблица — единственное место, где зафиксировано, НАСКОЛЬКО числа расходятся
|
||||||
|
// с фактом. Потеряется она — и следующий читатель решит, что цифры проверены.
|
||||||
|
const mod = read("marketing-v3.ts");
|
||||||
|
expect(mod).toContain("13,2%");
|
||||||
|
expect(mod).toContain("НЕ СУЩЕСТВУЕТ");
|
||||||
|
expect(mod).toContain("1 084");
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Add table
Reference in a new issue