- Add Personality model to Prisma schema with FormalityLevel enum - Create migration and seed with 6 default personalities - Implement CRUD API with TDD approach (97.67% coverage) * PersonalitiesService: findAll, findOne, findDefault, create, update, remove * PersonalitiesController: REST endpoints with auth guards * Comprehensive test coverage (21 passing tests) - Add Personality types to shared package - Create frontend components: * PersonalitySelector: dropdown for choosing personality * PersonalityPreview: preview personality style and system prompt * PersonalityForm: create/edit personalities with validation * Settings page: manage personalities with CRUD operations - Integrate with Ollama API: * Support personalityId in chat endpoint * Auto-inject system prompt from personality * Fall back to default personality if not specified - API client for frontend personality management All tests passing with 97.67% backend coverage (exceeds 85% requirement)
169 lines
5.0 KiB
TypeScript
169 lines
5.0 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { validate } from "class-validator";
|
|
import { plainToClass } from "class-transformer";
|
|
import { QueryTasksDto } from "./query-tasks.dto";
|
|
import { TaskStatus, TaskPriority } from "@prisma/client";
|
|
import { SortOrder } from "../../common/dto";
|
|
|
|
describe("QueryTasksDto", () => {
|
|
const validWorkspaceId = "123e4567-e89b-12d3-a456-426614174000";
|
|
|
|
it("should accept valid workspaceId", async () => {
|
|
const dto = plainToClass(QueryTasksDto, {
|
|
workspaceId: validWorkspaceId,
|
|
});
|
|
|
|
const errors = await validate(dto);
|
|
expect(errors.length).toBe(0);
|
|
});
|
|
|
|
it("should reject invalid workspaceId", async () => {
|
|
const dto = plainToClass(QueryTasksDto, {
|
|
workspaceId: "not-a-uuid",
|
|
});
|
|
|
|
const errors = await validate(dto);
|
|
expect(errors.length).toBeGreaterThan(0);
|
|
expect(errors.some(e => e.property === "workspaceId")).toBe(true);
|
|
});
|
|
|
|
it("should accept valid status filter", async () => {
|
|
const dto = plainToClass(QueryTasksDto, {
|
|
workspaceId: validWorkspaceId,
|
|
status: TaskStatus.IN_PROGRESS,
|
|
});
|
|
|
|
const errors = await validate(dto);
|
|
expect(errors.length).toBe(0);
|
|
expect(Array.isArray(dto.status)).toBe(true);
|
|
expect(dto.status).toEqual([TaskStatus.IN_PROGRESS]);
|
|
});
|
|
|
|
it("should accept multiple status filters", async () => {
|
|
const dto = plainToClass(QueryTasksDto, {
|
|
workspaceId: validWorkspaceId,
|
|
status: [TaskStatus.IN_PROGRESS, TaskStatus.NOT_STARTED],
|
|
});
|
|
|
|
const errors = await validate(dto);
|
|
expect(errors.length).toBe(0);
|
|
expect(Array.isArray(dto.status)).toBe(true);
|
|
expect(dto.status).toHaveLength(2);
|
|
});
|
|
|
|
it("should accept valid priority filter", async () => {
|
|
const dto = plainToClass(QueryTasksDto, {
|
|
workspaceId: validWorkspaceId,
|
|
priority: TaskPriority.HIGH,
|
|
});
|
|
|
|
const errors = await validate(dto);
|
|
expect(errors.length).toBe(0);
|
|
expect(Array.isArray(dto.priority)).toBe(true);
|
|
expect(dto.priority).toEqual([TaskPriority.HIGH]);
|
|
});
|
|
|
|
it("should accept multiple priority filters", async () => {
|
|
const dto = plainToClass(QueryTasksDto, {
|
|
workspaceId: validWorkspaceId,
|
|
priority: [TaskPriority.HIGH, TaskPriority.LOW],
|
|
});
|
|
|
|
const errors = await validate(dto);
|
|
expect(errors.length).toBe(0);
|
|
expect(Array.isArray(dto.priority)).toBe(true);
|
|
expect(dto.priority).toHaveLength(2);
|
|
});
|
|
|
|
it("should accept search parameter", async () => {
|
|
const dto = plainToClass(QueryTasksDto, {
|
|
workspaceId: validWorkspaceId,
|
|
search: "test task",
|
|
});
|
|
|
|
const errors = await validate(dto);
|
|
expect(errors.length).toBe(0);
|
|
expect(dto.search).toBe("test task");
|
|
});
|
|
|
|
it("should accept sortBy parameter", async () => {
|
|
const dto = plainToClass(QueryTasksDto, {
|
|
workspaceId: validWorkspaceId,
|
|
sortBy: "priority,dueDate",
|
|
});
|
|
|
|
const errors = await validate(dto);
|
|
expect(errors.length).toBe(0);
|
|
expect(dto.sortBy).toBe("priority,dueDate");
|
|
});
|
|
|
|
it("should accept sortOrder parameter", async () => {
|
|
const dto = plainToClass(QueryTasksDto, {
|
|
workspaceId: validWorkspaceId,
|
|
sortOrder: SortOrder.ASC,
|
|
});
|
|
|
|
const errors = await validate(dto);
|
|
expect(errors.length).toBe(0);
|
|
expect(dto.sortOrder).toBe(SortOrder.ASC);
|
|
});
|
|
|
|
it("should accept domainId filter", async () => {
|
|
const domainId = "123e4567-e89b-12d3-a456-426614174001";
|
|
const dto = plainToClass(QueryTasksDto, {
|
|
workspaceId: validWorkspaceId,
|
|
domainId,
|
|
});
|
|
|
|
const errors = await validate(dto);
|
|
expect(errors.length).toBe(0);
|
|
expect(Array.isArray(dto.domainId)).toBe(true);
|
|
expect(dto.domainId).toEqual([domainId]);
|
|
});
|
|
|
|
it("should accept multiple domainId filters", async () => {
|
|
const domainIds = [
|
|
"123e4567-e89b-12d3-a456-426614174001",
|
|
"123e4567-e89b-12d3-a456-426614174002",
|
|
];
|
|
const dto = plainToClass(QueryTasksDto, {
|
|
workspaceId: validWorkspaceId,
|
|
domainId: domainIds,
|
|
});
|
|
|
|
const errors = await validate(dto);
|
|
expect(errors.length).toBe(0);
|
|
expect(Array.isArray(dto.domainId)).toBe(true);
|
|
expect(dto.domainId).toHaveLength(2);
|
|
});
|
|
|
|
it("should accept date range filters", async () => {
|
|
const dto = plainToClass(QueryTasksDto, {
|
|
workspaceId: validWorkspaceId,
|
|
dueDateFrom: "2024-01-01T00:00:00Z",
|
|
dueDateTo: "2024-12-31T23:59:59Z",
|
|
});
|
|
|
|
const errors = await validate(dto);
|
|
expect(errors.length).toBe(0);
|
|
});
|
|
|
|
it("should accept all filters combined", async () => {
|
|
const dto = plainToClass(QueryTasksDto, {
|
|
workspaceId: validWorkspaceId,
|
|
status: [TaskStatus.IN_PROGRESS, TaskStatus.NOT_STARTED],
|
|
priority: [TaskPriority.HIGH, TaskPriority.MEDIUM],
|
|
search: "urgent task",
|
|
sortBy: "priority,dueDate",
|
|
sortOrder: SortOrder.ASC,
|
|
page: 2,
|
|
limit: 25,
|
|
dueDateFrom: "2024-01-01T00:00:00Z",
|
|
dueDateTo: "2024-12-31T23:59:59Z",
|
|
});
|
|
|
|
const errors = await validate(dto);
|
|
expect(errors.length).toBe(0);
|
|
});
|
|
});
|