Implement Personality system backend with database schema, service, controller, and comprehensive tests. Personalities define assistant behavior with system prompts and LLM configuration. Changes: - Update Personality model in schema.prisma with LLM provider relation - Create PersonalitiesService with CRUD and default management - Create PersonalitiesController with REST endpoints - Add DTOs with validation (create/update) - Add entity for type safety - Remove unused PromptFormatterService - Achieve 26 tests with full coverage Endpoints: - GET /personality - List all - GET /personality/default - Get default - GET /personality/by-name/:name - Get by name - GET /personality/:id - Get one - POST /personality - Create - PATCH /personality/:id - Update - DELETE /personality/:id - Delete - POST /personality/:id/set-default - Set default Fixes #130 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
180 lines
5.5 KiB
TypeScript
180 lines
5.5 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
import { Test, TestingModule } from "@nestjs/testing";
|
|
import { PersonalitiesController } from "./personalities.controller";
|
|
import { PersonalitiesService } from "./personalities.service";
|
|
import { CreatePersonalityDto, UpdatePersonalityDto } from "./dto";
|
|
import { AuthGuard } from "../auth/guards/auth.guard";
|
|
|
|
describe("PersonalitiesController", () => {
|
|
let controller: PersonalitiesController;
|
|
let service: PersonalitiesService;
|
|
|
|
const mockWorkspaceId = "workspace-123";
|
|
const mockUserId = "user-123";
|
|
const mockPersonalityId = "personality-123";
|
|
|
|
const mockPersonality = {
|
|
id: mockPersonalityId,
|
|
workspaceId: mockWorkspaceId,
|
|
name: "professional-assistant",
|
|
displayName: "Professional Assistant",
|
|
description: "A professional communication assistant",
|
|
systemPrompt: "You are a professional assistant who helps with tasks.",
|
|
temperature: 0.7,
|
|
maxTokens: 2000,
|
|
llmProviderInstanceId: "provider-123",
|
|
isDefault: true,
|
|
isEnabled: true,
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
};
|
|
|
|
const mockRequest = {
|
|
user: { id: mockUserId },
|
|
workspaceId: mockWorkspaceId,
|
|
};
|
|
|
|
const mockPersonalitiesService = {
|
|
create: vi.fn(),
|
|
findAll: vi.fn(),
|
|
findOne: vi.fn(),
|
|
findByName: vi.fn(),
|
|
findDefault: vi.fn(),
|
|
update: vi.fn(),
|
|
delete: vi.fn(),
|
|
setDefault: vi.fn(),
|
|
};
|
|
|
|
beforeEach(async () => {
|
|
const module: TestingModule = await Test.createTestingModule({
|
|
controllers: [PersonalitiesController],
|
|
providers: [
|
|
{
|
|
provide: PersonalitiesService,
|
|
useValue: mockPersonalitiesService,
|
|
},
|
|
],
|
|
})
|
|
.overrideGuard(AuthGuard)
|
|
.useValue({ canActivate: () => true })
|
|
.compile();
|
|
|
|
controller = module.get<PersonalitiesController>(PersonalitiesController);
|
|
service = module.get<PersonalitiesService>(PersonalitiesService);
|
|
|
|
// Reset mocks
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe("findAll", () => {
|
|
it("should return all personalities", async () => {
|
|
const mockPersonalities = [mockPersonality];
|
|
mockPersonalitiesService.findAll.mockResolvedValue(mockPersonalities);
|
|
|
|
const result = await controller.findAll(mockRequest);
|
|
|
|
expect(result).toEqual(mockPersonalities);
|
|
expect(service.findAll).toHaveBeenCalledWith(mockWorkspaceId);
|
|
});
|
|
});
|
|
|
|
describe("findOne", () => {
|
|
it("should return a personality by id", async () => {
|
|
mockPersonalitiesService.findOne.mockResolvedValue(mockPersonality);
|
|
|
|
const result = await controller.findOne(mockRequest, mockPersonalityId);
|
|
|
|
expect(result).toEqual(mockPersonality);
|
|
expect(service.findOne).toHaveBeenCalledWith(mockWorkspaceId, mockPersonalityId);
|
|
});
|
|
});
|
|
|
|
describe("findByName", () => {
|
|
it("should return a personality by name", async () => {
|
|
mockPersonalitiesService.findByName.mockResolvedValue(mockPersonality);
|
|
|
|
const result = await controller.findByName(mockRequest, "professional-assistant");
|
|
|
|
expect(result).toEqual(mockPersonality);
|
|
expect(service.findByName).toHaveBeenCalledWith(mockWorkspaceId, "professional-assistant");
|
|
});
|
|
});
|
|
|
|
describe("findDefault", () => {
|
|
it("should return the default personality", async () => {
|
|
mockPersonalitiesService.findDefault.mockResolvedValue(mockPersonality);
|
|
|
|
const result = await controller.findDefault(mockRequest);
|
|
|
|
expect(result).toEqual(mockPersonality);
|
|
expect(service.findDefault).toHaveBeenCalledWith(mockWorkspaceId);
|
|
});
|
|
});
|
|
|
|
describe("create", () => {
|
|
it("should create a new personality", async () => {
|
|
const createDto: CreatePersonalityDto = {
|
|
name: "casual-helper",
|
|
displayName: "Casual Helper",
|
|
description: "A casual helper",
|
|
systemPrompt: "You are a casual assistant.",
|
|
temperature: 0.8,
|
|
maxTokens: 1500,
|
|
};
|
|
|
|
mockPersonalitiesService.create.mockResolvedValue({
|
|
...mockPersonality,
|
|
...createDto,
|
|
});
|
|
|
|
const result = await controller.create(mockRequest, createDto);
|
|
|
|
expect(result).toMatchObject(createDto);
|
|
expect(service.create).toHaveBeenCalledWith(mockWorkspaceId, createDto);
|
|
});
|
|
});
|
|
|
|
describe("update", () => {
|
|
it("should update a personality", async () => {
|
|
const updateDto: UpdatePersonalityDto = {
|
|
description: "Updated description",
|
|
temperature: 0.9,
|
|
};
|
|
|
|
mockPersonalitiesService.update.mockResolvedValue({
|
|
...mockPersonality,
|
|
...updateDto,
|
|
});
|
|
|
|
const result = await controller.update(mockRequest, mockPersonalityId, updateDto);
|
|
|
|
expect(result).toMatchObject(updateDto);
|
|
expect(service.update).toHaveBeenCalledWith(mockWorkspaceId, mockPersonalityId, updateDto);
|
|
});
|
|
});
|
|
|
|
describe("delete", () => {
|
|
it("should delete a personality", async () => {
|
|
mockPersonalitiesService.delete.mockResolvedValue(undefined);
|
|
|
|
await controller.delete(mockRequest, mockPersonalityId);
|
|
|
|
expect(service.delete).toHaveBeenCalledWith(mockWorkspaceId, mockPersonalityId);
|
|
});
|
|
});
|
|
|
|
describe("setDefault", () => {
|
|
it("should set a personality as default", async () => {
|
|
mockPersonalitiesService.setDefault.mockResolvedValue({
|
|
...mockPersonality,
|
|
isDefault: true,
|
|
});
|
|
|
|
const result = await controller.setDefault(mockRequest, mockPersonalityId);
|
|
|
|
expect(result).toMatchObject({ isDefault: true });
|
|
expect(service.setDefault).toHaveBeenCalledWith(mockWorkspaceId, mockPersonalityId);
|
|
});
|
|
});
|
|
});
|