Files
FrenoCorp/server/trpc/project-router.test.ts
FrenoCorp Agent 8dc4827597 FRE-592: Implement character database and relationship mapping
Add full character management system with enriched profiles (bio, traits,
arcs, motivation, conflict, secrets), relationship mapping between
characters with types and strength, character search/filter by role and
arc type, and character statistics (scene count, dialogue, screen time).

Includes database schema, tRPC router procedures, SolidJS components,
API hooks, and unit tests.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-24 02:24:31 -04:00

212 lines
5.5 KiB
TypeScript

import { describe, it, expect, beforeEach } from 'vitest';
import { appRouter } from './index';
import type { Project } from '../../server/types/project';
describe('tRPC API Layer', () => {
let ctx: { userId: string };
beforeEach(() => {
ctx = { userId: '123e4567-e89b-12d3-a456-426614174000' };
});
describe('Project CRUD', () => {
it('should create a project', async () => {
const project = await appRouter.project.createProject.mutate({
input: {
name: 'Test Project',
description: 'A test project',
},
ctx,
});
expect(project).toMatchObject({
name: 'Test Project',
description: 'A test project',
userId: ctx.userId,
});
expect(project.id).toBeDefined();
expect(project.createdAt).toBeInstanceOf(Date);
expect(project.updatedAt).toBeInstanceOf(Date);
});
it('should list projects', async () => {
const projects = await appRouter.project.listProjects.query({
ctx: { userId: ctx.userId },
});
expect(Array.isArray(projects)).toBe(true);
});
it('should get a specific project', async () => {
// First create a project
const created = await appRouter.project.createProject.mutate({
input: { name: 'Get Test' },
ctx,
});
const project = await appRouter.project.getProject.query({
input: { id: created.id },
ctx,
});
expect(project.id).toBe(created.id);
expect(project.name).toBe('Get Test');
});
it('should update a project', async () => {
const created = await appRouter.project.createProject.mutate({
input: { name: 'Update Test' },
ctx,
});
const updated = await appRouter.project.updateProject.mutate({
input: {
id: created.id,
name: 'Updated Test',
description: 'Updated description',
},
ctx,
});
expect(updated.name).toBe('Updated Test');
expect(updated.description).toBe('Updated description');
});
it('should delete a project', async () => {
const created = await appRouter.project.createProject.mutate({
input: { name: 'Delete Test' },
ctx,
});
const result = await appRouter.project.deleteProject.mutate({
input: { id: created.id },
ctx,
});
expect(result).toEqual({ success: true });
});
});
describe('Character CRUD', () => {
let projectId: string;
beforeEach(async () => {
const project = await appRouter.project.createProject.mutate({
input: { name: 'Character Test Project' },
ctx,
});
projectId = project.id;
});
it('should create a character', async () => {
const character = await appRouter.project.createCharacter.mutate({
input: {
name: 'John Doe',
description: 'Main character',
projectId,
},
ctx,
});
expect(character).toMatchObject({
name: 'John Doe',
description: 'Main character',
projectId,
});
});
it('should list characters for a project', async () => {
await appRouter.project.createCharacter.mutate({
input: { name: 'Char 1', projectId },
ctx,
});
const characters = await appRouter.project.listCharacters.query({
input: { projectId },
ctx,
});
expect(characters.length).toBeGreaterThan(0);
});
});
describe('Scene CRUD', () => {
let projectId: string;
beforeEach(async () => {
const project = await appRouter.project.createProject.mutate({
input: { name: 'Scene Test Project' },
ctx,
});
projectId = project.id;
});
it('should create a scene', async () => {
const scene = await appRouter.project.createScene.mutate({
input: {
title: 'INT. OFFICE - DAY',
content: 'John sits at his desk.',
projectId,
order: 1,
},
ctx,
});
expect(scene).toMatchObject({
title: 'INT. OFFICE - DAY',
content: 'John sits at his desk.',
projectId,
order: 1,
});
});
it('should list scenes for a project', async () => {
await appRouter.project.createScene.mutate({
input: { title: 'Scene 1', projectId, order: 1 },
ctx,
});
const scenes = await appRouter.project.listScenes.query({
input: { projectId },
ctx,
});
expect(scenes.length).toBeGreaterThan(0);
});
it('should update scene order', async () => {
const scene = await appRouter.project.createScene.mutate({
input: { title: 'Reorder Scene', projectId, order: 1 },
ctx,
});
const updated = await appRouter.project.updateScene.mutate({
input: { id: scene.id, order: 5 },
ctx,
});
expect(updated.order).toBe(5);
});
});
describe('Error Handling', () => {
it('should throw error when getting non-existent project', async () => {
await expect(
appRouter.project.getProject.query({
input: { id: '00000000-0000-0000-0000-000000000000' },
ctx,
})
).rejects.toThrow('not found');
});
it('should throw error when deleting non-existent project', async () => {
const result = await appRouter.project.deleteProject.mutate({
input: { id: '00000000-0000-0000-0000-000000000000' },
ctx,
});
expect(result).toEqual({ success: false });
});
});
});