- Create comprehensive E2E test suite for job orchestration - Add test fixtures for Discord, BullMQ, and Prisma mocks - Implement 9 end-to-end test scenarios covering: * Happy path: webhook → job → step execution → completion * Event emission throughout job lifecycle * Step failure and retry handling * Job failure after max retries * Discord command parsing and job creation * WebSocket status updates integration * Job cancellation workflow * Job retry mechanism * Progress percentage tracking - Add helper methods to services for simplified testing: * JobStepsService: start(), complete(), fail(), findByJob() * RunnerJobsService: updateStatus(), updateProgress() * JobEventsService: findByJob() - Configure vitest.e2e.config.ts for E2E test execution - All 9 E2E tests passing - All 1405 unit tests passing - Quality gates: typecheck, lint, build all passing Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
84 lines
2.3 KiB
TypeScript
84 lines
2.3 KiB
TypeScript
import { vi } from "vitest";
|
|
import type { Queue, Job } from "bullmq";
|
|
|
|
/**
|
|
* Mock BullMQ job for testing
|
|
*/
|
|
export function createMockBullMqJob(overrides?: Partial<Job>): Partial<Job> {
|
|
return {
|
|
id: "mock-bull-job-id",
|
|
name: "runner-job",
|
|
data: {
|
|
jobId: "mock-job-id",
|
|
workspaceId: "mock-workspace-id",
|
|
type: "code-task",
|
|
},
|
|
progress: vi.fn().mockReturnValue(0),
|
|
updateProgress: vi.fn().mockResolvedValue(undefined),
|
|
log: vi.fn().mockResolvedValue(undefined),
|
|
remove: vi.fn().mockResolvedValue(undefined),
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Mock BullMQ queue for testing
|
|
*/
|
|
export function createMockBullMqQueue(): Partial<Queue> {
|
|
const jobs = new Map<string, Partial<Job>>();
|
|
|
|
return {
|
|
add: vi.fn().mockImplementation((name: string, data: unknown) => {
|
|
const job = createMockBullMqJob({
|
|
id: `job-${Date.now()}`,
|
|
name,
|
|
data: data as never,
|
|
});
|
|
jobs.set(job.id as string, job);
|
|
return Promise.resolve(job);
|
|
}),
|
|
getJob: vi.fn().mockImplementation((jobId: string) => {
|
|
return Promise.resolve(jobs.get(jobId) || null);
|
|
}),
|
|
getJobs: vi.fn().mockResolvedValue([]),
|
|
pause: vi.fn().mockResolvedValue(undefined),
|
|
resume: vi.fn().mockResolvedValue(undefined),
|
|
clean: vi.fn().mockResolvedValue([]),
|
|
close: vi.fn().mockResolvedValue(undefined),
|
|
on: vi.fn(),
|
|
once: vi.fn(),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Mock BullMQ service for testing
|
|
*/
|
|
export function createMockBullMqService() {
|
|
const queues = new Map<string, Partial<Queue>>();
|
|
|
|
return {
|
|
addJob: vi
|
|
.fn()
|
|
.mockImplementation((queueName: string, jobName: string, data: unknown, opts?: unknown) => {
|
|
let queue = queues.get(queueName);
|
|
if (!queue) {
|
|
queue = createMockBullMqQueue();
|
|
queues.set(queueName, queue);
|
|
}
|
|
return queue.add?.(jobName, data, opts as never);
|
|
}),
|
|
getQueue: vi.fn().mockImplementation((queueName: string) => {
|
|
let queue = queues.get(queueName);
|
|
if (!queue) {
|
|
queue = createMockBullMqQueue();
|
|
queues.set(queueName, queue);
|
|
}
|
|
return queue;
|
|
}),
|
|
getJob: vi.fn().mockImplementation((queueName: string, jobId: string) => {
|
|
const queue = queues.get(queueName);
|
|
return queue?.getJob?.(jobId);
|
|
}),
|
|
};
|
|
}
|