import { describe, it, expect, vi, beforeEach } from 'vitest' const { mockGroupBy, mockFindMany } = vi.hoisted(() => ({ mockGroupBy: vi.fn(), mockFindMany: vi.fn(), })) vi.mock('@/lib/prisma', () => ({ prisma: { claudeJob: { groupBy: mockGroupBy, findMany: mockFindMany, }, }, })) import { getVerifyResultStats } from '@/lib/insights/verify-stats' const USER_ID = 'user-1' const makeJob = (id: string, verifyResult: string, daysAgo: number) => { const finishedAt = new Date() finishedAt.setDate(finishedAt.getDate() - daysAgo) return { id, finished_at: finishedAt, task: { id: `task-${id}`, title: `Task ${id}` }, product: { id: 'prod-1', name: 'Scrum4Me' }, verify_result: verifyResult, } } beforeEach(() => { vi.clearAllMocks() }) describe('getVerifyResultStats', () => { it('returns counts in ALIGNED→PARTIAL→EMPTY→DIVERGENT order', async () => { mockGroupBy.mockResolvedValue([ { verify_result: 'DIVERGENT', _count: { _all: 2 } }, { verify_result: 'ALIGNED', _count: { _all: 10 } }, { verify_result: 'EMPTY', _count: { _all: 3 } }, { verify_result: 'PARTIAL', _count: { _all: 1 } }, ]) mockFindMany.mockResolvedValue([]) const stats = await getVerifyResultStats(USER_ID) expect(stats.counts.map(c => c.result)).toEqual([ 'ALIGNED', 'PARTIAL', 'EMPTY', 'DIVERGENT', ]) expect(stats.counts.map(c => c.count)).toEqual([10, 1, 3, 2]) }) it('omits results with zero count from groupBy', async () => { mockGroupBy.mockResolvedValue([ { verify_result: 'ALIGNED', _count: { _all: 5 } }, ]) mockFindMany.mockResolvedValue([]) const stats = await getVerifyResultStats(USER_ID) expect(stats.counts).toHaveLength(1) expect(stats.counts[0]).toEqual({ result: 'ALIGNED', count: 5 }) }) it('maps topEmpty jobs correctly', async () => { mockGroupBy.mockResolvedValue([]) const job = makeJob('j1', 'EMPTY', 2) // First findMany call → topEmpty, second → topDivergent mockFindMany .mockResolvedValueOnce([job]) .mockResolvedValueOnce([]) const stats = await getVerifyResultStats(USER_ID) expect(stats.topEmpty).toHaveLength(1) expect(stats.topEmpty[0]).toMatchObject({ jobId: 'j1', taskId: 'task-j1', taskTitle: 'Task j1', productId: 'prod-1', productName: 'Scrum4Me', }) }) it('topDivergent is ordered most-recent first (from DB order)', async () => { mockGroupBy.mockResolvedValue([]) const jobs = [ makeJob('jOld', 'DIVERGENT', 10), makeJob('jNew', 'DIVERGENT', 1), ] mockFindMany .mockResolvedValueOnce([]) // topEmpty .mockResolvedValueOnce(jobs) // topDivergent (already sorted by Prisma orderBy) const stats = await getVerifyResultStats(USER_ID) expect(stats.topDivergent.map(j => j.jobId)).toEqual(['jOld', 'jNew']) }) it('returns empty stats when no jobs found', async () => { mockGroupBy.mockResolvedValue([]) mockFindMany.mockResolvedValue([]) const stats = await getVerifyResultStats(USER_ID) expect(stats.counts).toEqual([]) expect(stats.topEmpty).toEqual([]) expect(stats.topDivergent).toEqual([]) }) })