import { vi } from "vitest"; import { RunnerJobStatus, JobStepStatus, JobStepPhase, JobStepType } from "@prisma/client"; import type { PrismaService } from "../../src/prisma/prisma.service"; /** * Create a mock RunnerJob */ export function createMockRunnerJob( overrides?: Partial<{ id: string; workspaceId: string; type: string; status: RunnerJobStatus; priority: number; progressPercent: number; result: unknown; error: string | null; createdAt: Date; startedAt: Date | null; completedAt: Date | null; agentTaskId: string | null; }> ) { return { id: "job-123", workspaceId: "workspace-123", type: "code-task", status: RunnerJobStatus.PENDING, priority: 10, progressPercent: 0, result: null, error: null, createdAt: new Date(), startedAt: null, completedAt: null, agentTaskId: null, ...overrides, }; } /** * Create a mock JobStep */ export function createMockJobStep( overrides?: Partial<{ id: string; jobId: string; ordinal: number; phase: JobStepPhase; name: string; type: JobStepType; status: JobStepStatus; output: string | null; tokensInput: number | null; tokensOutput: number | null; startedAt: Date | null; completedAt: Date | null; durationMs: number | null; }> ) { return { id: "step-123", jobId: "job-123", ordinal: 1, phase: JobStepPhase.VALIDATION, name: "Validate requirements", type: JobStepType.TOOL, status: JobStepStatus.PENDING, output: null, tokensInput: null, tokensOutput: null, startedAt: null, completedAt: null, durationMs: null, ...overrides, }; } /** * Create a mock JobEvent */ export function createMockJobEvent( overrides?: Partial<{ id: string; jobId: string; stepId: string | null; type: string; timestamp: Date; actor: string; payload: unknown; }> ) { return { id: "event-123", jobId: "job-123", stepId: null, type: "job.created", timestamp: new Date(), actor: "stitcher", payload: {}, ...overrides, }; } /** * Create a mock Prisma service with commonly used methods */ export function createMockPrismaService(): Partial { const jobs = new Map>(); const steps = new Map>(); const events: ReturnType[] = []; return { runnerJob: { create: vi.fn().mockImplementation(({ data }) => { // Use a counter to ensure unique IDs even if called in quick succession const timestamp = Date.now(); const randomSuffix = Math.floor(Math.random() * 1000); const job = createMockRunnerJob({ id: `job-${timestamp}-${randomSuffix}`, workspaceId: data.workspaceId || data.workspace?.connect?.id, type: data.type, status: data.status, priority: data.priority, progressPercent: data.progressPercent, }); jobs.set(job.id, job); return Promise.resolve(job); }), findUnique: vi.fn().mockImplementation(({ where, include }) => { const job = jobs.get(where.id); if (!job) return Promise.resolve(null); const result = { ...job }; if (include?.steps) { (result as never)["steps"] = Array.from(steps.values()).filter((s) => s.jobId === job.id); } if (include?.events) { (result as never)["events"] = events.filter((e) => e.jobId === job.id); } return Promise.resolve(result); }), findMany: vi.fn().mockImplementation(({ where }) => { const allJobs = Array.from(jobs.values()); if (!where) return Promise.resolve(allJobs); return Promise.resolve( allJobs.filter((job) => { if (where.workspaceId && job.workspaceId !== where.workspaceId) return false; if (where.status && job.status !== where.status) return false; return true; }) ); }), update: vi.fn().mockImplementation(({ where, data }) => { const job = jobs.get(where.id); if (!job) return Promise.resolve(null); const updated = { ...job, ...data }; jobs.set(job.id, updated); return Promise.resolve(updated); }), count: vi.fn().mockImplementation(() => Promise.resolve(jobs.size)), } as never, jobStep: { create: vi.fn().mockImplementation(({ data }) => { const step = createMockJobStep({ id: `step-${Date.now()}`, jobId: data.jobId || data.job?.connect?.id, ordinal: data.ordinal, phase: data.phase, name: data.name, type: data.type, status: data.status, }); steps.set(step.id, step); return Promise.resolve(step); }), findUnique: vi.fn().mockImplementation(({ where }) => { const step = steps.get(where.id); return Promise.resolve(step || null); }), findMany: vi.fn().mockImplementation(({ where }) => { const allSteps = Array.from(steps.values()); if (!where) return Promise.resolve(allSteps); return Promise.resolve(allSteps.filter((step) => step.jobId === where.jobId)); }), update: vi.fn().mockImplementation(({ where, data }) => { const step = steps.get(where.id); if (!step) return Promise.resolve(null); const updated = { ...step, ...data }; steps.set(step.id, updated); return Promise.resolve(updated); }), } as never, jobEvent: { create: vi.fn().mockImplementation(({ data }) => { const event = createMockJobEvent({ id: `event-${Date.now()}`, jobId: data.jobId || data.job?.connect?.id, stepId: data.stepId || data.step?.connect?.id || null, type: data.type, timestamp: data.timestamp || new Date(), actor: data.actor, payload: data.payload, }); events.push(event); return Promise.resolve(event); }), findMany: vi.fn().mockImplementation(({ where, orderBy }) => { let filtered = events; if (where?.jobId) { filtered = filtered.filter((e) => e.jobId === where.jobId); } if (orderBy?.timestamp) { filtered = [...filtered].sort((a, b) => orderBy.timestamp === "asc" ? a.timestamp.getTime() - b.timestamp.getTime() : b.timestamp.getTime() - a.timestamp.getTime() ); } return Promise.resolve(filtered); }), } as never, workspace: { findUnique: vi.fn().mockResolvedValue({ id: "workspace-123", slug: "test-workspace", name: "Test Workspace", }), } as never, }; }