f8dd01b5a9
The READY badge next to the executor name already conveys ready-state; the dedicated "Environment ready · 12s" row above the executor info just added vertical noise. Skip rendering for the ready phase (other phases that surface non-redundant info — preparing, resuming, failed — still render). Drop top padding on the executor info section now that nothing sits above it on the happy path.
163 lines
5.9 KiB
TypeScript
163 lines
5.9 KiB
TypeScript
import { cleanup, render, screen } from "@testing-library/react";
|
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import type { SessionPrepareState } from "@/lib/state/slices/session-runtime/types";
|
|
|
|
let mockPrepareState: SessionPrepareState | null = null;
|
|
let mockSessionState: string | null = null;
|
|
let mockEnv: { executor_type: string; sandbox_id?: string; container_id?: string } | null = null;
|
|
|
|
vi.mock("@/components/state-provider", () => ({
|
|
useAppStore: (selector: (state: Record<string, unknown>) => unknown) =>
|
|
selector({
|
|
prepareProgress: {
|
|
bySessionId: mockPrepareState ? { [mockPrepareState.sessionId]: mockPrepareState } : {},
|
|
},
|
|
taskSessions: {
|
|
items: mockSessionState
|
|
? { [SESSION_ID]: { id: SESSION_ID, state: mockSessionState } }
|
|
: {},
|
|
},
|
|
}),
|
|
}));
|
|
|
|
vi.mock("@/lib/api/domains/task-environment-api", () => ({
|
|
fetchTaskEnvironmentLive: vi.fn().mockImplementation(async () => ({
|
|
environment: mockEnv ?? { executor_type: "" },
|
|
container: null,
|
|
})),
|
|
resetTaskEnvironment: vi.fn().mockResolvedValue({ success: true }),
|
|
}));
|
|
|
|
vi.mock("./task-reset-env-confirm-dialog", () => ({
|
|
TaskResetEnvConfirmDialog: () => null,
|
|
}));
|
|
|
|
import { ExecutorSettingsButton } from "./executor-settings-button";
|
|
|
|
const SESSION_ID = "session-1";
|
|
const TASK_ID = "task-1";
|
|
const STEP_CREATE_SANDBOX = "Creating cloud sandbox";
|
|
const PREPARE_STATUS_TESTID = "executor-prepare-status";
|
|
const SETTINGS_BUTTON_TESTID = "executor-settings-button";
|
|
|
|
describe("ExecutorSettingsButton", () => {
|
|
afterEach(() => {
|
|
cleanup();
|
|
mockPrepareState = null;
|
|
mockSessionState = null;
|
|
mockEnv = null;
|
|
});
|
|
|
|
it("shows the cloud icon when the executor type is sprites", async () => {
|
|
mockEnv = { executor_type: "sprites", sandbox_id: "kandev-abc" };
|
|
|
|
render(<ExecutorSettingsButton taskId={TASK_ID} sessionId={SESSION_ID} />);
|
|
|
|
// Wait a tick for the live fetch to resolve.
|
|
await Promise.resolve();
|
|
await Promise.resolve();
|
|
expect(await screen.findByTestId("executor-status-cloud-icon")).toBeTruthy();
|
|
});
|
|
|
|
it("shows the container icon for both docker variants", async () => {
|
|
mockEnv = { executor_type: "local_docker", container_id: "abcdef" };
|
|
|
|
render(<ExecutorSettingsButton taskId={TASK_ID} sessionId={SESSION_ID} />);
|
|
|
|
await Promise.resolve();
|
|
expect(await screen.findByTestId("executor-status-container-icon")).toBeTruthy();
|
|
});
|
|
|
|
it("swaps to a spinner while the prepare progress is preparing", async () => {
|
|
mockEnv = { executor_type: "sprites", sandbox_id: "kandev-abc" };
|
|
mockPrepareState = {
|
|
sessionId: SESSION_ID,
|
|
status: "preparing",
|
|
steps: [{ name: STEP_CREATE_SANDBOX, status: "running" }],
|
|
};
|
|
|
|
render(<ExecutorSettingsButton taskId={TASK_ID} sessionId={SESSION_ID} />);
|
|
|
|
expect(screen.getByTestId("executor-settings-button-spinner")).toBeTruthy();
|
|
expect(screen.queryByTestId("executor-status-cloud-icon")).toBeNull();
|
|
});
|
|
|
|
it("renders the preparing section with current step copy", async () => {
|
|
mockPrepareState = {
|
|
sessionId: SESSION_ID,
|
|
status: "preparing",
|
|
steps: [
|
|
{ name: STEP_CREATE_SANDBOX, status: "completed" },
|
|
{ name: "Uploading agent controller", status: "running" },
|
|
{ name: "Waiting for agent controller", status: "pending" },
|
|
],
|
|
};
|
|
|
|
render(<ExecutorSettingsButton taskId={TASK_ID} sessionId={SESSION_ID} />);
|
|
|
|
// Open the popover by clicking the trigger.
|
|
const trigger = screen.getByTestId(SETTINGS_BUTTON_TESTID);
|
|
trigger.click();
|
|
|
|
expect(await screen.findByTestId(PREPARE_STATUS_TESTID)).toHaveProperty(
|
|
"dataset.phase",
|
|
"preparing",
|
|
);
|
|
expect(screen.getByText(/Step 2 of 3: Uploading agent controller/)).toBeTruthy();
|
|
});
|
|
|
|
it("renders the fallback warning callout when the missing-sandbox notice is present", async () => {
|
|
mockPrepareState = {
|
|
sessionId: SESSION_ID,
|
|
status: "preparing",
|
|
steps: [
|
|
{
|
|
name: "Reconnecting cloud sandbox",
|
|
status: "skipped",
|
|
warning:
|
|
"Previous sandbox is no longer available — provisioning a fresh one for this branch.",
|
|
},
|
|
{ name: STEP_CREATE_SANDBOX, status: "running" },
|
|
],
|
|
};
|
|
|
|
render(<ExecutorSettingsButton taskId={TASK_ID} sessionId={SESSION_ID} />);
|
|
screen.getByTestId(SETTINGS_BUTTON_TESTID).click();
|
|
|
|
const status = await screen.findByTestId(PREPARE_STATUS_TESTID);
|
|
expect(status.dataset.phase).toBe("preparing_fallback");
|
|
expect(screen.getByTestId("executor-prepare-fallback-warning")).toBeTruthy();
|
|
});
|
|
|
|
it("renders the Resuming session row when session is STARTING with no prepare events", async () => {
|
|
mockSessionState = "STARTING";
|
|
|
|
render(<ExecutorSettingsButton taskId={TASK_ID} sessionId={SESSION_ID} />);
|
|
|
|
expect(screen.getByTestId("executor-settings-button-spinner")).toBeTruthy();
|
|
screen.getByTestId(SETTINGS_BUTTON_TESTID).click();
|
|
|
|
const status = await screen.findByTestId(PREPARE_STATUS_TESTID);
|
|
expect(status.dataset.phase).toBe("resuming");
|
|
expect(screen.getByText("Resuming session")).toBeTruthy();
|
|
expect(screen.getByText(/Reconnecting to the existing environment/)).toBeTruthy();
|
|
});
|
|
|
|
it("hides the prepare-status section once preparation completes", async () => {
|
|
// The READY badge next to the executor name conveys ready-state; the
|
|
// dedicated "Environment ready · 12s" row is redundant noise.
|
|
mockPrepareState = {
|
|
sessionId: SESSION_ID,
|
|
status: "completed",
|
|
steps: [{ name: "Creating cloud sandbox", status: "completed" }],
|
|
durationMs: 12500,
|
|
};
|
|
|
|
render(<ExecutorSettingsButton taskId={TASK_ID} sessionId={SESSION_ID} />);
|
|
screen.getByTestId(SETTINGS_BUTTON_TESTID).click();
|
|
|
|
expect(screen.queryByTestId(PREPARE_STATUS_TESTID)).toBeNull();
|
|
expect(screen.queryByText(/Environment ready/)).toBeNull();
|
|
});
|
|
});
|