import { describe, expect, it, vi } from 'vitest'; import { clearWhiteboardStrokes, createWhiteboard, insertWhiteboardStroke, listWhiteboardStrokes, } from './whiteboards'; function makeClient(opts: { user?: { id: string } | null; insertReturn?: { data: unknown; error: unknown }; selectReturn?: { data: unknown[]; error: unknown }; deleteReturn?: { error: unknown }; }): any { const single = vi.fn().mockResolvedValue(opts.insertReturn ?? { data: {}, error: null }); const order = vi.fn().mockResolvedValue(opts.selectReturn ?? { data: [], error: null }); const eqDelete = vi.fn().mockResolvedValue(opts.deleteReturn ?? { error: null }); const insertSelect = vi.fn().mockReturnValue({ single }); const insertChain = vi.fn().mockReturnValue({ select: insertSelect }); const selectChain = vi.fn().mockReturnValue({ eq: vi.fn().mockReturnValue({ order }), }); const deleteChain = vi.fn().mockReturnValue({ eq: eqDelete }); const from = vi.fn().mockReturnValue({ insert: insertChain, select: selectChain, delete: deleteChain, }); return { auth: { getUser: vi.fn().mockResolvedValue({ data: { user: opts.user ?? { id: 'u-1' } } }) }, from, }; } describe('createWhiteboard', () => { it('inserts with owner = current user', async () => { const client = makeClient({ insertReturn: { data: { id: 'w-1', conversation_id: 'c-1', owner_user_id: 'u-1', created_at: '2026-05-16T00:00:00Z', }, error: null, }, }); const out = await createWhiteboard(client, 'c-1'); expect(out).toEqual({ id: 'w-1', conversationId: 'c-1', ownerUserId: 'u-1', createdAt: '2026-05-16T00:00:00Z', }); }); }); describe('listWhiteboardStrokes', () => { it('maps DB rows to camelCase + ascending order', async () => { const client = makeClient({ selectReturn: { data: [ { id: 's-1', whiteboard_id: 'w-1', author_user_id: 'u-1', stroke_json: { tool: 'pen' }, created_at: '2026-05-16T00:00:00Z', }, ], error: null, }, }); const out = await listWhiteboardStrokes(client, 'w-1'); expect(out).toEqual([ { id: 's-1', whiteboardId: 'w-1', authorUserId: 'u-1', strokeJson: { tool: 'pen' }, createdAt: '2026-05-16T00:00:00Z', }, ]); }); }); describe('insertWhiteboardStroke', () => { it('writes author + stroke_json', async () => { const client = makeClient({ insertReturn: { data: { id: 's-2', whiteboard_id: 'w-1', author_user_id: 'u-1', stroke_json: { tool: 'pen', points: [[0, 0, 0]] }, created_at: '2026-05-16T00:00:01Z', }, error: null, }, }); const out = await insertWhiteboardStroke(client, { whiteboardId: 'w-1', strokeJson: { tool: 'pen', points: [[0, 0, 0]] }, }); expect(out.id).toBe('s-2'); expect((out.strokeJson as { tool: string }).tool).toBe('pen'); }); }); describe('clearWhiteboardStrokes', () => { it('does not throw on a successful delete', async () => { const client = makeClient({ deleteReturn: { error: null } }); await expect(clearWhiteboardStrokes(client, 'w-1')).resolves.toBeUndefined(); }); it('throws when delete returns an error', async () => { const client = makeClient({ deleteReturn: { error: { message: 'rls denied' } as any } }); await expect(clearWhiteboardStrokes(client, 'w-1')).rejects.toBeTruthy(); }); });