64 lines
2.6 KiB
TypeScript
64 lines
2.6 KiB
TypeScript
/**
|
|
* faq-scroll-block-start-smoke — every scrollIntoView() in FaqSearch.svelte
|
|
* must use block:'start'.
|
|
*
|
|
* WHY: the FAQ page has a sticky header and a global `scroll-padding-top:
|
|
* 5rem` (app.css). With block:'start', scrollIntoView lands a clicked /
|
|
* Entered FAQ card so its TOP — the question title — sits just below the
|
|
* header, which is what the user wants to see ("did I land on the right
|
|
* article?"). block:'center' (the prior behavior) centers a tall card and
|
|
* pushes its title above the viewport, so the user scrolls "too far" and
|
|
* can't see the title. This smoke pins block:'start' for all FAQ-card
|
|
* scrolls and asserts the global offset it relies on still exists.
|
|
*
|
|
* Usage (from apps/web):
|
|
* tsx scripts/faq-scroll-block-start-smoke.ts
|
|
*/
|
|
|
|
import { readFileSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
|
|
const faqFile = join(import.meta.dirname, '..', 'src', 'lib', 'components', 'FaqSearch.svelte');
|
|
const cssFile = join(import.meta.dirname, '..', 'src', 'app.css');
|
|
const src = readFileSync(faqFile, 'utf-8');
|
|
const css = readFileSync(cssFile, 'utf-8');
|
|
|
|
let failures = 0;
|
|
let checks = 0;
|
|
function check(name: string, cond: boolean, detail = ''): void {
|
|
checks++;
|
|
if (cond) {
|
|
console.log(` ✓ ${name}`);
|
|
} else {
|
|
failures++;
|
|
console.log(` ✗ ${name}${detail ? ' — ' + detail : ''}`);
|
|
}
|
|
}
|
|
|
|
console.log('\n── FAQ scroll lands on card top ───────────────────────');
|
|
|
|
// Each scrollIntoView({...}) options object + the block alignment inside.
|
|
const calls = [...src.matchAll(/scrollIntoView\(\{[^}]*\}\)/g)].map((m) => m[0]);
|
|
check('found at least one scrollIntoView call', calls.length > 0, `found ${calls.length}`);
|
|
|
|
for (const [i, call] of calls.entries()) {
|
|
const m = call.match(/block:\s*'([^']+)'/);
|
|
const block = m ? m[1] : '(none specified)';
|
|
check(`scrollIntoView #${i + 1} uses block:'start'`, block === 'start', `got '${block}'`);
|
|
}
|
|
|
|
// Belt + suspenders: no center/end/nearest alignment lingering in the file.
|
|
check("no block:'center' remains in FaqSearch", !/block:\s*'center'/.test(src));
|
|
|
|
// The fix relies on the global header offset; if that's removed, the title
|
|
// would hide under the sticky header even with block:'start'.
|
|
check('global scroll-padding-top still set in app.css', /scroll-padding-top:\s*\S/.test(css));
|
|
|
|
console.log('');
|
|
if (failures === 0) {
|
|
console.log(`✓ all ${checks} faq-scroll-block-start scenarios passed (${calls.length} scrollIntoView calls, every block:'start')`);
|
|
process.exit(0);
|
|
} else {
|
|
console.log(`✗ ${failures} check(s) failed`);
|
|
process.exit(1);
|
|
}
|