useCheckinDraft.test.js
3.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest'
import { useCheckinDraft } from '../useCheckinDraft'
// Mock localStorage
const localStorageMock = (() => {
let store = {}
return {
getItem: vi.fn(key => store[key] || null),
setItem: vi.fn((key, value) => { store[key] = value.toString() }),
removeItem: vi.fn(key => { delete store[key] }),
clear: vi.fn(() => { store = {} }),
key: vi.fn(i => Object.keys(store)[i] || null),
get length() { return Object.keys(store).length }
}
})()
global.localStorage = localStorageMock
describe('useCheckinDraft', () => {
beforeEach(() => {
localStorageMock.clear()
vi.clearAllMocks()
// Mock Date.now
vi.useFakeTimers()
})
afterEach(() => {
vi.useRealTimers()
})
const mockContext = {
user_id: 'u123',
task_id: 't456',
date: '2026-01-25',
task_type: 'upload',
status: 'create'
}
const {
build_key,
save_draft,
read_draft,
clear_draft,
cleanup_expired
} = useCheckinDraft()
it('should generate correct key', () => {
const key = build_key(mockContext)
expect(key).toBe('CHECKIN_DRAFT_V1:u123:t456:2026-01-25:upload:create')
})
it('should save and read draft', () => {
const key = build_key(mockContext)
const payload = { message: 'hello', file_list: [] }
save_draft(key, payload)
const saved = read_draft(key)
expect(saved).not.toBeNull()
expect(saved.payload).toEqual(payload)
expect(saved.version).toBe(1)
})
it('should return null for expired draft', () => {
const key = build_key(mockContext)
const payload = { message: 'expired' }
save_draft(key, payload)
// Advance time by 8 days (TTL is 7 days)
vi.setSystemTime(Date.now() + 8 * 24 * 60 * 60 * 1000)
const saved = read_draft(key)
expect(saved).toBeNull()
// Should also remove from storage
expect(localStorage.getItem(key)).toBeNull()
})
it('should cleanup only expired drafts', () => {
const ctx1 = { ...mockContext, task_id: 't1' }
const ctx2 = { ...mockContext, task_id: 't2' }
const key1 = build_key(ctx1)
const key2 = build_key(ctx2)
const otherKey = 'OTHER_KEY'
save_draft(key1, { msg: 'expire soon' })
save_draft(key2, { msg: 'keep' })
localStorage.setItem(otherKey, 'some value')
// Set key1 to expire
// We need to manually manipulate storage to simulate different saved_at
// Or just save key1, advance time, save key2
// Reset storage and start over
localStorageMock.clear()
// Save key1
save_draft(key1, { msg: 'old' })
// Advance 8 days
const eightDays = 8 * 24 * 60 * 60 * 1000
vi.setSystemTime(Date.now() + eightDays)
// Save key2 (fresh)
save_draft(key2, { msg: 'new' })
// Other key
localStorage.setItem(otherKey, 'val')
// Run cleanup
cleanup_expired()
expect(localStorage.getItem(key1)).toBeNull()
expect(localStorage.getItem(key2)).not.toBeNull()
expect(localStorage.getItem(otherKey)).toBe('val')
})
it('should only save "done" files with meta_id', () => {
const key = build_key(mockContext)
const files = [
{ status: 'done', meta_id: 'm1', name: 'f1' },
{ status: 'uploading', name: 'f2' },
{ status: 'failed', name: 'f3' },
{ status: 'done', name: 'f4' } // no meta_id
]
save_draft(key, { file_list: files })
const saved = read_draft(key)
expect(saved.payload.file_list).toHaveLength(1)
expect(saved.payload.file_list[0].meta_id).toBe('m1')
})
})