import { readFileSync } from 'node:fs' import { describe, expect, it } from 'vitest' const source = readFileSync('src/CountdownPanel.vue', 'utf8') describe('countdown modal accessibility', () => { it('names the dialog and supports focus and Escape close', () => { expect(source).toContain('aria-labelledby="countdown-dialog-title"') expect(source).toContain('id="countdown-dialog-title"') expect(source).toContain('@keydown.esc="closeDialog"') expect(source).toContain('ref="titleInput"') expect(source).toContain('titleInput.value?.focus()') expect(source).toContain(':inert="open || Boolean(detailItem)"') }) it('uses one time-capsule focus and moves row actions into a detail sheet', () => { expect(source).toContain('class="countdown-timeline"') expect(source).toContain('class="countdown-row"') expect(source).toContain('class="countdown-focus"') expect(source).toContain('@click="openDetail(focusItem)"') expect(source).toContain('item.id !== focusItem.value?.id') expect(source).toContain('`kind-${item.kind}`') expect(source).toContain(':class="`kind-${focusItem.kind}`"') expect(source).toContain('class="countdown-detail-sheet"') expect(source).toContain('ref="detailCloseButton"') expect(source).toContain('detailCloseButton.value?.focus()') expect(source).toContain('@keydown="trapDetailFocus"') expect(source).not.toContain('class="countdown-actions"') }) it('does not show or edit countdown icons', () => { expect(source).not.toContain('countdown-icon') expect(source).not.toContain('form.icon') expect(source).not.toContain('item.icon') expect(source).not.toContain('focusItem.icon') expect(source).not.toContain('detailItem.icon') expect(source).not.toContain('图标与名称') }) it('keeps advanced creation fields collapsed behind more settings', () => { expect(source).toContain('class="countdown-advanced"') expect(source).toContain('更多设置') expect(source).toContain('@change="applyKindDefaults"') expect(source).toContain(':disabled="form.ignore_year"') }) it('shows cached countdowns immediately and refreshes active items first', () => { expect(source).toContain('readCountdownCache()') expect(source).toContain("const active = await request('/countdowns')") expect(source).toContain("const archivedItems = await request('/countdowns?archived=true')") expect(source).toContain('writeCountdownCache(items.value, archived.value)') expect(source).not.toContain("Promise.all([request('/countdowns'),request('/countdowns?archived=true')])") }) it('keeps the empty state directly actionable', () => { expect(source).toContain('添加第一个重要日子') expect(source).toContain('@click="openFromEmpty"') }) })