import { describe, it, expect, beforeEach } from 'vitest'; import { appRouter } from './index'; import { getTestDb, resetTestDb } from './test-setup'; import { resetInMemoryState } from './revisions-router'; import type { TRPCContext } from './types'; describe('revisionsRouter', () => { let ctx: TRPCContext; let caller: ReturnType; beforeEach(async () => { await resetTestDb(); const db = await getTestDb(); await resetInMemoryState(db); ctx = { userId: 1, db }; caller = appRouter.createCaller(ctx); }); describe('createRevision', () => { it('should create a revision with version 1', async () => { const result = await caller.revisions.createRevision({ scriptId: 1, title: 'Initial draft', content: 'FADE IN:\n\nINT. ROOM - DAY', }); expect(result.versionNumber).toBe(1); expect(result.branchName).toBe('main'); expect(result.status).toBe('draft'); expect(result.authorId).toBe(1); }); it('should increment version number for same script', async () => { await caller.revisions.createRevision({ scriptId: 1, title: 'v1', content: 'content1', }); const result = await caller.revisions.createRevision({ scriptId: 1, title: 'v2', content: 'content2', }); expect(result.versionNumber).toBe(2); }); it('should support custom branch', async () => { const result = await caller.revisions.createRevision({ scriptId: 1, title: 'Branch revision', content: 'branch content', branchName: 'feature-act2', }); expect(result.branchName).toBe('feature-act2'); }); }); describe('listRevisions', () => { it('should return empty array for unknown script', async () => { const result = await caller.revisions.listRevisions({ scriptId: 999 }); expect(result).toEqual([]); }); it('should filter by branch', async () => { await caller.revisions.createRevision({ scriptId: 1, title: 'main v1', content: 'main', branchName: 'main', }); await caller.revisions.createRevision({ scriptId: 1, title: 'feature v1', content: 'feature', branchName: 'feature', }); const mainRevisions = await caller.revisions.listRevisions({ scriptId: 1, branchName: 'main', }); expect(mainRevisions).toHaveLength(1); expect(mainRevisions[0]!.branchName).toBe('main'); }); }); describe('acceptRevision', () => { it('should accept a revision', async () => { const created = await caller.revisions.createRevision({ scriptId: 1, title: 'To accept', content: 'content', }); const result = await caller.revisions.acceptRevision({ revisionId: created.id, }); expect(result.status).toBe('accepted'); expect(result.reviewedById).toBe(1); expect(result.reviewedAt).toBeDefined(); }); }); describe('rejectRevision', () => { it('should reject a revision with reason', async () => { const created = await caller.revisions.createRevision({ scriptId: 1, title: 'To reject', content: 'content', }); const result = await caller.revisions.rejectRevision({ revisionId: created.id, reason: 'Needs more work on dialogue', }); expect(result.status).toBe('rejected'); expect(result.summary).toContain('Needs more work on dialogue'); }); }); describe('rollbackToRevision', () => { it('should create a new revision with old content', async () => { const original = await caller.revisions.createRevision({ scriptId: 1, title: 'Original', content: 'original content', }); await caller.revisions.createRevision({ scriptId: 1, title: 'Changed', content: 'changed content', }); const rollback = await caller.revisions.rollbackToRevision({ scriptId: 1, revisionId: original.id, }); expect(rollback.content).toBe('original content'); expect(rollback.versionNumber).toBe(3); expect(rollback.title).toContain('Rollback'); }); }); describe('compareRevisions', () => { it('should compare two revisions', async () => { const rev1 = await caller.revisions.createRevision({ scriptId: 1, title: 'v1', content: 'line1\nline2\nline3', }); const rev2 = await caller.revisions.createRevision({ scriptId: 1, title: 'v2', content: 'line1\nchanged\nline3', }); const result = await caller.revisions.compareRevisions({ baseRevisionId: rev1.id, targetRevisionId: rev2.id, }); expect(result.diff.modifications).toBe(1); expect(result.diff.additions).toBe(0); expect(result.diff.deletions).toBe(0); }); }); describe('getTimeline', () => { it('should return timeline entries in chronological order', async () => { await caller.revisions.createRevision({ scriptId: 1, title: 'First', content: 'first', }); await caller.revisions.createRevision({ scriptId: 1, title: 'Second', content: 'second', }); const timeline = await caller.revisions.getTimeline({ scriptId: 1 }); expect(timeline).toHaveLength(2); expect(timeline[0]!.revision.title).toBe('First'); expect(timeline[1]!.revision.title).toBe('Second'); }); }); describe('getBranches', () => { it('should return branch information', async () => { await caller.revisions.createRevision({ scriptId: 1, title: 'main v1', content: 'main', }); await caller.revisions.createBranch({ scriptId: 1, branchName: 'feature', }); const branches = await caller.revisions.getBranches({ scriptId: 1 }); expect(branches).toHaveLength(2); const branchNames = branches.map((b: any) => b.branchName); expect(branchNames).toContain('main'); expect(branchNames).toContain('feature'); }); }); describe('deleteRevision', () => { it('should delete a revision', async () => { const created = await caller.revisions.createRevision({ scriptId: 1, title: 'To delete', content: 'content', }); const result = await caller.revisions.deleteRevision({ id: created.id }); expect(result.success).toBe(true); await expect( caller.revisions.getRevision({ id: created.id }) ).rejects.toThrow(); }); }); });