104 lines
3.9 KiB
TypeScript
104 lines
3.9 KiB
TypeScript
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();
|
|
});
|
|
});
|