import fs from 'node:fs'; import path from 'node:path'; import { describe, expect, test } from 'vitest'; const stylesheet = fs.readFileSync( path.resolve(process.cwd(), 'apps/admin-web/src/styles/admin.css'), 'utf8', ); describe('admin shell scrolling contract', () => { test('desktop shell keeps sidebar separate from the scrollable content', () => { expect(ruleFor('.admin-shell')).toContain('\n height: 100dvh;'); expect(ruleFor('.admin-shell')).toContain('overflow: hidden'); expect(ruleFor('.admin-sidebar')).toContain('min-height: 0'); expect(ruleFor('.admin-sidebar')).toContain('overflow-y: auto'); expect(ruleFor('.admin-main')).toContain('min-height: 0'); expect(ruleFor('.admin-main')).toContain('overflow: hidden'); expect(ruleFor('.admin-content')).toContain('min-height: 0'); expect(ruleFor('.admin-content')).toContain('overflow: auto'); }); test('mobile navigation stays in one horizontally scrollable row', () => { const mobileStyles = stylesheet.slice(stylesheet.indexOf('@media (max-width: 980px)')); expect(mobileStyles).toContain('.admin-bottom-nav {'); expect(mobileStyles).toContain('display: flex'); expect(mobileStyles).toContain('overflow-x: auto'); expect(mobileStyles).not.toContain( 'grid-template-columns: repeat(auto-fit, minmax(64px, 1fr))', ); expect(mobileStyles).toContain('flex: 0 0 76px'); }); }); function ruleFor(selector: string) { const escapedSelector = selector.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); const match = stylesheet.match( new RegExp(`${escapedSelector}\\s*\\{([^}]*)\\}`), ); if (!match) { throw new Error(`Missing CSS rule for ${selector}`); } return match[1]; }