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";
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