feat: show habit history in details
ci / gitleaks (push) Successful in 53s
ci / docker (push) Successful in 4m59s

This commit is contained in:
2026-09-15 16:32:53 +08:00
parent a6c12ee01f
commit e857506bf6
5 changed files with 159 additions and 9 deletions
+20 -1
View File
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest'
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, nextTotalAfterLocalTaskRemoval, snapFabPosition, normalizeRequiredName, numericHabitInputValue, performHabitRestore, performTrashMutation, previousHabitSwipeValue, quickTaskFields, readCountdownCache, readHabitGridCache, readStoredBoolean, readStoredNavigation, shouldToggleRowSwipe, validateHabitForm, writeCountdownCache, writeHabitGridCache, writeStoredBoolean, writeStoredNavigation } from './mvp-utils'
import { archivePanelFlags, calendarModeLabel, changedHabitFields, clampFabPosition, countdownDayText, countdownKindLabel, dateKey, dayBefore, defaultView, formatArchivedAt, formatAuditAction, formatAuditEntity, formatHabitApiError, formatHabitHistoryNumber, formatLocalShortDateTime, formatUserAgent, habitActionState, habitButtonNotice, habitButtonValue, habitHistoryWindow, habitWeek, invalidateHabitGridCache, isFabDrag, isHabitComplete, isHabitScheduledToday, isTaskView, mergeHabitHistory, nextHabitSwipeValue, nextTotalAfterLocalTaskAdd, nextTotalAfterLocalTaskRemoval, snapFabPosition, normalizeRequiredName, numericHabitInputValue, performHabitRestore, performTrashMutation, 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', () => {
@@ -71,6 +71,25 @@ describe('MVP view utilities', () => {
expect(readStoredNavigation(fakeStorage, 'dodo.navigation')).toEqual({ view: 'today', listId: '' })
})
it('builds non-overlapping 90-day habit history windows', () => {
expect(habitHistoryWindow('2026-09-15')).toEqual({ from: '2026-06-18', to: '2026-09-15' })
expect(dayBefore('2026-06-18')).toBe('2026-06-17')
expect(habitHistoryWindow('2026-01-01', 2)).toEqual({ from: '2025-12-31', to: '2026-01-01' })
})
it('merges habit history by day, coerces API values, and keeps newest first', () => {
expect(mergeHabitHistory(
[{ day: '2026-09-14', value: 1 }, { day: '2026-09-13', value: 2 }],
[{ day: '2026-09-15', value: 3 }, { day: '2026-09-14', value: 4 }],
)).toEqual([
{ day: '2026-09-15', value: 3 },
{ day: '2026-09-14', value: 4 },
{ day: '2026-09-13', value: 2 },
])
expect(formatHabitHistoryNumber(8)).toBe('8')
expect(formatHabitHistoryNumber(1.25)).toBe('1.25')
})
it('only completes numeric habits when progress reaches the target', () => {
expect(isHabitComplete('numeric', 3, 5)).toBe(false)
expect(isHabitComplete('numeric', 5, 5)).toBe(true)