feat: refine archived habit management
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { calendarModeLabel, changedHabitFields, clampFabPosition, countdownDayText, countdownKindLabel, dateKey, defaultView, formatAuditAction, formatAuditEntity, formatHabitApiError, formatLocalShortDateTime, formatUserAgent, habitActionState, habitButtonNotice, habitButtonValue, habitWeek, isFabDrag, isHabitComplete, isHabitScheduledToday, isTaskView, nextHabitSwipeValue, nextTotalAfterLocalTaskAdd, normalizeRequiredName, numericHabitInputValue, previousHabitSwipeValue, quickTaskFields, readCountdownCache, readHabitGridCache, readStoredBoolean, readStoredNavigation, shouldToggleRowSwipe, validateHabitForm, writeCountdownCache, writeHabitGridCache, writeStoredBoolean, writeStoredNavigation } from './mvp-utils'
|
||||
import { archivePanelFlags, calendarModeLabel, changedHabitFields, clampFabPosition, countdownDayText, countdownKindLabel, dateKey, defaultView, formatArchivedAt, formatAuditAction, formatAuditEntity, formatHabitApiError, formatLocalShortDateTime, formatUserAgent, habitActionState, habitButtonNotice, habitButtonValue, habitWeek, invalidateHabitGridCache, isFabDrag, isHabitComplete, isHabitScheduledToday, isTaskView, nextHabitSwipeValue, nextTotalAfterLocalTaskAdd, normalizeRequiredName, numericHabitInputValue, performHabitRestore, previousHabitSwipeValue, quickTaskFields, readCountdownCache, readHabitGridCache, readStoredBoolean, readStoredNavigation, shouldToggleRowSwipe, validateHabitForm, writeCountdownCache, writeHabitGridCache, writeStoredBoolean, writeStoredNavigation } from './mvp-utils'
|
||||
|
||||
describe('MVP view utilities', () => {
|
||||
it('formats a local date as YYYY-MM-DD', () => {
|
||||
@@ -196,6 +196,49 @@ describe('MVP view utilities', () => {
|
||||
expect(formatLocalShortDateTime('2026-04-31T12:00:00+08:00', { timeZone: 'UTC' })).toBe('未知时间')
|
||||
})
|
||||
|
||||
it('keeps a successful restore committed when the grid refresh fails', async () => {
|
||||
const events: string[] = []
|
||||
const result = await performHabitRestore({
|
||||
restore: async () => { events.push('restored') },
|
||||
commitRestore: () => { events.push('archive-removed') },
|
||||
refreshGrid: async () => false,
|
||||
})
|
||||
|
||||
expect(events).toEqual(['restored', 'archive-removed'])
|
||||
expect(result).toEqual({ restored: true, refreshed: false })
|
||||
})
|
||||
|
||||
it('invalidates a restored habit grid cache before reconciliation', () => {
|
||||
writeHabitGridCache('2026-09-07', [{ id: 'restored-habit' }])
|
||||
invalidateHabitGridCache()
|
||||
expect(readHabitGridCache('2026-09-07')).toBeNull()
|
||||
})
|
||||
|
||||
it('does not commit a failed restore or attempt a grid refresh', async () => {
|
||||
const events: string[] = []
|
||||
await expect(performHabitRestore({
|
||||
restore: async () => { throw new Error('恢复失败') },
|
||||
commitRestore: () => { events.push('archive-removed') },
|
||||
refreshGrid: async () => { events.push('grid-refreshed') },
|
||||
})).rejects.toThrow('恢复失败')
|
||||
expect(events).toEqual([])
|
||||
})
|
||||
|
||||
it('formats archive timestamps locally and rejects every malformed calendar value', () => {
|
||||
expect(formatArchivedAt('2026-09-10T12:08:00Z', { timeZone: 'Asia/Shanghai' })).toMatch(/^归档于 2026\/9\/10 20:08$/)
|
||||
for (const value of [null, '', 'not-a-date', '2026-02-30T12:00:00Z', '2026-13-01T00:00:00Z', '2026-09-10T25:00:00Z']) {
|
||||
expect(formatArchivedAt(value, { timeZone: 'UTC' })).toBe('归档时间未知')
|
||||
}
|
||||
})
|
||||
|
||||
it('makes archive loading, error, and empty states mutually exclusive', () => {
|
||||
expect(archivePanelFlags('loading', 0)).toEqual({ loading: true, error: false, empty: false, list: false })
|
||||
expect(archivePanelFlags('error', 0)).toEqual({ loading: false, error: true, empty: false, list: false })
|
||||
expect(archivePanelFlags('success', 0)).toEqual({ loading: false, error: false, empty: true, list: false })
|
||||
expect(archivePanelFlags('success', 2)).toEqual({ loading: false, error: false, empty: false, list: true })
|
||||
expect(archivePanelFlags('idle', 0)).toEqual({ loading: false, error: false, empty: false, list: false })
|
||||
})
|
||||
|
||||
it('localizes known audit actions and entities and hides unknown actions', () => {
|
||||
expect(['create', 'update', 'complete', 'delete', 'archive', 'restore', 'move', 'import'].map(formatAuditAction)).toEqual(['创建', '更新', '完成', '删除', '归档', '恢复', '移动', '导入'])
|
||||
expect(['task', 'list', 'folder', 'countdown', 'backup'].map(formatAuditEntity)).toEqual(['任务', '清单', '文件夹', '倒数日', '备份'])
|
||||
|
||||
Reference in New Issue
Block a user