fix: replay completion motion reliably
ci / gitleaks (push) Successful in 6s
ci / docker (push) Successful in 3m29s

This commit is contained in:
2026-09-09 09:52:53 +08:00
parent aff070d2f7
commit 17005b0a50
4 changed files with 55 additions and 25 deletions
+19 -9
View File
@@ -1,5 +1,6 @@
import { readFileSync } from 'node:fs'
import { describe, expect, it } from 'vitest'
import { describe, expect, it, vi } from 'vitest'
import { createCompletionPulse } from './lib/completion-motion'
const css = readFileSync('src/style.css', 'utf8')
const app = readFileSync('src/App.vue', 'utf8')
@@ -58,14 +59,23 @@ describe('completion feedback motion', () => {
expect(css).toContain('@media(prefers-reduced-motion:reduce){.task-row.just-completed,.habit-row.just-completed,.task-row.just-completed .task-check-mark,.habit-row.just-completed .task-check-mark{animation:none}}')
})
it('adds transient completion classes only for incomplete to complete transitions', () => {
expect(app).toContain("const justCompletedTaskIds = ref(new Set<string>())")
expect(app).toContain("if (completing) markTaskJustCompleted(task.id)")
expect(app).toContain("'just-completed': justCompletedTaskIds.has(node.task.id)")
expect(app).toContain("'just-completed': justCompletedTaskIds.has(subtask.id)")
expect(mvpPanel).toContain("const justCompletedHabitIds = ref(new Set<string>())")
expect(mvpPanel.match(/if \(!wasDone && isHabitComplete\(h\.kind, next, h\.target \?\? 1\)\) markHabitJustCompleted\(h\.id\)/g)).toHaveLength(2)
expect(mvpPanel.match(/'just-completed': justCompletedHabitIds\.has\(h\.id\)/g)).toHaveLength(2)
it('restarts the pulse and ignores a stale timer on rapid repeat completion', () => {
vi.useFakeTimers()
const active = new Set<string>()
const pulse = createCompletionPulse((id) => active.add(id), (id) => active.delete(id), 420)
pulse('item-1')
vi.advanceTimersByTime(16)
expect(active.has('item-1')).toBe(true)
vi.advanceTimersByTime(200)
pulse('item-1')
expect(active.has('item-1')).toBe(false)
vi.advanceTimersByTime(16)
expect(active.has('item-1')).toBe(true)
vi.advanceTimersByTime(220)
expect(active.has('item-1')).toBe(true)
vi.advanceTimersByTime(200)
expect(active.has('item-1')).toBe(false)
vi.useRealTimers()
})
})