import { describe, it, expect, vi, beforeEach } from 'vitest' vi.mock('@/lib/prisma', () => ({ prisma: { sprint: { findFirst: vi.fn() }, user: { findUnique: vi.fn(), update: vi.fn().mockResolvedValue({}), }, $executeRaw: vi.fn().mockResolvedValue(1), }, })) import { prisma } from '@/lib/prisma' import type { UserSettings } from '@/lib/user-settings' import { clearActiveSprintInSettings, readStoredActiveSprintState, resolveActiveSprint, } from '@/lib/active-sprint' const mockPrisma = prisma as unknown as { sprint: { findFirst: ReturnType } user: { findUnique: ReturnType update: ReturnType } $executeRaw: ReturnType } function withSettings(settings: UserSettings) { mockPrisma.user.findUnique.mockResolvedValueOnce({ settings }) } describe('readStoredActiveSprintState', () => { it('returns unset when activeSprints map is absent', () => { expect(readStoredActiveSprintState({}, 'p1')).toEqual({ kind: 'unset' }) }) it('returns unset when productId key is absent', () => { const settings: UserSettings = { layout: { activeSprints: { p2: 'sprint-2' } }, } expect(readStoredActiveSprintState(settings, 'p1')).toEqual({ kind: 'unset', }) }) it('returns cleared when key is present with null value', () => { const settings: UserSettings = { layout: { activeSprints: { p1: null } }, } expect(readStoredActiveSprintState(settings, 'p1')).toEqual({ kind: 'cleared', }) }) it('returns set when key is present with string value', () => { const settings: UserSettings = { layout: { activeSprints: { p1: 'sprint-1' } }, } expect(readStoredActiveSprintState(settings, 'p1')).toEqual({ kind: 'set', sprintId: 'sprint-1', }) }) }) describe('resolveActiveSprint', () => { beforeEach(() => { vi.clearAllMocks() }) it('returns null without fallback when key is explicitly null (cleared)', async () => { withSettings({ layout: { activeSprints: { p1: null } } }) const result = await resolveActiveSprint('p1', 'user-1') expect(result).toBeNull() expect(mockPrisma.sprint.findFirst).not.toHaveBeenCalled() }) it('returns the stored sprint when key is set and sprint exists', async () => { withSettings({ layout: { activeSprints: { p1: 'sprint-1' } } }) mockPrisma.sprint.findFirst.mockResolvedValueOnce({ id: 'sprint-1', code: 'SP-1', status: 'OPEN', }) const result = await resolveActiveSprint('p1', 'user-1') expect(result).toEqual({ id: 'sprint-1', code: 'SP-1', status: 'OPEN' }) expect(mockPrisma.sprint.findFirst).toHaveBeenCalledTimes(1) }) it('falls back when stored sprint is not found in DB', async () => { withSettings({ layout: { activeSprints: { p1: 'stale-id' } } }) mockPrisma.sprint.findFirst .mockResolvedValueOnce(null) // stored lookup misses .mockResolvedValueOnce({ id: 'sprint-open', code: 'SP-O', status: 'OPEN' }) const result = await resolveActiveSprint('p1', 'user-1') expect(result).toEqual({ id: 'sprint-open', code: 'SP-O', status: 'OPEN', }) }) it('falls back to first OPEN sprint when key is absent', async () => { withSettings({}) mockPrisma.sprint.findFirst.mockResolvedValueOnce({ id: 'sprint-open', code: 'SP-O', status: 'OPEN', }) const result = await resolveActiveSprint('p1', 'user-1') expect(result).toEqual({ id: 'sprint-open', code: 'SP-O', status: 'OPEN', }) }) it('falls back to recent CLOSED sprint when no OPEN exists', async () => { withSettings({}) mockPrisma.sprint.findFirst .mockResolvedValueOnce(null) // no OPEN .mockResolvedValueOnce({ id: 'sprint-closed', code: 'SP-C', status: 'CLOSED', }) const result = await resolveActiveSprint('p1', 'user-1') expect(result).toEqual({ id: 'sprint-closed', code: 'SP-C', status: 'CLOSED', }) }) it('returns null when key absent and no sprints exist', async () => { withSettings({}) mockPrisma.sprint.findFirst.mockResolvedValue(null) const result = await resolveActiveSprint('p1', 'user-1') expect(result).toBeNull() }) }) describe('clearActiveSprintInSettings', () => { beforeEach(() => { vi.clearAllMocks() }) it('writes null instead of deleting the key', async () => { withSettings({ layout: { activeSprints: { p1: 'sprint-1', p2: 'sprint-2' } }, }) await clearActiveSprintInSettings('user-1', 'p1') expect(mockPrisma.user.update).toHaveBeenCalledTimes(1) const updateArg = mockPrisma.user.update.mock.calls[0][0] as { data: { settings: UserSettings } } expect(updateArg.data.settings.layout?.activeSprints).toEqual({ p1: null, p2: 'sprint-2', }) }) it('adds the key with null when previously unset', async () => { withSettings({}) await clearActiveSprintInSettings('user-1', 'p1') const updateArg = mockPrisma.user.update.mock.calls[0][0] as { data: { settings: UserSettings } } expect(updateArg.data.settings.layout?.activeSprints).toEqual({ p1: null }) }) })