[verified] harden trash actions and mobile details
ci / gitleaks (push) Successful in 26s
ci / docker (push) Successful in 5m5s

This commit is contained in:
2026-09-21 09:37:55 +08:00
parent 8a4d1de9be
commit 927e15cf17
5 changed files with 108 additions and 14 deletions
+26 -1
View File
@@ -326,7 +326,7 @@ describe('approved UI detail direction', () => {
const trashRows = app.slice(app.indexOf('class="trash-groups"'), ordinaryStart)
expect(trashRows).toContain('class="task-actions"')
expect(trashRows).toContain('restoreTask(node.task)')
expect(trashRows).toContain('purgeTask(node.task)')
expect(trashRows).toContain('openTrashAction(node.task,$event)')
const overdue = app.slice(app.indexOf('<section v-if="overdueTaskTree.length"'), app.indexOf('id="today-tasks-heading"'))
expect(overdue).toContain('selectTaskUnlessSwiped(node.task)')
expect(overdue).not.toContain('aria-label="打开任务详情"')
@@ -845,6 +845,31 @@ describe('task and habit row decoration', () => {
expect(css).toMatch(/\.restore\{[^}]*min-height:44px/)
})
it('keeps Trash deadlines visible on mobile before the action area', () => {
expect(css).not.toContain('.trash-list .task-tail{display:none}')
expect(css).toContain('.trash-list>.task-row{height:68px;min-height:68px;max-height:68px;grid-template-columns:minmax(0,1fr) minmax(38px,auto) auto;gap:6px}')
})
it('uses a real Trash action menu and typed permanent-delete confirmation', () => {
expect(app).toContain('const trashAction = ref<Task | null>(null)')
expect(app).toContain('const trashMenu = ref<HTMLElement | null>(null)')
expect(app).toContain('const trashPageTitle = ref<HTMLElement | null>(null)')
expect(app).toContain('aria-haspopup="menu"')
expect(app).toContain('@click.stop="openTrashAction(node.task,$event)"')
expect(app).toContain('ref="trashMenu" class="trash-action-menu" role="menu" aria-label="回收站任务操作"')
expect(app).toContain('@keydown.esc.stop="closeTrashAction()"')
expect(app).toContain('@keydown.tab.prevent="focusTrashMenuItem"')
expect(app).toContain("nextTick(() => trashMenu.value?.querySelector<HTMLElement>('[role=menuitem]')?.focus())")
expect(app).toContain('if (trigger?.isConnected) trigger.focus()')
expect(app).toContain('await purgeTask(task)')
expect(app).toContain('focusTrashActionTrigger(trigger)')
expect(app).toContain('else trashPageTitle.value?.focus()')
expect(app).toContain('@click="requestPurgeTask"')
expect(app).toContain("label: `输入任务名称“${task.title}”确认`")
expect(app).toContain("validate: (value) => value.trim() === task.title ? null : '任务名称不匹配'")
expect(app).not.toContain('class="trash-safety-note"')
})
it('reconciles only top-level Trash mutations and distinguishes refresh failure', () => {
const loadBlock = app.slice(app.indexOf('async function loadTrash()'), app.indexOf('async function switchView'))
const mutationBlock = app.slice(app.indexOf('async function mutateTrashTask'), app.indexOf('async function restoreTask'))