58 lines
3.4 KiB
TypeScript
58 lines
3.4 KiB
TypeScript
import { readFileSync } from 'node:fs'
|
||
import { describe, expect, it } from 'vitest'
|
||
|
||
const app = readFileSync('src/App.vue', 'utf8')
|
||
const style = readFileSync('src/style.css', 'utf8')
|
||
const css = readFileSync('src/today-sections.css', 'utf8')
|
||
|
||
describe('Today independent collapsible sections', () => {
|
||
it('owns and persists one three-field collapse state in App', () => {
|
||
expect(app).toContain("const TODAY_SECTION_COLLAPSE_KEY = 'dodo.today-section-collapse.v1'")
|
||
expect(app).toContain('readTodaySectionCollapse(window.localStorage, TODAY_SECTION_COLLAPSE_KEY)')
|
||
expect(app).toContain('writeTodaySectionCollapse(window.localStorage, TODAY_SECTION_COLLAPSE_KEY, todaySectionCollapse.value)')
|
||
})
|
||
|
||
it('imports the section stylesheet from the global stylesheet', () => {
|
||
expect(style).toContain('@import "./today-sections.css";')
|
||
})
|
||
|
||
it('renders full-row accessible toggles and labelled regions for all three sections', () => {
|
||
for (const section of ['overdue', 'tasks', 'habits']) {
|
||
expect(app).toContain(`id="today-${section}-heading"`)
|
||
expect(app).toContain(`aria-controls="today-${section}"`)
|
||
expect(app).toContain(`:aria-expanded="!todaySectionCollapse.${section}"`)
|
||
if (section === 'tasks') {
|
||
expect(app).toContain(":id=\"activeView==='today' ? 'today-tasks' : undefined\"")
|
||
expect(app).toContain(":aria-labelledby=\"activeView==='today' ? 'today-tasks-heading' : (activeView==='tasks' || activeView==='upcoming') ? 'task-list-title' : undefined\"")
|
||
} else {
|
||
expect(app).toContain(`id="today-${section}"`)
|
||
expect(app).toContain(`aria-labelledby="today-${section}-heading"`)
|
||
}
|
||
}
|
||
expect(app).toContain('<span class="today-section-title">逾期</span>')
|
||
expect(app).toContain('<span class="today-section-title">今天</span>')
|
||
expect(app).toContain('<span class="today-section-title">习惯</span>')
|
||
expect(app).not.toMatch(/today-section-title"><(?:CalendarDays|ListTodo|Repeat2)\/>/)
|
||
expect(app.match(/class="today-section-toggle(?: today-section-anchor)?"/g)).toHaveLength(3)
|
||
expect(app).toContain('<span class="today-section-summary">{{totalTasks}}</span>')
|
||
expect(app).not.toContain('<span class="today-section-summary">{{taskTree.length}} 项</span>')
|
||
expect(app).toContain("{{ todaySectionCollapse.overdue ? '›' : '⌄' }}")
|
||
expect(app).not.toContain('<ChevronRight v-if="todaySectionCollapse.overdue"')
|
||
expect(css).toMatch(/\.today-section-toggle\{[^}]*min-height:44px/)
|
||
})
|
||
|
||
it('keeps the habit panel mounted while collapsed and omits an empty overdue section', () => {
|
||
expect(app).toContain('<section v-if="overdueTaskTree.length" class="overdue-section today-collapsible-section">')
|
||
expect(app).toContain('<div v-show="!todaySectionCollapse.habits" id="today-habits"')
|
||
const habits = app.slice(app.indexOf('id="today-habits-heading"'), app.indexOf('</div>', app.indexOf('<MvpPanel ref="habitComposer" view="today-habits"')) + 6)
|
||
expect(habits).toContain('<MvpPanel ref="habitComposer" view="today-habits"')
|
||
expect(habits).not.toContain('v-if="!todaySectionCollapse.habits"')
|
||
})
|
||
|
||
it('keeps section navigation local to each collapse toggle', () => {
|
||
expect(app).not.toContain("async function navigateTodaySection(section: 'tasks' | 'habits')")
|
||
expect(app).toContain("@click=\"toggleTodaySection('tasks')\"")
|
||
expect(app).toContain("@click=\"toggleTodaySection('habits')\"")
|
||
})
|
||
})
|