Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 0 additions & 105 deletions lib/tasks/__tests__/enrichTaskWithTriggerInfo.test.ts

This file was deleted.

130 changes: 130 additions & 0 deletions lib/tasks/__tests__/enrichTasks.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import { enrichTasks } from "../enrichTasks";

vi.mock("@/lib/trigger/fetchTriggerRuns", () => ({
fetchTriggerRuns: vi.fn(),
}));

vi.mock("@/lib/trigger/retrieveTaskRun", () => ({
retrieveTaskRun: vi.fn(),
}));

vi.mock("@/lib/supabase/account_emails/selectAccountEmails", () => ({
default: vi.fn(),
}));

import { fetchTriggerRuns } from "@/lib/trigger/fetchTriggerRuns";
import { retrieveTaskRun } from "@/lib/trigger/retrieveTaskRun";
import selectAccountEmails from "@/lib/supabase/account_emails/selectAccountEmails";

const mockTask = {
id: "task-123",
title: "Test Task",
prompt: "Do something",
schedule: "0 9 * * *",
account_id: "account-456",
artist_account_id: "artist-789",
trigger_schedule_id: "sched_abc",
enabled: true,
created_at: "2026-01-01T00:00:00Z",
next_run: null,
last_run: null,
model: null,
updated_at: null,
} as Parameters<typeof enrichTasks>[0][number];

const mockRun = {
id: "run_xyz",
status: "COMPLETED",
createdAt: "2026-03-20T09:00:00.000Z",
startedAt: "2026-03-20T09:00:01.000Z",
finishedAt: "2026-03-20T09:01:00.000Z",
durationMs: 59000,
};

describe("enrichTasks", () => {
beforeEach(() => {
vi.clearAllMocks();
});

it("returns recent_runs, upcoming, and owner_email", async () => {
vi.mocked(fetchTriggerRuns).mockResolvedValue([mockRun] as never);
vi.mocked(retrieveTaskRun).mockResolvedValue({
...mockRun,
payload: {
upcoming: ["2026-03-27T09:00:00Z", "2026-04-03T09:00:00Z"],
},
} as never);
vi.mocked(selectAccountEmails).mockResolvedValue([
{
id: "email-1",
account_id: "account-456",
email: "owner@example.com",
updated_at: "2026-01-01T00:00:00Z",
},
]);

const result = await enrichTasks([mockTask]);

expect(result).toEqual([
{
...mockTask,
recent_runs: [mockRun],
upcoming: ["2026-03-27T09:00:00Z", "2026-04-03T09:00:00Z"],
owner_email: "owner@example.com",
},
]);
expect(fetchTriggerRuns).toHaveBeenCalledWith({ "filter[schedule]": "sched_abc" }, 5);
expect(selectAccountEmails).toHaveBeenCalledWith({ accountIds: ["account-456"] });
});

it("returns empty trigger fields and null owner_email when no schedule or email exists", async () => {
vi.mocked(selectAccountEmails).mockResolvedValue([]);

const result = await enrichTasks([{ ...mockTask, trigger_schedule_id: null }]);

expect(result).toEqual([
{
...mockTask,
trigger_schedule_id: null,
recent_runs: [],
upcoming: [],
owner_email: null,
},
]);
expect(fetchTriggerRuns).not.toHaveBeenCalled();
});

it("returns empty trigger enrichment when Trigger.dev fails", async () => {
vi.mocked(fetchTriggerRuns).mockRejectedValue(new Error("API error"));
vi.mocked(selectAccountEmails).mockResolvedValue([]);

const result = await enrichTasks([mockTask]);

expect(result).toEqual([
{
...mockTask,
recent_runs: [],
upcoming: [],
owner_email: null,
},
]);
});

it("returns empty upcoming when no runs exist", async () => {
vi.mocked(fetchTriggerRuns).mockResolvedValue([] as never);
vi.mocked(selectAccountEmails).mockResolvedValue([]);

const result = await enrichTasks([mockTask]);

expect(result).toEqual([
{
...mockTask,
recent_runs: [],
upcoming: [],
owner_email: null,
},
]);
expect(retrieveTaskRun).not.toHaveBeenCalled();
});
});
124 changes: 124 additions & 0 deletions lib/tasks/__tests__/getTasksHandler.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Custom agent: Enforce Clear Code Style and Maintainability Practices

