useCheckinDraft.test.js 3.95 KB
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')
    })
})