feat(workspace): extract LaneConsolePane from the inline run console
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* @file LaneConsolePane.test.tsx
|
||||
* @description Test suite for the LaneConsolePane component
|
||||
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
|
||||
import { LaneConsolePane } from "../LaneConsolePane";
|
||||
import { api } from "../../../lib/api";
|
||||
import type { Lane } from "../../../lib/types";
|
||||
|
||||
vi.mock("../TerminalView", () => ({
|
||||
TerminalView: ({ runId }: { runId: string }) => (
|
||||
<div data-testid="terminal-view" data-run-id={runId} />
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock("../../../lib/api", () => ({
|
||||
api: {
|
||||
lanes: {
|
||||
ensure: vi.fn(),
|
||||
action: vi.fn(),
|
||||
list: vi.fn(),
|
||||
},
|
||||
run: {
|
||||
list: vi.fn().mockResolvedValue({ items: [] }),
|
||||
history: vi.fn().mockResolvedValue({ items: [] }),
|
||||
get: vi.fn(),
|
||||
start: vi.fn(),
|
||||
},
|
||||
},
|
||||
RUN_MODEL_CHOICES: [],
|
||||
RUN_EFFORT_CHOICES: [],
|
||||
}));
|
||||
|
||||
const LANE: Lane = {
|
||||
id: 1,
|
||||
title: "demo",
|
||||
cwd: "/workspace/a",
|
||||
branch: null,
|
||||
kind: "adopted",
|
||||
source_repo: null,
|
||||
pipeline: "default",
|
||||
session_id: null,
|
||||
run_id: null,
|
||||
stage: "idle",
|
||||
stage_since: null,
|
||||
status: "idle",
|
||||
gate_decision: null,
|
||||
ci_status: null,
|
||||
needs_action: null,
|
||||
links: {},
|
||||
stages: {},
|
||||
notes: null,
|
||||
pipeline_name: "Default",
|
||||
pipeline_nodes: [],
|
||||
progress: 0,
|
||||
stage_seconds: null,
|
||||
last_event_seconds: null,
|
||||
liveness: "idle" as Lane["liveness"],
|
||||
detected_stage: null,
|
||||
detected_signal: null,
|
||||
slot: null,
|
||||
ports: {},
|
||||
active_feature_id: null,
|
||||
};
|
||||
|
||||
function baseProps() {
|
||||
return {
|
||||
lanes: [LANE],
|
||||
laneId: 1,
|
||||
showLaneSelector: false,
|
||||
onLaneIdChange: vi.fn(),
|
||||
onLaneCreated: vi.fn(),
|
||||
binaryStatus: { found: true, path: "/usr/local/bin/claude" },
|
||||
cwdSuggestions: [],
|
||||
activeRuns: { items: [] },
|
||||
wsConnected: true,
|
||||
};
|
||||
}
|
||||
|
||||
describe("LaneConsolePane", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("starts a run through /api/lanes/<id>/start, not /api/run/start", async () => {
|
||||
(api.lanes.action as ReturnType<typeof vi.fn>).mockResolvedValue({
|
||||
lane: { ...LANE, run_id: "run-1" },
|
||||
});
|
||||
(api.run.get as ReturnType<typeof vi.fn>).mockResolvedValue({
|
||||
id: "run-1",
|
||||
laneId: 1,
|
||||
status: "running",
|
||||
cwd: "/workspace/a",
|
||||
model: null,
|
||||
permissionMode: null,
|
||||
effort: null,
|
||||
resumeSessionId: null,
|
||||
sessionId: null,
|
||||
startedAt: null,
|
||||
promptPreview: null,
|
||||
});
|
||||
|
||||
render(<LaneConsolePane {...baseProps()} />);
|
||||
|
||||
// Set cwd and prompt
|
||||
const cwdInput = screen.getByPlaceholderText(/type to search/i);
|
||||
fireEvent.change(cwdInput, { target: { value: "/workspace/a" } });
|
||||
|
||||
const promptTextarea = screen.getByPlaceholderText(/ask claude/i);
|
||||
fireEvent.change(promptTextarea, { target: { value: "test prompt" } });
|
||||
|
||||
// Find and click the Run button (the main start button in RunSetup)
|
||||
fireEvent.click(screen.getByRole("button", { name: /^run$/i }));
|
||||
|
||||
await waitFor(() =>
|
||||
expect(api.lanes.action).toHaveBeenCalledWith(1, "start", expect.any(Object))
|
||||
);
|
||||
expect(api.run.start).not.toHaveBeenCalled();
|
||||
await waitFor(() =>
|
||||
expect(screen.getByTestId("terminal-view")).toHaveAttribute("data-run-id", "run-1")
|
||||
);
|
||||
});
|
||||
|
||||
it("shows a lane dropdown only when showLaneSelector is true", () => {
|
||||
const { rerender } = render(<LaneConsolePane {...baseProps()} showLaneSelector />);
|
||||
expect(screen.getByTestId("pane-lane-select")).toBeInTheDocument();
|
||||
|
||||
rerender(<LaneConsolePane {...baseProps()} showLaneSelector={false} />);
|
||||
expect(screen.queryByTestId("pane-lane-select")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders an empty placeholder with just a picker when laneId is null", () => {
|
||||
render(<LaneConsolePane {...baseProps()} laneId={null} showLaneSelector />);
|
||||
expect(screen.getByTestId("pane-empty")).toBeInTheDocument();
|
||||
expect(screen.getByTestId("pane-lane-select")).toBeInTheDocument();
|
||||
expect(screen.queryByTestId("console-body")).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user