This test file is 124 lines, exceeding the 100-line limit. The task fixture objects are defined inline three times (raw tasks, mock return, assertion). Extract shared test fixtures into a helper (e.g., makeTask() factory) to eliminate the repetition and bring the file under 100 lines.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/tasks/__tests__/getTasksHandler.test.ts, line 1:

<comment>This test file is 124 lines, exceeding the 100-line limit. The task fixture objects are defined inline three times (raw tasks, mock return, assertion). Extract shared test fixtures into a helper (e.g., `makeTask()` factory) to eliminate the repetition and bring the file under 100 lines.</comment>

<file context>
@@ -0,0 +1,124 @@
+import { describe, it, expect, vi, beforeEach } from "vitest";
+import { NextRequest, NextResponse } from "next/server";
+import { getTasksHandler } from "@/lib/tasks/getTasksHandler";
</file context>
Fix with Cubic

import { NextRequest, NextResponse } from "next/server";
import { getTasksHandler } from "@/lib/tasks/getTasksHandler";
import { validateGetTasksQuery } from "@/lib/tasks/validateGetTasksQuery";
import { selectScheduledActions } from "@/lib/supabase/scheduled_actions/selectScheduledActions";
import { enrichTasks } from "@/lib/tasks/enrichTasks";

vi.mock("@/lib/networking/getCorsHeaders", () => ({
getCorsHeaders: vi.fn(() => ({ "Access-Control-Allow-Origin": "*" })),
}));

vi.mock("@/lib/tasks/validateGetTasksQuery", () => ({
validateGetTasksQuery: vi.fn(),
}));

vi.mock("@/lib/supabase/scheduled_actions/selectScheduledActions", () => ({
selectScheduledActions: vi.fn(),
}));

vi.mock("@/lib/tasks/enrichTasks", () => ({
enrichTasks: vi.fn(),
}));

describe("getTasksHandler", () => {
beforeEach(() => {
vi.clearAllMocks();
});

it("returns enriched tasks with owner_email", async () => {
const validatedQuery = {
account_id: "owner-1",
artist_account_id: "artist-1",
};

const tasks = [
{
id: "task-1",
account_id: "owner-1",
artist_account_id: "artist-1",
created_at: null,
enabled: true,
last_run: null,
model: null,
next_run: null,
prompt: "prompt 1",
schedule: "0 9 * * *",
title: "Task One",
trigger_schedule_id: null,
updated_at: null,
},
{
id: "task-2",
account_id: "owner-2",
artist_account_id: "artist-1",
created_at: null,
enabled: true,
last_run: null,
model: null,
next_run: null,
prompt: "prompt 2",
schedule: "0 10 * * *",
title: "Task Two",
trigger_schedule_id: null,
updated_at: null,
},
];

vi.mocked(validateGetTasksQuery).mockResolvedValue(validatedQuery);
vi.mocked(selectScheduledActions).mockResolvedValue(tasks);
vi.mocked(enrichTasks).mockResolvedValue([
{
...tasks[0],
recent_runs: [],
upcoming: [],
owner_email: "owner1@example.com",
},
{
...tasks[1],
recent_runs: [],
upcoming: [],
owner_email: null,
},
]);

const request = new NextRequest("http://localhost:3000/api/tasks");
const response = await getTasksHandler(request);
const body = await response.json();

expect(response.status).toBe(200);
expect(enrichTasks).toHaveBeenCalledWith(tasks);
expect(body).toEqual({
status: "success",
tasks: [
{
...tasks[0],
recent_runs: [],
upcoming: [],
owner_email: "owner1@example.com",
},
{
...tasks[1],
recent_runs: [],
upcoming: [],
owner_email: null,
},
],
});
});

it("returns validator errors directly", async () => {
const errorResponse = NextResponse.json(
{ status: "error", error: "Unauthorized" },
{ status: 401 },
);
vi.mocked(validateGetTasksQuery).mockResolvedValue(errorResponse);

const request = new NextRequest("http://localhost:3000/api/tasks");
const response = await getTasksHandler(request);

expect(response).toBe(errorResponse);
expect(selectScheduledActions).not.toHaveBeenCalled();
expect(enrichTasks).not.toHaveBeenCalled();
});
});
Loading
Loading