import { readFileSync } from 'node:fs' import { describe, expect, it } from 'vitest' const css = readFileSync('src/style.css', 'utf8') const app = readFileSync('src/App.vue', 'utf8') const mvpPanel = readFileSync('src/MvpPanel.vue', 'utf8') const countdownPanel = readFileSync('src/CountdownPanel.vue', 'utf8') const floatingAdd = readFileSync('src/components/FloatingAddButton.vue', 'utf8') describe('mobile navigation styles', () => { it('renames the bottom More tab to a direct Settings tab', () => { expect(app).not.toContain('aria-controls="mobile-more-menu"') expect(app).not.toContain('更多') expect(app).toContain("设置") expect(app).toContain("@click=\"switchView('settings')\"") expect(app).toContain('设置') }) it('keeps the mobile More sheet visible when it is rendered', () => { expect(css).not.toContain('.more-mask{display:none}') expect(css).toContain('@media(max-width:930px){.shell') expect(css).toContain('.more-mask{position:fixed;z-index:45;') }) it('lets the mobile sidebar scrim cover the outside area and stay below the sidebar', () => { expect(app).toContain('
') expect(css).toContain('.sidebar{position:fixed;z-index:50;') expect(css).toContain('.scrim{position:fixed;z-index:35;inset:0;') expect(css).toMatch(/\.scrim\{position:fixed;z-index:35;[^}]*display:block/) }) }) describe('mobile sheet contract', () => { it('uses shared roles for details, creation and secondary actions', () => { expect(app).toContain('class="task-compose-mask app-sheet-mask"') expect(app).toContain('class="task-compose-sheet app-sheet app-sheet--create"') expect(app).toContain('class="more-sheet app-sheet app-sheet--actions"') expect(mvpPanel).toContain('class="task-compose-sheet habit-compose-sheet app-sheet app-sheet--create"') expect(mvpPanel).toContain('class="habit-detail-sheet app-sheet app-sheet--detail"') expect(countdownPanel).toContain('class="countdown-detail-sheet app-sheet app-sheet--detail"') expect(countdownPanel).toContain('class="countdown-modal app-sheet app-sheet--create"') expect(css).toContain('--sheet-radius:20px;--sheet-scrim:rgba(45,38,31,.4)') expect(css).toContain('.app-sheet-mask.app-sheet-mask{background:var(--sheet-scrim)') expect(css).toContain('.app-sheet__header{min-height:64px;') expect(css).toContain('.app-sheet__body{min-height:0;overflow-y:auto;') expect(css).toContain('.app-sheet__footer{position:sticky;bottom:0;') expect(css).toContain('padding-bottom:calc(16px + env(safe-area-inset-bottom))') }) it('keeps destructive actions in a separate bottom danger zone', () => { expect(mvpPanel).toContain('class="app-sheet__danger"') expect(mvpPanel).toMatch(/app-sheet__danger[\s\S]*?deleteHabit\(selectedHabit\)/) expect(css).toContain('.app-sheet__danger{border-top:1px solid #f1d4cd;') }) }) describe('mobile list row language', () => { it('uses one quiet bordered row surface for tasks, habits, and countdowns on mobile', () => { expect(css).toContain('@media(max-width:930px){.task-row,.habit-row,.countdown-row{') expect(css).toMatch(/@media\(max-width:930px\)\{\.task-row,\.habit-row,\.countdown-row\{[^}]*background:#fff;[^}]*border:1px solid var\(--line\);[^}]*border-radius:13px;[^}]*box-shadow:none/) expect(css).toContain('.task-list,.habit-list,.countdown-timeline{display:grid;gap:8px}') expect(css).toContain('.countdown-row{grid-template-columns:minmax(0,1fr) 72px;') expect(css).not.toContain('grid-template-columns:44px minmax(0,1fr) 72px') expect(css).not.toContain('grid-template-columns:40px minmax(0,1fr) 76px') expect(css).toContain('.task-main strong,.habit-name,.countdown-main>b{font-size:14px;') expect(css).toContain('.meta,.countdown-main>small,.countdown-state small{font-size:11px;') expect(css).toContain('.habit-progress{font-size:16px}') }) it('keeps destructive habit actions in a detail sheet instead of the list row', () => { expect(mvpPanel).not.toContain('