Files
kandev/apps/web/hooks/domains/session/use-task-executor-profile.test.ts
T

158 lines
4.0 KiB
TypeScript

import { act, renderHook, waitFor } from "@testing-library/react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { Executor } from "@/lib/types/http";
import { useTaskExecutorProfile } from "./use-task-executor-profile";
const mockFetchTaskEnvironment = vi.fn();
const EXECUTOR_ID = "executor-1";
const EXECUTOR_NAME = "Local Exec";
const PROFILE_ID = "profile-1";
const PROFILE_NAME = "Profile 1";
const TASK_ID = "task-1";
const TASK_ENV_ID = "env-1";
const REPO_ID = "repo-1";
const AGENT_EXEC_ID = "agent-exec-1";
const CONTROL_PORT = 8080;
const TIMESTAMP = "2026-01-01T00:00:00Z";
const PROFILE_TEMPLATE = {
id: PROFILE_ID,
executor_id: EXECUTOR_ID,
name: PROFILE_NAME,
prepare_script: "",
cleanup_script: "",
created_at: TIMESTAMP,
updated_at: TIMESTAMP,
};
const EXECUTOR_TEMPLATE = {
id: EXECUTOR_ID,
name: EXECUTOR_NAME,
type: "local_pc",
status: "idle",
is_system: false,
profiles: [
{
...PROFILE_TEMPLATE,
executor_type: "local_pc",
executor_name: EXECUTOR_NAME,
},
],
created_at: TIMESTAMP,
updated_at: TIMESTAMP,
} satisfies Executor;
let mockExecutors: Executor[] = [
{
...EXECUTOR_TEMPLATE,
},
];
const BASE_ENV = {
id: TASK_ENV_ID,
task_id: TASK_ID,
repository_id: REPO_ID,
executor_type: "local_pc",
executor_id: EXECUTOR_ID,
executor_profile_id: PROFILE_ID,
agent_execution_id: AGENT_EXEC_ID,
control_port: CONTROL_PORT,
status: "ready",
created_at: TIMESTAMP,
updated_at: TIMESTAMP,
};
vi.mock("@/components/state-provider", () => ({
useAppStore: (selector: (state: { executors: { items: Executor[] } }) => unknown) =>
selector({
executors: { items: mockExecutors },
}),
}));
vi.mock("@/lib/api/domains/task-environment-api", () => ({
fetchTaskEnvironment: (...args: Parameters<typeof mockFetchTaskEnvironment>) =>
mockFetchTaskEnvironment(...args),
}));
describe("useTaskExecutorProfile", () => {
beforeEach(() => {
vi.clearAllMocks();
mockFetchTaskEnvironment.mockReset();
mockFetchTaskEnvironment.mockResolvedValue(BASE_ENV);
mockExecutors = [
{
...EXECUTOR_TEMPLATE,
},
];
});
it("resolves matching executor profile and fills fallback executor metadata", async () => {
const { result } = renderHook(() => useTaskExecutorProfile(TASK_ID));
await waitFor(() => {
expect(mockFetchTaskEnvironment).toHaveBeenCalledWith(TASK_ID);
});
await act(async () => {
await Promise.resolve();
});
expect(result.current).toMatchObject({
id: PROFILE_ID,
name: PROFILE_NAME,
executor_type: "local_pc",
executor_name: EXECUTOR_NAME,
});
});
it("returns null when environment profile cannot be found", async () => {
mockFetchTaskEnvironment.mockResolvedValue({
...BASE_ENV,
executor_profile_id: "missing-profile",
});
const { result } = renderHook(() => useTaskExecutorProfile(TASK_ID));
await act(async () => {
await Promise.resolve();
});
await waitFor(() => {
expect(result.current).toBeNull();
});
});
it("returns null when disabled", async () => {
const { result } = renderHook(() => useTaskExecutorProfile(TASK_ID, false));
expect(mockFetchTaskEnvironment).not.toHaveBeenCalled();
expect(result.current).toBeNull();
});
it("returns null when task ID is missing", async () => {
const { result } = renderHook(() => useTaskExecutorProfile(""));
expect(mockFetchTaskEnvironment).not.toHaveBeenCalled();
expect(result.current).toBeNull();
});
it("does not re-fetch when only unrelated executor metadata changes", async () => {
const { rerender } = renderHook(() => useTaskExecutorProfile(TASK_ID));
await waitFor(() => {
expect(mockFetchTaskEnvironment).toHaveBeenCalledTimes(1);
});
mockExecutors = [
{
...mockExecutors[0],
status: "running",
},
];
rerender();
await act(async () => {
await Promise.resolve();
});
expect(mockFetchTaskEnvironment).toHaveBeenCalledTimes(1);
});
});