50eb76a10d
- Add shared task_runner.run_saved_task helper used by routers/tasks.py and widgets/sources.py SshTaskWidgetSource. - Saved tasks now target ssh_tasks service instances via default_service_id; the legacy default_machine_id and saved_task_runs are removed. - Actions page lists ssh_tasks services for default and run-time selection. - Update types, API client, hooks, tests, docs, and changelog. Backend tests: 222 passed. Frontend lint/build/test: clean (71 passed).
126 lines
3.7 KiB
TypeScript
126 lines
3.7 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
import { render, screen } from "@testing-library/react";
|
|
import userEvent from "@testing-library/user-event";
|
|
import { Actions } from "../Actions";
|
|
import type { SavedTask, ServiceInstance } from "../../types";
|
|
|
|
const saveTaskMutate = vi.fn().mockResolvedValue({
|
|
id: "t1",
|
|
name: "Restart svc",
|
|
task_type: "shell",
|
|
content: "",
|
|
enabled: true,
|
|
default_service_id: "",
|
|
notes: "",
|
|
});
|
|
const deleteTaskMutate = vi.fn();
|
|
const runTaskMutate = vi.fn().mockResolvedValue({});
|
|
|
|
let sshServices: ServiceInstance[] = [];
|
|
let tasks: SavedTask[] = [];
|
|
|
|
vi.mock("../../hooks/useSettings", () => ({
|
|
useTasks: () => ({ data: tasks }),
|
|
useSaveTask: () => ({ mutateAsync: saveTaskMutate, isPending: false }),
|
|
useDeleteTask: () => ({ mutate: deleteTaskMutate }),
|
|
useRunTask: () => ({ mutateAsync: runTaskMutate, isPending: false }),
|
|
useTaskRuns: () => ({ data: { items: [] } }),
|
|
}));
|
|
|
|
vi.mock("../../hooks/useServices", () => ({
|
|
useServiceInstances: () => ({ data: sshServices }),
|
|
}));
|
|
|
|
function sshService(overrides: Partial<ServiceInstance> = {}): ServiceInstance {
|
|
return {
|
|
id: "s1",
|
|
service_type: "ssh_tasks",
|
|
name: "Box",
|
|
config: { host: "box", username: "u" },
|
|
secrets_set: {},
|
|
enabled: true,
|
|
created_at: 0,
|
|
updated_at: 0,
|
|
...overrides,
|
|
} as ServiceInstance;
|
|
}
|
|
|
|
function task(overrides: Partial<SavedTask> = {}): SavedTask {
|
|
return {
|
|
id: "t1",
|
|
name: "Restart svc",
|
|
task_type: "shell",
|
|
content: "systemctl restart foo",
|
|
enabled: true,
|
|
default_service_id: "",
|
|
notes: "",
|
|
created_at: 0,
|
|
updated_at: 0,
|
|
...overrides,
|
|
} as SavedTask;
|
|
}
|
|
|
|
beforeEach(() => {
|
|
saveTaskMutate.mockClear();
|
|
deleteTaskMutate.mockClear();
|
|
runTaskMutate.mockClear();
|
|
sshServices = [];
|
|
tasks = [];
|
|
});
|
|
|
|
describe("Actions", () => {
|
|
it("shows the empty state and creates a task via the editor dialog", async () => {
|
|
render(<Actions />);
|
|
|
|
expect(screen.getByText("No action selected")).toBeInTheDocument();
|
|
expect(
|
|
screen.getByRole("button", { name: "Add action" }),
|
|
).toBeInTheDocument();
|
|
|
|
await userEvent.click(screen.getByRole("button", { name: "Add action" }));
|
|
// Editor dialog opened (Name field is unique to the editor).
|
|
expect(screen.getByLabelText("Name")).toBeInTheDocument();
|
|
|
|
// Controlled input parity: name + default shell type flow through.
|
|
await userEvent.type(screen.getByLabelText("Name"), "Restart svc");
|
|
await userEvent.click(screen.getByRole("button", { name: "Save action" }));
|
|
|
|
expect(saveTaskMutate).toHaveBeenCalledTimes(1);
|
|
const saved = saveTaskMutate.mock.calls[0][0];
|
|
expect(saved.name).toBe("Restart svc");
|
|
expect(saved.task_type).toBe("shell");
|
|
expect(saved.default_service_id).toBe("");
|
|
});
|
|
|
|
it("disables the Run button until a run service is selected", async () => {
|
|
sshServices = [sshService()];
|
|
tasks = [task()];
|
|
render(<Actions />);
|
|
|
|
// Selecting a saved task tab exposes the detail + Run control.
|
|
await userEvent.click(screen.getByRole("tab", { name: "Restart svc" }));
|
|
|
|
const runButton = screen.getByRole("button", { name: "Run action" });
|
|
expect(runButton).toBeDisabled();
|
|
});
|
|
|
|
it("runs a task on the selected SSH task service", async () => {
|
|
sshServices = [sshService()];
|
|
tasks = [task()];
|
|
render(<Actions />);
|
|
|
|
await userEvent.click(screen.getByRole("tab", { name: "Restart svc" }));
|
|
await userEvent.click(
|
|
screen.getByRole("combobox", { name: "Run on SSH task service" }),
|
|
);
|
|
await userEvent.click(screen.getByRole("option", { name: "Box" }));
|
|
await userEvent.click(screen.getByRole("button", { name: "Run action" }));
|
|
|
|
expect(runTaskMutate).toHaveBeenCalledTimes(1);
|
|
expect(runTaskMutate).toHaveBeenCalledWith({
|
|
taskId: "t1",
|
|
serviceId: "s1",
|
|
});
|
|
});
|
|
});
|