morphit/apps/web/scripts/featured-order-copy-smoke.ts

90 lines
4.6 KiB
TypeScript

#!/usr/bin/env tsx
/**
* Smoke: the "🚀 Feature this order!" copy and the homepage featured section
* (Ken, 2026-07-08).
*
* - The explainer names the duration the user actually selected (6h / 24h /
* 72h), not a vague "the selected duration".
* - It states the real slot cap. It used to say "Max 5 concurrent slots"
* while the indexer (`MAX_SLOTS = 3`) and the FAQ both said 3 — copy that
* hardcodes a number drifts silently, so the number now comes from a shared
* constant, and THIS smoke pins that constant to the indexer's value.
* - The homepage no longer prints a "FEATURED RIGHT NOW" eyebrow above the
* cards, but the section keeps an accessible name.
*/
import { readFileSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { SUPPORTED_LOCALES } from '../src/lib/i18n/locales';
const __dirname = dirname(fileURLToPath(import.meta.url));
const WEB = join(__dirname, '..');
const REPO = join(WEB, '..', '..');
const LOCALES = SUPPORTED_LOCALES.map((l) => l.code);
const form = readFileSync(join(WEB, 'src', 'lib', 'components', 'FeatureBidForm.svelte'), 'utf8');
const featured = readFileSync(join(WEB, 'src', 'lib', 'components', 'FeaturedOrders.svelte'), 'utf8');
const slotsConst = readFileSync(join(WEB, 'src', 'lib', 'orders', 'featuredSlots.ts'), 'utf8');
const indexerFeatured = readFileSync(
join(REPO, 'apps', 'indexer', 'src', 'api', 'featuredOrderbook.ts'),
'utf8'
);
let pass = 0;
let fail = 0;
function check(name: string, ok: boolean): void {
if (ok) {
pass++;
console.log(` \u2713 ${name}`);
} else {
fail++;
console.error(` \u2717 ${name}`);
}
}
// ─── slot-count parity: the drift that caused the wrong copy ─────────
const webSlots = /MAX_FEATURED_SLOTS = (\d+)/.exec(slotsConst)?.[1];
const idxSlots = /const MAX_SLOTS = (\d+)/.exec(indexerFeatured)?.[1];
check('web MAX_FEATURED_SLOTS is defined', webSlots !== undefined);
check('indexer MAX_SLOTS is defined', idxSlots !== undefined);
check(`featured-slot-count-parity (web ${webSlots} === indexer ${idxSlots})`, webSlots === idxSlots);
// ─── the explainer is interpolated, not hardcoded ────────────────────
check('explainer receives the SELECTED hours', /feature_bid\.explainer',[\s\S]{0,120}hours: selectedHours/.test(form));
check('explainer receives the slot count from the shared constant', /slots: MAX_FEATURED_SLOTS/.test(form));
check('FeatureBidForm imports the constant', /import \{ MAX_FEATURED_SLOTS \} from '\$lib\/orders\/featuredSlots';/.test(form));
check('the hours ladder still offers 6 / 24 / 72', /HOURS_OPTIONS = \[6, 24, 72\]/.test(form));
// ─── locale copy ─────────────────────────────────────────────────────
let allHave = true;
let anyFive = false;
let pluralOk = true;
for (const loc of LOCALES) {
const v = JSON.parse(readFileSync(join(WEB, 'src', 'lib', 'i18n', 'locales', `${loc}.json`), 'utf8'))
?.feature_bid?.explainer as string | undefined;
if (typeof v !== 'string' || !v.includes('{hours') || !v.includes('{slots}')) allHave = false;
if (typeof v === 'string' && /\b5\b/.test(v.replace('{slots}', ''))) anyFive = true;
if (typeof v === 'string' && !/\{hours, plural,/.test(v)) pluralOk = false;
}
check('all 10 locales interpolate {hours} and {slots}', allHave);
check('no locale still claims the stale "5" slots', !anyFive);
check('hours uses an ICU plural (correct forms in pl/ru)', pluralOk);
const en = JSON.parse(readFileSync(join(WEB, 'src', 'lib', 'i18n', 'locales', 'en.json'), 'utf8'))
.feature_bid.explainer as string;
check('EN reads "above the main orderbook, and on the homepage for …"', /above the main orderbook, and on the homepage for \{hours/.test(en));
check('EN reads "Only {slots} slots are available; highest per-hour bid wins:"', /Only \{slots\} slots are available; highest per-hour bid wins:$/.test(en));
// ─── homepage eyebrow removed, a11y preserved ────────────────────────
check('no visible "Featured right now" heading remains', !/id="featured-heading"/.test(featured) && !/<h2[\s\S]{0,160}featured\.heading/.test(featured));
check('the section keeps an accessible name', /<section aria-label=\{\$_\('featured\.heading'\)\}/.test(featured));
console.log('');
if (fail === 0) {
console.log(`\u2713 all ${pass} featured-order-copy scenarios passed`);
} else {
console.error(`\u2717 ${fail} of ${pass + fail} featured-order-copy checks FAILED`);
process.exit(1);
}