test(ui): lock responsive shell breakpoints

This commit is contained in:
Saravana Achu Mac 2026-05-09 02:06:52 -07:00
parent a65d7261ca
commit c51544aa29

View File

@ -0,0 +1,75 @@
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
import { describe, expect, it } from 'vitest';
const css = readFileSync(resolve(__dirname, 'index.css'), 'utf8');
const mediaBlocks = (() => {
const blocks: Array<{ query: string; body: string }> = [];
const mediaPattern = /@media\s*([^{]+)\{/g;
let match: RegExpExecArray | null;
while ((match = mediaPattern.exec(css))) {
let depth = 1;
let cursor = mediaPattern.lastIndex;
for (; cursor < css.length; cursor += 1) {
if (css[cursor] === '{') depth += 1;
if (css[cursor] === '}') depth -= 1;
if (depth === 0) break;
}
blocks.push({
query: match[1].trim(),
body: css.slice(mediaPattern.lastIndex, cursor),
});
mediaPattern.lastIndex = cursor + 1;
}
return blocks;
})();
const blocksFor = (queryPart: string) =>
mediaBlocks.filter((block) => block.query.includes(queryPart));
const ruleBodies = (source: string, selector: string) => {
const escapedSelector = selector.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
return [...source.matchAll(new RegExp(`${escapedSelector}\\s*\\{([^}]*)\\}`, 'g'))]
.map((match) => match[1]);
};
describe('responsive shell CSS contract', () => {
it('keeps desktop navigation as a left rail by default', () => {
expect(css).toMatch(/\.dashboard-main\s*\{[\s\S]*?margin-left:\s*248px;/);
expect(css).toMatch(/\.trading-sidebar\s*\{[\s\S]*?width:\s*248px;/);
expect(css).toMatch(/\.dashboard-right-panel\s*\{[\s\S]*?width:\s*340px;/);
});
it('keeps tablet navigation on the side instead of switching to footer nav', () => {
const tabletBlocks = blocksFor('min-width: 561px');
expect(tabletBlocks.length).toBeGreaterThan(0);
const tabletCss = tabletBlocks.map((block) => block.body).join('\n');
const tabletSidebarRules = ruleBodies(tabletCss, '.trading-sidebar').join('\n');
expect(tabletCss).toContain('margin-left: 88px');
expect(tabletSidebarRules).toContain('width: 88px');
expect(tabletSidebarRules).toContain('flex-direction: column');
expect(tabletSidebarRules).toContain('border-right: 1px solid var(--border)');
expect(tabletSidebarRules).not.toContain('width: 100%');
expect(tabletSidebarRules).not.toContain('border-top: 1px solid var(--border)');
});
it('uses bottom navigation only at phone width', () => {
const phoneCss = blocksFor('max-width: 560px').map((block) => block.body).join('\n');
const phoneSidebarRules = ruleBodies(phoneCss, '.trading-sidebar').join('\n');
expect(phoneCss).toContain('margin-left: 0');
expect(phoneSidebarRules).toContain('width: 100%');
expect(phoneSidebarRules).toContain('flex-direction: row');
expect(phoneSidebarRules).toContain('border-top: 1px solid var(--border)');
const wideResponsiveCss = mediaBlocks
.filter((block) => !block.query.includes('max-width: 560px'))
.map((block) => block.body)
.join('\n');
const wideSidebarRules = ruleBodies(wideResponsiveCss, '.trading-sidebar').join('\n');
expect(wideSidebarRules).not.toContain('width: 100%');
});
});