import { describe, it, expect, vi, beforeEach } from 'vitest'; import { isActionFailure } from '@sveltejs/kit'; import { createFormRequest, createLocals, mockUser } from '$lib/test-utils'; vi.mock('$lib/db', () => ({ prisma: { proclamationCategory: { findMany: vi.fn() }, proclamationGroup: { findMany: vi.fn() }, proclamation: { findMany: vi.fn() } } })); vi.mock('$lib/server/schedule', () => ({ listBlocks: vi.fn(), createBlock: vi.fn(), updateBlock: vi.fn(), deleteBlock: vi.fn() })); import { prisma } from '$lib/db'; import { createBlock, deleteBlock, listBlocks } from '$lib/server/schedule'; import { actions, load } from './+page.server'; const procFindMany = prisma.proclamation.findMany as ReturnType; const listBlocksMock = listBlocks as ReturnType; const createBlockMock = createBlock as ReturnType; const deleteBlockMock = deleteBlock as ReturnType; const locals = createLocals(mockUser() as never); beforeEach(() => { vi.clearAllMocks(); (prisma.proclamationCategory.findMany as ReturnType).mockResolvedValue([ { id: 2, name: 'Physical' } ]); (prisma.proclamationGroup.findMany as ReturnType).mockResolvedValue([ { id: 1, name: 'General' } ]); procFindMany.mockResolvedValue([{ id: 'p1', name: 'Peace', categoryId: 2, groupId: 1 }]); listBlocksMock.mockResolvedValue([]); }); describe('schedule load', () => { it('rejects unauthenticated requests', async () => { await expect(load({ locals: createLocals() } as never)).rejects.toMatchObject({ status: 403 }); }); it('never selects proclamation content', async () => { await load({ locals } as never); expect(procFindMany).toHaveBeenCalledWith( expect.objectContaining({ select: { id: true, name: true, categoryId: true, groupId: true } }) ); }); it('maps blocks to title/category/group only', async () => { listBlocksMock.mockResolvedValue([ { id: 'b1', startMinutes: 360, endMinutes: 480, dynamicAudio: true, proclamations: [ { proclamation: { id: 'p1', name: 'Peace', categoryId: 2, groupId: 1, content: '

secret

' } } ] } ]); const result = (await load({ locals } as never)) as { blocks: { id: string; dynamicAudio: boolean; proclamations: Record[]; }[]; }; expect(result.blocks[0].dynamicAudio).toBe(true); expect(result.blocks[0].proclamations[0]).toEqual({ id: 'p1', name: 'Peace', categoryId: 2, groupId: 1 }); expect(Object.keys(result.blocks[0].proclamations[0])).not.toContain('content'); }); }); describe('schedule actions', () => { it('createBlock rejects unauthenticated requests', async () => { await expect( actions.createBlock!({ request: createFormRequest({}), locals: createLocals() } as never) ).rejects.toMatchObject({ status: 403 }); }); it('createBlock surfaces the service error', async () => { createBlockMock.mockResolvedValue({ ok: false, error: 'Select at least one proclamation.' }); const result = await actions.createBlock!({ request: createFormRequest({ startMinutes: '360', endMinutes: '480', proclamationIds: '[]' }), locals } as never); expect(isActionFailure(result)).toBe(true); if (isActionFailure(result)) { expect(result.status).toBe(400); expect(result.data).toEqual({ error: 'Select at least one proclamation.' }); } }); it('createBlock parses the payload and succeeds', async () => { createBlockMock.mockResolvedValue({ ok: true, id: 'b1' }); const result = await actions.createBlock!({ request: createFormRequest({ startMinutes: '360', endMinutes: '480', proclamationIds: JSON.stringify(['p1', 'p2']), dynamicAudio: 'true' }), locals } as never); expect(result).toEqual({ success: true }); expect(createBlockMock).toHaveBeenCalledWith('user-1', { startMinutes: 360, endMinutes: 480, proclamationIds: ['p1', 'p2'], dynamicAudio: true }); }); it('createBlock defaults dynamic audio to false when the field is absent', async () => { createBlockMock.mockResolvedValue({ ok: true, id: 'b1' }); await actions.createBlock!({ request: createFormRequest({ startMinutes: '360', endMinutes: '480', proclamationIds: JSON.stringify(['p1']) }), locals } as never); expect(createBlockMock).toHaveBeenCalledWith( 'user-1', expect.objectContaining({ dynamicAudio: false }) ); }); it('deleteBlock returns not found without an id', async () => { const result = await actions.deleteBlock!({ request: createFormRequest({}), locals } as never); expect(isActionFailure(result)).toBe(true); if (isActionFailure(result)) { expect(result.data).toEqual({ error: 'Block not found.' }); } expect(deleteBlockMock).not.toHaveBeenCalled(); }); });