import { readFileSync } from 'node:fs' import { describe, expect, it } from 'vitest' import { loadTaskOpenTotal } from './lib/task-open-total' const app = readFileSync('src/App.vue', 'utf8') const countdown = readFileSync('src/CountdownPanel.vue', 'utf8') const habits = readFileSync('src/MvpPanel.vue', 'utf8') const css = readFileSync('src/style.css', 'utf8') const memoCss = readFileSync('src/memo.css', 'utf8') const memoPanel = readFileSync('src/MemoPanel.vue', 'utf8') const memoRow = readFileSync('src/components/MemoRow.vue', 'utf8') describe('task-list open summary reconciliation', () => { it('returns primary data without waiting for the open-total request', async () => { let resolveSummary!: (value: { total: number }) => void const summary = new Promise<{ total: number }>((resolve) => { resolveSummary = resolve }) const committed: Array = [] const result = await loadTaskOpenTotal( async () => summary, () => true, value => committed.push(value), ) expect(result).toBeUndefined() expect(committed).toEqual([]) resolveSummary({ total: 4 }) await summary await Promise.resolve() expect(committed).toEqual([4]) }) it('keeps null on failure and ignores stale list responses', async () => { const failed: Array = [] loadTaskOpenTotal(async () => { throw new Error('summary failed') }, () => true, value => failed.push(value)) await Promise.resolve() await Promise.resolve() expect(failed).toEqual([]) let current = true let resolveSummary!: (value: { total: number }) => void const summary = new Promise<{ total: number }>((resolve) => { resolveSummary = resolve }) const committed: Array = [] loadTaskOpenTotal(async () => summary, () => current, value => committed.push(value)) current = false resolveSummary({ total: 9 }) await summary await Promise.resolve() expect(committed).toEqual([]) }) }) describe('approved five-detail polish', () => { it('does not expose task-search controls or styles', () => { expect(app).not.toContain('mobileSearchOpen') expect(app).not.toContain('task-search-panel') expect(app).not.toContain('handleTaskSearchKeydown') expect(css).not.toContain('.task-search-toggle') expect(css).not.toContain('.search-reveal{') }) it('keeps the countdown focus compact and detail titles unique', () => { const focusStart = countdown.indexOf('class="countdown-focus"') const focus = countdown.slice(focusStart, countdown.indexOf('', focusStart)) expect(focus).not.toContain('置顶的重要日子') expect(focus).not.toContain('下一个重要日子') expect(focus).not.toContain('countdown-copy') expect(focus).toContain('

{{focusItem.title}}

') expect(countdown).not.toContain('重要日子详情') expect(habits).not.toContain('习惯详情') expect(countdown).toContain('title-id="countdown-detail-title"') expect(habits).toContain('title-id="habit-detail-title"') expect(css).toMatch(/@media\(max-width:930px\)\{[\s\S]*?\.countdown-focus\{[^}]*height:140px/) }) it('uses approved Today-sourced page headers and the grouped Trash layout', () => { expect(app).toContain('v-if="activeView===\'tasks\' || activeView===\'upcoming\'" class="list-page-context"') expect(app).toContain('

{{ activeName }}

') expect(app).toContain('

{{ taskOpenTotal === null ? \'待完成统计暂不可用\' : `还有 ${taskOpenTotal} 项待完成` }}

') expect(app).toContain('') expect(app).toContain("v-if=\"activeView==='tasks' || activeView==='upcoming'\" id=\"task-list-heading\" class=\"list-section-heading\"") expect(app).toContain('任务') expect(app).toContain("v-if=\"activeView==='tasks' && taskReorderAvailable\"") expect(app).toContain('{{ totalTasks }}') expect(app).not.toContain("v-if=\"activeView==='tasks' && totalPages > 1\" class=\"list-page-meta\"") const taskListEnd = app.indexOf('', app.indexOf('class=\"task-list plain-list\"')) expect(app.indexOf('class=\"pager\"')).toBeGreaterThan(taskListEnd) expect(app).toContain('ref="taskListElement"') expect(app).toContain("totalPages > 1 && (activeView!=='today' || !todaySectionCollapse.tasks)") expect(app).toContain("taskListElement.value?.scrollIntoView({ block: 'start' })") expect(app).not.toContain('class="list-page-meta" aria-live="polite"') expect(app).toContain('