271 lines
7.8 KiB
TypeScript
271 lines
7.8 KiB
TypeScript
import {
|
|
CreateTaskSchema,
|
|
UpdateTaskSchema,
|
|
TaskQuerySchema,
|
|
BulkCreateTasksSchema,
|
|
BulkUpdateTasksSchema,
|
|
BulkDeleteTasksSchema,
|
|
DuplicateTaskSchema,
|
|
CreateTemplateFromTaskSchema,
|
|
ApplyTemplateSchema
|
|
} from '../../src/api/validators/task.validator';
|
|
|
|
describe('Task Validators', () => {
|
|
describe('CreateTaskSchema', () => {
|
|
it('should validate a valid task creation request', () => {
|
|
const validTask = {
|
|
title: 'Test Task',
|
|
description: 'Test Description',
|
|
priority: 'medium',
|
|
task_type: 'feature',
|
|
project: '123e4567-e89b-12d3-a456-426614174000'
|
|
};
|
|
|
|
const result = CreateTaskSchema.safeParse(validTask);
|
|
expect(result.success).toBe(true);
|
|
if (result.success) {
|
|
expect(result.data.title).toBe('Test Task');
|
|
expect(result.data.priority).toBe('medium');
|
|
}
|
|
});
|
|
|
|
it('should reject invalid task creation request', () => {
|
|
const invalidTask = {
|
|
// Missing required title
|
|
description: 'Test Description',
|
|
priority: 'invalid-priority', // Invalid enum value
|
|
project: 'not-a-uuid' // Invalid UUID
|
|
};
|
|
|
|
const result = CreateTaskSchema.safeParse(invalidTask);
|
|
expect(result.success).toBe(false);
|
|
if (!result.success) {
|
|
expect(result.error.errors).toHaveLength(3);
|
|
}
|
|
});
|
|
|
|
it('should apply default values', () => {
|
|
const taskWithDefaults = {
|
|
title: 'Test Task',
|
|
project: '123e4567-e89b-12d3-a456-426614174000'
|
|
};
|
|
|
|
const result = CreateTaskSchema.safeParse(taskWithDefaults);
|
|
expect(result.success).toBe(true);
|
|
if (result.success) {
|
|
expect(result.data.priority).toBe('medium');
|
|
expect(result.data.progress_percentage).toBe(0);
|
|
expect(result.data.ai_generated).toBe(false);
|
|
expect(result.data.auto_status_updates).toBe(false);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('UpdateTaskSchema', () => {
|
|
it('should validate partial update', () => {
|
|
const partialUpdate = {
|
|
title: 'Updated Title',
|
|
priority: 'high'
|
|
};
|
|
|
|
const result = UpdateTaskSchema.safeParse(partialUpdate);
|
|
expect(result.success).toBe(true);
|
|
if (result.success) {
|
|
expect(result.data.title).toBe('Updated Title');
|
|
expect(result.data.priority).toBe('high');
|
|
}
|
|
});
|
|
|
|
it('should accept empty update', () => {
|
|
const emptyUpdate = {};
|
|
|
|
const result = UpdateTaskSchema.safeParse(emptyUpdate);
|
|
expect(result.success).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('TaskQuerySchema', () => {
|
|
it('should validate query parameters', () => {
|
|
const validQuery = {
|
|
page: '2',
|
|
limit: '50',
|
|
sort: 'created_at,-priority',
|
|
search: 'test query'
|
|
};
|
|
|
|
const result = TaskQuerySchema.safeParse(validQuery);
|
|
expect(result.success).toBe(true);
|
|
if (result.success) {
|
|
expect(result.data.page).toBe(2);
|
|
expect(result.data.limit).toBe(50);
|
|
expect(result.data.sort).toBe('created_at,-priority');
|
|
}
|
|
});
|
|
|
|
it('should apply default pagination values', () => {
|
|
const emptyQuery = {};
|
|
|
|
const result = TaskQuerySchema.safeParse(emptyQuery);
|
|
expect(result.success).toBe(true);
|
|
if (result.success) {
|
|
expect(result.data.page).toBe(1);
|
|
expect(result.data.limit).toBe(20);
|
|
}
|
|
});
|
|
|
|
it('should reject invalid pagination values', () => {
|
|
const invalidQuery = {
|
|
page: '0', // Must be positive
|
|
limit: '200' // Exceeds max limit of 100
|
|
};
|
|
|
|
const result = TaskQuerySchema.safeParse(invalidQuery);
|
|
expect(result.success).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('BulkCreateTasksSchema', () => {
|
|
it('should validate bulk create request', () => {
|
|
const bulkCreate = {
|
|
tasks: [
|
|
{
|
|
title: 'Task 1',
|
|
project: '123e4567-e89b-12d3-a456-426614174000'
|
|
},
|
|
{
|
|
title: 'Task 2',
|
|
project: '123e4567-e89b-12d3-a456-426614174000'
|
|
}
|
|
]
|
|
};
|
|
|
|
const result = BulkCreateTasksSchema.safeParse(bulkCreate);
|
|
expect(result.success).toBe(true);
|
|
if (result.success) {
|
|
expect(result.data.tasks).toHaveLength(2);
|
|
}
|
|
});
|
|
|
|
it('should reject empty tasks array', () => {
|
|
const emptyBulk = {
|
|
tasks: []
|
|
};
|
|
|
|
const result = BulkCreateTasksSchema.safeParse(emptyBulk);
|
|
expect(result.success).toBe(false);
|
|
});
|
|
|
|
it('should reject more than 100 tasks', () => {
|
|
const tooManyTasks = {
|
|
tasks: Array(101).fill({
|
|
title: 'Task',
|
|
project: '123e4567-e89b-12d3-a456-426614174000'
|
|
})
|
|
};
|
|
|
|
const result = BulkCreateTasksSchema.safeParse(tooManyTasks);
|
|
expect(result.success).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('BulkUpdateTasksSchema', () => {
|
|
it('should validate bulk update request', () => {
|
|
const bulkUpdate = {
|
|
ids: [
|
|
'123e4567-e89b-12d3-a456-426614174000',
|
|
'123e4567-e89b-12d3-a456-426614174001'
|
|
],
|
|
updates: {
|
|
priority: 'high',
|
|
status: '123e4567-e89b-12d3-a456-426614174002'
|
|
}
|
|
};
|
|
|
|
const result = BulkUpdateTasksSchema.safeParse(bulkUpdate);
|
|
expect(result.success).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('BulkDeleteTasksSchema', () => {
|
|
it('should validate bulk delete request', () => {
|
|
const bulkDelete = {
|
|
ids: [
|
|
'123e4567-e89b-12d3-a456-426614174000',
|
|
'123e4567-e89b-12d3-a456-426614174001'
|
|
]
|
|
};
|
|
|
|
const result = BulkDeleteTasksSchema.safeParse(bulkDelete);
|
|
expect(result.success).toBe(true);
|
|
});
|
|
|
|
it('should reject invalid UUIDs', () => {
|
|
const invalidDelete = {
|
|
ids: ['not-a-uuid', 'another-invalid-id']
|
|
};
|
|
|
|
const result = BulkDeleteTasksSchema.safeParse(invalidDelete);
|
|
expect(result.success).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('DuplicateTaskSchema', () => {
|
|
it('should validate duplicate task request', () => {
|
|
const duplicateRequest = {
|
|
taskId: '123e4567-e89b-12d3-a456-426614174000',
|
|
includeSubtasks: true,
|
|
includeAttachments: false,
|
|
overrides: {
|
|
title: 'Duplicated Task'
|
|
}
|
|
};
|
|
|
|
const result = DuplicateTaskSchema.safeParse(duplicateRequest);
|
|
expect(result.success).toBe(true);
|
|
if (result.success) {
|
|
expect(result.data.includeSubtasks).toBe(true);
|
|
expect(result.data.includeAttachments).toBe(false);
|
|
expect(result.data.includeComments).toBe(false); // Default value
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('CreateTemplateFromTaskSchema', () => {
|
|
it('should validate template creation request', () => {
|
|
const templateRequest = {
|
|
taskId: '123e4567-e89b-12d3-a456-426614174000',
|
|
templateName: 'Feature Template',
|
|
templateDescription: 'Template for new features',
|
|
excludeFields: ['notes', 'created_by']
|
|
};
|
|
|
|
const result = CreateTemplateFromTaskSchema.safeParse(templateRequest);
|
|
expect(result.success).toBe(true);
|
|
});
|
|
|
|
it('should require template name', () => {
|
|
const invalidRequest = {
|
|
taskId: '123e4567-e89b-12d3-a456-426614174000'
|
|
// Missing templateName
|
|
};
|
|
|
|
const result = CreateTemplateFromTaskSchema.safeParse(invalidRequest);
|
|
expect(result.success).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('ApplyTemplateSchema', () => {
|
|
it('should validate template application request', () => {
|
|
const applyRequest = {
|
|
templateId: '123e4567-e89b-12d3-a456-426614174000',
|
|
projectId: '123e4567-e89b-12d3-a456-426614174001',
|
|
overrides: {
|
|
title: 'Custom Title from Template'
|
|
}
|
|
};
|
|
|
|
const result = ApplyTemplateSchema.safeParse(applyRequest);
|
|
expect(result.success).toBe(true);
|
|
});
|
|
});
|
|
}); |