import { describe, it, expect, vi, beforeEach } from 'vitest' vi.mock('next/cache', () => ({ revalidatePath: vi.fn() })) vi.mock('next/headers', () => ({ cookies: vi.fn().mockResolvedValue({ set: vi.fn(), get: vi.fn(), delete: vi.fn(), }), })) vi.mock('iron-session', () => ({ getIronSession: vi.fn().mockResolvedValue({ userId: 'user-1', isDemo: false }), })) vi.mock('@/lib/session', () => ({ sessionOptions: { cookieName: 'test', password: 'test' }, })) vi.mock('@/lib/product-access', () => ({ productAccessFilter: vi.fn().mockReturnValue({}), })) vi.mock('@/lib/prisma', () => ({ prisma: { product: { findFirst: vi.fn() }, user: { findUnique: vi.fn(), update: vi.fn().mockResolvedValue({}), }, $executeRaw: vi.fn().mockResolvedValue(1), }, })) import { prisma } from '@/lib/prisma' import { clearPendingSprintDraftAction, setPendingSprintDraftAction, } from '@/actions/sprint-draft' import type { PendingSprintDraft, UserSettings } from '@/lib/user-settings' const mockPrisma = prisma as unknown as { product: { findFirst: ReturnType } user: { findUnique: ReturnType update: ReturnType } } const validDraft: PendingSprintDraft = { goal: 'Sprint 1', pbiIntent: { pbiA: 'all' }, storyOverrides: { pbiA: { add: [], remove: ['story-1'] } }, } describe('setPendingSprintDraftAction', () => { beforeEach(() => { vi.clearAllMocks() mockPrisma.product.findFirst.mockReset() mockPrisma.user.findUnique.mockReset() mockPrisma.user.update.mockReset().mockResolvedValue({}) }) it('persists draft for accessible product', async () => { mockPrisma.product.findFirst.mockResolvedValueOnce({ id: 'p1' }) mockPrisma.user.findUnique.mockResolvedValueOnce({ settings: {} }) const result = await setPendingSprintDraftAction('p1', validDraft) expect(result).toEqual({ success: true }) const updateArg = mockPrisma.user.update.mock.calls[0][0] as { data: { settings: UserSettings } } expect(updateArg.data.settings.workflow?.pendingSprintDraft?.p1).toMatchObject({ goal: 'Sprint 1', pbiIntent: { pbiA: 'all' }, }) }) it('preserves drafts for other products', async () => { mockPrisma.product.findFirst.mockResolvedValueOnce({ id: 'p1' }) mockPrisma.user.findUnique.mockResolvedValueOnce({ settings: { workflow: { pendingSprintDraft: { p2: { goal: 'P2 draft', pbiIntent: {}, storyOverrides: {} }, }, }, }, }) await setPendingSprintDraftAction('p1', validDraft) const updateArg = mockPrisma.user.update.mock.calls[0][0] as { data: { settings: UserSettings } } const drafts = updateArg.data.settings.workflow?.pendingSprintDraft expect(Object.keys(drafts ?? {})).toEqual(expect.arrayContaining(['p1', 'p2'])) }) it('rejects invalid draft (empty goal)', async () => { mockPrisma.product.findFirst.mockResolvedValueOnce({ id: 'p1' }) const result = await setPendingSprintDraftAction('p1', { ...validDraft, goal: '', } as PendingSprintDraft) expect(result).toHaveProperty('error') expect(mockPrisma.user.update).not.toHaveBeenCalled() }) it('rejects when product not accessible', async () => { mockPrisma.product.findFirst.mockResolvedValueOnce(null) const result = await setPendingSprintDraftAction('p1', validDraft) expect(result).toEqual({ error: 'Product niet gevonden of niet toegankelijk' }) expect(mockPrisma.user.update).not.toHaveBeenCalled() }) }) describe('clearPendingSprintDraftAction', () => { beforeEach(() => { vi.clearAllMocks() mockPrisma.product.findFirst.mockReset() mockPrisma.user.findUnique.mockReset() mockPrisma.user.update.mockReset().mockResolvedValue({}) }) it('removes draft key for product', async () => { mockPrisma.product.findFirst.mockResolvedValueOnce({ id: 'p1' }) mockPrisma.user.findUnique.mockResolvedValueOnce({ settings: { workflow: { pendingSprintDraft: { p1: { goal: 'gone', pbiIntent: {}, storyOverrides: {} }, p2: { goal: 'keep', pbiIntent: {}, storyOverrides: {} }, }, }, }, }) await clearPendingSprintDraftAction('p1') const updateArg = mockPrisma.user.update.mock.calls[0][0] as { data: { settings: UserSettings } } expect(updateArg.data.settings.workflow?.pendingSprintDraft).toEqual({ p2: { goal: 'keep', pbiIntent: {}, storyOverrides: {} }, }) }) it('is a no-op when there is no draft for the product', async () => { mockPrisma.product.findFirst.mockResolvedValueOnce({ id: 'p1' }) mockPrisma.user.findUnique.mockResolvedValueOnce({ settings: {} }) const result = await clearPendingSprintDraftAction('p1') expect(result).toEqual({ success: true }) expect(mockPrisma.user.update).not.toHaveBeenCalled() }) it('rejects when product not accessible', async () => { mockPrisma.product.findFirst.mockResolvedValueOnce(null) const result = await clearPendingSprintDraftAction('p1') expect(result).toEqual({ error: 'Product niet gevonden of niet toegankelijk' }) }) })