import { describe, expect, it } from 'vitest'; import type { Mission, Project, Task } from '@/lib/types'; import { validateMissionCollection, validateProjectCollection, validateProjectEntity, validateTaskCollection, } from './validators'; import { missionFixtures, projectFixtures, taskFixtures } from '@/spa/pages/page-fixtures'; describe('validateTaskCollection', () => { it('accepts a well-formed task collection', () => { expect(validateTaskCollection(taskFixtures)).toEqual({ data: taskFixtures, workspace: null, }); }); it('accepts an empty collection (a healthy empty state is a valid payload)', () => { expect(validateTaskCollection([])).toEqual({ data: [], workspace: null }); }); it.each([ ['not an array', { items: [] }], ['item is not an object', ['nope']], ['missing id', [{ ...(taskFixtures[0] as Task), id: undefined }]], ['missing title', [{ ...(taskFixtures[0] as Task), title: undefined }]], ['unknown status enum', [{ ...(taskFixtures[0] as Task), status: 'finished' }]], ['unknown priority enum', [{ ...(taskFixtures[0] as Task), priority: 'urgent' }]], ['tags of the wrong type', [{ ...(taskFixtures[0] as Task), tags: 'spa' }]], ['metadata of the wrong type', [{ ...(taskFixtures[0] as Task), metadata: 'notes' }]], ['createdAt of the wrong type', [{ ...(taskFixtures[0] as Task), createdAt: 1234 }]], ['null sneaks past a required string', [{ ...(taskFixtures[0] as Task), title: null }]], ])('rejects a malformed payload: %s', (_label, value) => { expect(validateTaskCollection(value)).toBeNull(); }); }); describe('validateMissionCollection', () => { it('accepts a well-formed mission collection', () => { expect(validateMissionCollection(missionFixtures)).toEqual({ data: missionFixtures, workspace: null, }); }); it.each([ ['not an array', null], ['item missing name', [{ ...(missionFixtures[0] as Mission), name: 42 }]], ['unknown status enum', [{ ...(missionFixtures[0] as Mission), status: 'canceled' }]], ['projectId of the wrong type', [{ ...(missionFixtures[0] as Mission), projectId: 7 }]], ])('rejects a malformed payload: %s', (_label, value) => { expect(validateMissionCollection(value)).toBeNull(); }); }); describe('validateProjectCollection', () => { it('accepts a uniform workspace-scoped collection and reports its workspace', () => { expect(validateProjectCollection(projectFixtures)).toEqual({ data: projectFixtures, workspace: 'user-1', }); }); it('accepts an empty collection with no workspace identity', () => { expect(validateProjectCollection([])).toEqual({ data: [], workspace: null }); }); it.each([ ['not an array', 42], ['item missing userId', [{ ...(projectFixtures[0] as Project), userId: undefined }]], ['unknown status enum', [{ ...(projectFixtures[0] as Project), status: 'live' }]], ['description of the wrong type', [{ ...(projectFixtures[0] as Project), description: 1 }]], ])('rejects a malformed payload: %s', (_label, value) => { expect(validateProjectCollection(value)).toBeNull(); }); it('rejects a collection mixing workspace identities (cross-workspace leak)', () => { const mixed = [ projectFixtures[0] as Project, { ...(projectFixtures[1] as Project), userId: 'user-2' }, ]; expect(validateProjectCollection(mixed)).toBeNull(); }); }); describe('validateProjectEntity', () => { it('accepts a well-formed project and reports its workspace', () => { expect(validateProjectEntity(projectFixtures[0])).toEqual({ data: projectFixtures[0], workspace: 'user-1', }); }); it.each([ ['not an object', 'project-1'], ['null', null], ['array', [projectFixtures[0]]], ['missing userId', [{ ...(projectFixtures[0] as Project), userId: null }]], ])('rejects a malformed entity: %s', (_label, value) => { expect(validateProjectEntity(value)).toBeNull(); }); });