diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-17 14:32:37 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-17 14:32:37 +0800 |
| commit | 5c0ba37eda80d39e6ceca59bb1d5f4942f858995 (patch) | |
| tree | 948723f9cedf7ccb0707fa6ee516bd30fe20fd10 /frontend/src/lib/mobileCss.test.ts | |
| download | strategy-lab-5c0ba37eda80d39e6ceca59bb1d5f4942f858995.tar.gz | |
chore: establish Strategy Lab source baseline (development, not release)
Diffstat (limited to 'frontend/src/lib/mobileCss.test.ts')
| -rw-r--r-- | frontend/src/lib/mobileCss.test.ts | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/frontend/src/lib/mobileCss.test.ts b/frontend/src/lib/mobileCss.test.ts new file mode 100644 index 0000000..c4d1efb --- /dev/null +++ b/frontend/src/lib/mobileCss.test.ts @@ -0,0 +1,63 @@ +// @ts-nocheck +import { describe, expect, it } from 'vitest'; +// Live 375px browser overflow regression (artifacts/qa/supervisor-live/ +// mobile-overflow-probe.json): document scrollWidth measured 532 → 552 at a +// 375px viewport, sidebar/main 552px, cards 523px; DOM authoritative (a +// full-page screenshot expands to the overflow width, so source/DOM checks +// are the honest regression). Root causes are real CSS: grid min-content +// blow-up (layout/grid3), nowrap table cells, and unbreakable provider error +// URLs. CSS `?raw` imports are stubbed empty by vitest, so the real source +// files are read from disk instead. +import { readFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import path from 'node:path'; + +const srcRoot = path.join(fileURLToPath('file://' + process.cwd()), 'src'); +const appCss = readFileSync(path.join(srcRoot, 'app.css'), 'utf8'); +const layoutSource = readFileSync(path.join(srcRoot, 'components', 'Layout.svelte'), 'utf8'); +const datasetCard = readFileSync(path.join(srcRoot, 'components', 'DatasetCard.svelte'), 'utf8'); + +describe('375px responsive sizing (no global content hiding)', () => { + it('layout columns shrink below min-content (no document-level overflow)', () => { + // the mobile layout must be allowed to shrink (minmax(0,1fr), not bare 1fr) + expect(layoutSource).toMatch(/@media\s*\(max-width:\s*900px\)[\s\S]*?\.layout\s*\{[^}]*grid-template-columns:\s*minmax\(0,\s*1fr\)/); + // the content column opts out of min-content propagation + expect(layoutSource).toMatch(/\.content\s*\{[^}]*min-width:\s*0/); + // project tab context wraps instead of forcing one long line + expect(layoutSource).toMatch(/\.projctx\s*\{[^}]*flex-wrap:\s*wrap/); + }); + + it('multi-column forms and tables collapse/wrap on narrow view', () => { + expect(appCss).toContain('@media (max-width: 900px)'); + expect(appCss).toContain('.grid2, .grid3 { grid-template-columns: minmax(0, 1fr); }'); + expect(appCss).toContain('table.data th, table.data td {'); + expect(appCss).toContain('white-space: normal'); + }); + + it('long real provider errors wrap instead of inflating width', () => { + // `overflow-wrap: anywhere` wraps even long URL payloads; NOT + // overflow-x:hidden on body/document (that would hide content). + expect(appCss).toMatch(/\.banner\s*\{[^}]*overflow-wrap:\s*anywhere/); + expect(appCss.includes('body { overflow-x: hidden')).toBe(false); + expect(appCss.includes('html { overflow-x: hidden')).toBe(false); + }); + + it('dataset card keeps a local scroll container for tabular data', () => { + expect(datasetCard).toContain('scrollx'); + }); +}); + +function getMediaBlock(css, query) { + const idx = css.indexOf(`@media ${query}`); + if (idx < 0) return null; + const open = css.indexOf('{', idx); + let depth = 1; + for (let i = open + 1; i < css.length; i++) { + if (css[i] === '{') depth++; + else if (css[i] === '}') { + depth--; + if (depth === 0) return css.slice(idx, i + 1); + } + } + return null; +} |
