import { beforeEach, describe, expect, it, vi } from 'vitest'; import { saveLearningProgress } from '@/lib/learning'; import type { LearningProgressWrite } from '../../shared/learning'; const hostApiFetchMock = vi.hoisted(() => vi.fn()); vi.mock('@/lib/host-api', () => ({ hostApiFetch: (...args: unknown[]) => hostApiFetchMock(...args), })); vi.mock('@/lib/api-client', () => ({ invokeIpc: vi.fn(), })); describe('Learning renderer client', () => { beforeEach(() => { hostApiFetchMock.mockReset(); hostApiFetchMock.mockResolvedValue({ success: true, data: { courseId: 'course-1', contentHash: 'a'.repeat(64), moduleId: 'module-1', sceneOrder: 2, actionIndex: 1, positionMs: 300, completed: false, updatedAt: '2026-08-16T00:00:00.000Z', }, }); }); it('writes only the strict cloud progress contract and keeps module hashes local', async () => { const progress: LearningProgressWrite & { moduleContentHash: string } = { contentHash: 'a'.repeat(64), moduleId: 'module-1', moduleContentHash: 'b'.repeat(64), sceneOrder: 2, actionIndex: 1, positionMs: 300, completed: false, }; await saveLearningProgress('course-1', progress); expect(hostApiFetchMock).toHaveBeenCalledWith( '/api/works/learning/courses/course-1/progress', expect.objectContaining({ method: 'PUT' }), ); const init = hostApiFetchMock.mock.calls[0][1] as RequestInit; expect(JSON.parse(String(init.body))).toEqual({ contentHash: 'a'.repeat(64), moduleId: 'module-1', sceneOrder: 2, actionIndex: 1, positionMs: 300, completed: false, }); }); });