Files
fusion/packages/dashboard/app/components/__tests__/AgentPromptsManager.test.tsx
gsxdsm c3d1716fdd refactor(dashboard): split monolithic styles.css into per-component files
Split app/styles.css from ~40k lines down to ~4.5k. Created 56 co-located
component CSS files in app/components/, each imported by its owning .tsx.
The remainder of styles.css holds genuinely global rules (design tokens,
.btn/.card/.modal/.form-input primitives, cross-component @media overrides).

- Lazy-load 13 heavy views (AgentsView, RoadmapsView, NodesView, etc.) via
  React.lazy + Suspense; prefetch all chunks on idle so first navigation is
  instant. Initial JS bundle: 1.58 MB → 1.16 MB (-26%). Initial CSS bundle:
  635 kB → 471 kB (-26%); the rest splits into 13 per-view chunks.

- Add app/test/cssFixture.ts exposing loadAllAppCss() + loadAllAppCssBaseOnly()
  so CSS regression tests load the full per-component bundle (mirroring Vite
  source order). Migrate 30+ tests off direct readFileSync('../styles.css').

- Enable test.css: { include: [/.+/] } in vitest.config.ts so component CSS
  imports actually inject styles in jsdom (fixes getComputedStyle assertions).

- Add ESLint rule (no-restricted-syntax) banning direct styles.css reads in
  dashboard test files; points at loadAllAppCss() instead.

- Restore lost utility classes (.text-muted, .text-secondary, .text-dim,
  .form-input) and rescue dropped chat tool-call rules into QuickChatFAB.css.

- Mobile fixes along the way: scroll containment for view containers
  (min-height:0 + -webkit-overflow-scrolling), QuickChatFAB full-screen on
  mobile (with safe-area-inset for iOS home bar), AgentsView single-row
  header layout, ActivityLogModal close button on right, model-combobox
  z-index above the mobile quick-chat panel.

- Bug fix: SkillsView toggle was display:none which hid the input from the
  accessibility tree; replaced with the visually-hidden pattern so screen
  readers + getByRole still find the checkbox.

- Bug fix: standalone Delete button in TaskDetailModal for triage-column
  tasks (Actions dropdown is hidden in triage state, so previously no way
  to delete a freshly-created task without status change first).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 19:39:20 -07:00

1192 lines
40 KiB
TypeScript

import { readFileSync } from "node:fs";
import { loadAllAppCss } from "../../test/cssFixture";
import { resolve } from "node:path";
import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { AgentPromptsManager } from "../AgentPromptsManager";
import { BUILTIN_AGENT_PROMPTS } from "../../utils/builtinPrompts";
import type { AgentPromptsConfig } from "@fusion/core";
// Mock the builtinPrompts utility to avoid importing the large prompt texts
vi.mock("../../utils/builtinPrompts", () => ({
BUILTIN_AGENT_PROMPTS: [
{
id: "default-executor",
name: "Default Executor",
description: "Standard task execution agent with full tooling.",
role: "executor",
prompt: "You are a task execution agent responsible for implementing scoped tasks with precision. Always read PROMPT.md, run tests, keep git history clean, and verify lint, tests, and build pass before calling task_done.",
builtIn: true,
},
{
id: "default-triage",
name: "Default Triage",
description: "Standard task specification agent.",
role: "triage",
prompt: "You are a task specification agent...",
builtIn: true,
},
{
id: "default-reviewer",
name: "Default Reviewer",
description: "Standard independent code and plan reviewer.",
role: "reviewer",
prompt: "You are an independent code and plan reviewer.",
builtIn: true,
},
{
id: "default-merger",
name: "Default Merger",
description: "Standard merge agent for squash merges.",
role: "merger",
prompt: "You are a merge agent.",
builtIn: true,
},
],
PROMPT_KEY_CATALOG: {
"executor-welcome": {
key: "executor-welcome",
name: "Executor Welcome",
roles: ["executor"],
description: "Introductory section for the executor",
defaultContent: "You are a task execution agent...",
},
"triage-welcome": {
key: "triage-welcome",
name: "Triage Welcome",
roles: ["triage"],
description: "Introductory section for triage",
defaultContent: "You are a task specification agent...",
},
},
}));
const defaultConfig: AgentPromptsConfig = {};
const onChange = vi.fn();
const onPromptOverridesChange = vi.fn();
const stylesContent = loadAllAppCss();
const testStylesId = "agent-prompts-manager-test-styles";
beforeEach(() => {
vi.clearAllMocks();
if (!document.getElementById(testStylesId)) {
const styleElement = document.createElement("style");
styleElement.id = testStylesId;
styleElement.textContent = stylesContent;
document.head.appendChild(styleElement);
}
});
describe("AgentPromptsManager", () => {
describe("Tab Navigation", () => {
it("renders all three tabs", () => {
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
expect(screen.getByTestId("tab-templates")).toBeTruthy();
expect(screen.getByTestId("tab-assignments")).toBeTruthy();
expect(screen.getByTestId("tab-overrides")).toBeTruthy();
});
it("Templates tab is active by default", () => {
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
expect(screen.getByTestId("tab-templates")).toHaveClass(/active/);
});
it("clicking a tab switches active state", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Click Assignments tab
await user.click(screen.getByTestId("tab-assignments"));
expect(screen.getByTestId("tab-assignments")).toHaveClass(/active/);
expect(screen.getByTestId("tab-templates")).not.toHaveClass(/active/);
// Click Overrides tab
await user.click(screen.getByTestId("tab-overrides"));
expect(screen.getByTestId("tab-overrides")).toHaveClass(/active/);
});
});
describe("Templates Tab", () => {
it("renders built-in templates as read-only cards", () => {
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Should show built-in templates section
expect(screen.getByTestId("builtin-templates")).toBeTruthy();
expect(screen.getByTestId("builtin-template-default-executor")).toBeTruthy();
expect(screen.getByTestId("builtin-template-default-triage")).toBeTruthy();
// Should show Built-in badge
expect(screen.getAllByText("Built-in").length).toBe(4);
});
it("built-in template cards have role badges", () => {
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
expect(screen.getAllByText("Executor Agent").length).toBe(1);
expect(screen.getAllByText("Triage Agent").length).toBe(1);
expect(screen.getAllByText("Reviewer Agent").length).toBe(1);
expect(screen.getAllByText("Merger Agent").length).toBe(1);
});
it("template preview shows full prompt text (not truncated)", () => {
const defaultExecutorTemplate = BUILTIN_AGENT_PROMPTS.find(
(template) => template.id === "default-executor",
);
if (!defaultExecutorTemplate) {
throw new Error("default-executor template is required for this test");
}
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
const card = screen.getByTestId("builtin-template-default-executor");
const previewCode = card.querySelector(".prompt-template-card-preview code");
expect(previewCode).toBeTruthy();
expect(previewCode?.textContent).toBe(defaultExecutorTemplate.prompt);
expect(defaultExecutorTemplate.prompt.length).toBeGreaterThan(200);
});
it("template preview area has scrollable overflow", () => {
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
const card = screen.getByTestId("builtin-template-default-executor");
const previewCode = card.querySelector(".prompt-template-card-preview code") as HTMLElement | null;
expect(previewCode).toBeTruthy();
expect(window.getComputedStyle(previewCode!).maxHeight).toBe("120px");
expect(window.getComputedStyle(previewCode!).overflowY).toBe("auto");
});
it("shows custom templates section", () => {
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
expect(screen.getByTestId("custom-templates")).toBeTruthy();
expect(screen.getByText("No custom templates yet. Create one to get started.")).toBeTruthy();
});
it("shows Add Custom Template button", () => {
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
expect(screen.getByTestId("add-template-btn")).toBeTruthy();
});
it("clicking Add Custom Template shows editor form", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
await user.click(screen.getByTestId("add-template-btn"));
expect(screen.getByTestId("template-editor")).toBeTruthy();
expect(screen.getByTestId("template-name-input")).toBeTruthy();
expect(screen.getByTestId("template-description-input")).toBeTruthy();
expect(screen.getByTestId("template-role-select")).toBeTruthy();
expect(screen.getByTestId("template-prompt-input")).toBeTruthy();
});
it("creating a custom template fires onChange with new template", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Open editor
await user.click(screen.getByTestId("add-template-btn"));
// Fill in the form
await user.type(screen.getByTestId("template-name-input"), "My Custom Template");
await user.type(screen.getByTestId("template-description-input"), "A custom description");
await user.type(screen.getByTestId("template-prompt-input"), "Custom prompt text");
// Save
await user.click(screen.getByTestId("save-template-btn"));
// Verify onChange was called with new template
expect(onChange).toHaveBeenCalledTimes(1);
const newConfig = onChange.mock.calls[0][0];
expect(newConfig.templates).toBeDefined();
expect(newConfig.templates.length).toBe(1);
expect(newConfig.templates[0].name).toBe("My Custom Template");
expect(newConfig.templates[0].id).toBe("my-custom-template");
});
it("shows existing custom templates", () => {
const config: AgentPromptsConfig = {
templates: [
{
id: "my-custom",
name: "My Custom",
description: "Custom description",
role: "executor",
prompt: "Custom prompt",
builtIn: false,
},
],
};
render(
<AgentPromptsManager
value={config}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
expect(screen.getByTestId("custom-template-my-custom")).toBeTruthy();
expect(screen.getAllByText("Custom").length).toBeGreaterThan(0);
});
it("edit button shows editor with existing template data", async () => {
const user = userEvent.setup();
const config: AgentPromptsConfig = {
templates: [
{
id: "my-custom",
name: "My Custom",
description: "Custom description",
role: "executor",
prompt: "Custom prompt",
builtIn: false,
},
],
};
render(
<AgentPromptsManager
value={config}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Click edit button
await user.click(screen.getByTestId("edit-my-custom"));
// Should show editor with existing data
expect(screen.getByTestId("template-editor")).toBeTruthy();
expect((screen.getByTestId("template-name-input") as HTMLInputElement).value).toBe("My Custom");
});
it("delete button requires confirmation", async () => {
const user = userEvent.setup();
const config: AgentPromptsConfig = {
templates: [
{
id: "my-custom",
name: "My Custom",
description: "Custom description",
role: "executor",
prompt: "Custom prompt",
builtIn: false,
},
],
};
render(
<AgentPromptsManager
value={config}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Click delete button
await user.click(screen.getByTestId("delete-my-custom"));
// Should show confirmation
expect(screen.getByTestId("confirm-delete-my-custom")).toBeTruthy();
expect(screen.getByTestId("cancel-delete-my-custom")).toBeTruthy();
});
it("confirming delete fires onChange with template removed", async () => {
const user = userEvent.setup();
const config: AgentPromptsConfig = {
templates: [
{
id: "my-custom",
name: "My Custom",
description: "Custom description",
role: "executor",
prompt: "Custom prompt",
builtIn: false,
},
],
};
render(
<AgentPromptsManager
value={config}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Click delete and confirm
await user.click(screen.getByTestId("delete-my-custom"));
await user.click(screen.getByTestId("confirm-delete-my-custom"));
// Verify onChange was called with empty templates
expect(onChange).toHaveBeenCalledTimes(1);
const newConfig = onChange.mock.calls[0][0];
expect(newConfig.templates).toBeUndefined();
});
});
describe("Assignments Tab", () => {
it("renders assignment rows for each core role", () => {
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Click Assignments tab
fireEvent.click(screen.getByTestId("tab-assignments"));
expect(screen.getByTestId("assignment-executor")).toBeTruthy();
expect(screen.getByTestId("assignment-triage")).toBeTruthy();
expect(screen.getByTestId("assignment-reviewer")).toBeTruthy();
expect(screen.getByTestId("assignment-merger")).toBeTruthy();
});
it("shows dropdown with template options", () => {
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Click Assignments tab
fireEvent.click(screen.getByTestId("tab-assignments"));
// Executor dropdown should have built-in and "Use default" options
const executorSelect = screen.getByTestId("select-executor") as HTMLSelectElement;
expect(executorSelect.options.length).toBeGreaterThan(1); // "Use default" + built-in templates for executor
});
it("changing assignment fires onChange", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Click Assignments tab
fireEvent.click(screen.getByTestId("tab-assignments"));
// Select a template
const select = screen.getByTestId("select-executor");
fireEvent.change(select, { target: { value: "default-executor" } });
// Verify onChange was called
expect(onChange).toHaveBeenCalledTimes(1);
const newConfig = onChange.mock.calls[0][0];
expect(newConfig.roleAssignments).toBeDefined();
expect(newConfig.roleAssignments?.executor).toBe("default-executor");
});
it("clearing assignment removes it from config", async () => {
const user = userEvent.setup();
const config: AgentPromptsConfig = {
roleAssignments: {
executor: "default-executor",
},
};
render(
<AgentPromptsManager
value={config}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Click Assignments tab
fireEvent.click(screen.getByTestId("tab-assignments"));
// Select "Use default"
const select = screen.getByTestId("select-executor");
fireEvent.change(select, { target: { value: "" } });
// Verify onChange was called with executor removed
expect(onChange).toHaveBeenCalledTimes(1);
const newConfig = onChange.mock.calls[0][0];
expect(newConfig.roleAssignments?.executor).toBeUndefined();
});
});
describe("Overrides Tab", () => {
it("renders override accordion items", () => {
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Click Overrides tab
fireEvent.click(screen.getByTestId("tab-overrides"));
expect(screen.getByTestId("override-executor-welcome")).toBeTruthy();
expect(screen.getByTestId("override-triage-welcome")).toBeTruthy();
});
it("accordion items are collapsed by default", () => {
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Click Overrides tab
fireEvent.click(screen.getByTestId("tab-overrides"));
// Editor should not be visible
expect(screen.queryByTestId("override-input-executor-welcome")).toBeNull();
});
it("clicking expand button shows editor", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Click Overrides tab
fireEvent.click(screen.getByTestId("tab-overrides"));
// Click expand button
await user.click(screen.getByTestId("expand-executor-welcome"));
// Editor should now be visible
await waitFor(() => {
expect(screen.getByTestId("override-input-executor-welcome")).toBeTruthy();
});
});
it("editing an override fires onPromptOverridesChange", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Click Overrides tab
fireEvent.click(screen.getByTestId("tab-overrides"));
// Expand and edit
await user.click(screen.getByTestId("expand-executor-welcome"));
await waitFor(() => {
expect(screen.getByTestId("override-input-executor-welcome")).toBeTruthy();
});
const textarea = screen.getByTestId("override-input-executor-welcome") as HTMLTextAreaElement;
// Use fireEvent.change for a single programmatic change
fireEvent.change(textarea, { target: { value: "Custom override" } });
// Verify onPromptOverridesChange was called
await waitFor(() => {
expect(onPromptOverridesChange).toHaveBeenCalled();
});
// Check the last call contains the expected value
const lastCall = onPromptOverridesChange.mock.calls[onPromptOverridesChange.mock.calls.length - 1];
const newOverrides = lastCall[0];
expect(newOverrides["executor-welcome"]).toBe("Custom override");
});
it("shows Reset button for existing overrides", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{
"executor-welcome": "Custom text",
}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Click Overrides tab
fireEvent.click(screen.getByTestId("tab-overrides"));
// Expand
await user.click(screen.getByTestId("expand-executor-welcome"));
await waitFor(() => {
expect(screen.getByTestId("override-input-executor-welcome")).toBeTruthy();
});
// Should show "customized" badge and Reset button
expect(screen.getByText("customized")).toBeTruthy();
expect(screen.getByTestId("reset-executor-welcome")).toBeTruthy();
});
it("Reset button fires onPromptOverridesChange with null", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{
"executor-welcome": "Custom text",
}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Click Overrides tab
fireEvent.click(screen.getByTestId("tab-overrides"));
// Expand and reset
await user.click(screen.getByTestId("expand-executor-welcome"));
await waitFor(() => {
expect(screen.getByTestId("override-input-executor-welcome")).toBeTruthy();
});
await user.click(screen.getByTestId("reset-executor-welcome"));
// Verify onPromptOverridesChange was called with null
expect(onPromptOverridesChange).toHaveBeenCalledTimes(1);
const newOverrides = onPromptOverridesChange.mock.calls[0][0];
expect(newOverrides["executor-welcome"]).toBeNull();
});
});
describe("Fullscreen Expansion", () => {
describe("Overrides tab fullscreen", () => {
it("shows fullscreen button when override is expanded", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Click Overrides tab
fireEvent.click(screen.getByTestId("tab-overrides"));
// Expand the override
await user.click(screen.getByTestId("expand-executor-welcome"));
await waitFor(() => {
expect(screen.getByTestId("override-input-executor-welcome")).toBeTruthy();
});
// Fullscreen button should be visible
expect(screen.getByTestId("fullscreen-executor-welcome")).toBeTruthy();
});
it("clicking fullscreen button opens fullscreen view", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Click Overrides tab
fireEvent.click(screen.getByTestId("tab-overrides"));
// Expand and click fullscreen
await user.click(screen.getByTestId("expand-executor-welcome"));
await waitFor(() => {
expect(screen.getByTestId("override-input-executor-welcome")).toBeTruthy();
});
await user.click(screen.getByTestId("fullscreen-executor-welcome"));
// Fullscreen container should be visible
await waitFor(() => {
expect(screen.getByTestId("override-input-fullscreen-executor-welcome")).toBeTruthy();
expect(screen.getByTestId("collapse-fullscreen-executor-welcome")).toBeTruthy();
});
});
it("fullscreen textarea contains current override value", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{
"executor-welcome": "My custom welcome message",
}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Click Overrides tab
fireEvent.click(screen.getByTestId("tab-overrides"));
// Expand and go fullscreen
await user.click(screen.getByTestId("expand-executor-welcome"));
await waitFor(() => {
expect(screen.getByTestId("override-input-executor-welcome")).toBeTruthy();
});
await user.click(screen.getByTestId("fullscreen-executor-welcome"));
// Verify fullscreen textarea has the value
await waitFor(() => {
const textarea = screen.getByTestId("override-input-fullscreen-executor-welcome") as HTMLTextAreaElement;
expect(textarea.value).toBe("My custom welcome message");
});
});
it("clicking collapse button exits fullscreen", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Click Overrides tab
fireEvent.click(screen.getByTestId("tab-overrides"));
// Expand, go fullscreen, and collapse
await user.click(screen.getByTestId("expand-executor-welcome"));
await waitFor(() => {
expect(screen.getByTestId("override-input-executor-welcome")).toBeTruthy();
});
await user.click(screen.getByTestId("fullscreen-executor-welcome"));
await waitFor(() => {
expect(screen.getByTestId("override-input-fullscreen-executor-welcome")).toBeTruthy();
});
await user.click(screen.getByTestId("collapse-fullscreen-executor-welcome"));
// Fullscreen should be gone, but accordion should still be expanded
await waitFor(() => {
expect(screen.queryByTestId("override-input-fullscreen-executor-welcome")).toBeNull();
expect(screen.getByTestId("override-input-executor-welcome")).toBeTruthy();
});
});
it("Escape key exits fullscreen", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Click Overrides tab
fireEvent.click(screen.getByTestId("tab-overrides"));
// Expand, go fullscreen
await user.click(screen.getByTestId("expand-executor-welcome"));
await waitFor(() => {
expect(screen.getByTestId("override-input-executor-welcome")).toBeTruthy();
});
await user.click(screen.getByTestId("fullscreen-executor-welcome"));
await waitFor(() => {
expect(screen.getByTestId("override-input-fullscreen-executor-welcome")).toBeTruthy();
});
// Press Escape
const textarea = screen.getByTestId("override-input-fullscreen-executor-welcome") as HTMLTextAreaElement;
fireEvent.keyDown(textarea, { key: "Escape" });
// Fullscreen should be gone
await waitFor(() => {
expect(screen.queryByTestId("override-input-fullscreen-executor-welcome")).toBeNull();
});
});
it("editing in fullscreen fires onPromptOverridesChange", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Click Overrides tab
fireEvent.click(screen.getByTestId("tab-overrides"));
// Expand, go fullscreen, and type
await user.click(screen.getByTestId("expand-executor-welcome"));
await waitFor(() => {
expect(screen.getByTestId("override-input-executor-welcome")).toBeTruthy();
});
await user.click(screen.getByTestId("fullscreen-executor-welcome"));
await waitFor(() => {
expect(screen.getByTestId("override-input-fullscreen-executor-welcome")).toBeTruthy();
});
const textarea = screen.getByTestId("override-input-fullscreen-executor-welcome") as HTMLTextAreaElement;
fireEvent.change(textarea, { target: { value: "Fullscreen edit" } });
// Verify onPromptOverridesChange was called with updated value
await waitFor(() => {
expect(onPromptOverridesChange).toHaveBeenCalled();
const lastCall = onPromptOverridesChange.mock.calls[onPromptOverridesChange.mock.calls.length - 1];
const newOverrides = lastCall[0];
expect(newOverrides["executor-welcome"]).toBe("Fullscreen edit");
});
});
});
describe("Templates tab fullscreen", () => {
it("each built-in template card has an expand button", () => {
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
for (const template of BUILTIN_AGENT_PROMPTS) {
expect(screen.getByTestId(`expand-view-${template.id}`)).toBeTruthy();
}
});
it("clicking expand button opens fullscreen view", async () => {
const user = userEvent.setup();
const defaultExecutorTemplate = BUILTIN_AGENT_PROMPTS.find(
(template) => template.id === "default-executor",
);
if (!defaultExecutorTemplate) {
throw new Error("default-executor template is required for this test");
}
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
await user.click(screen.getByTestId("expand-view-default-executor"));
await waitFor(() => {
expect(screen.getByTestId("collapse-view-default-executor")).toBeTruthy();
expect(screen.getByRole("dialog").textContent).toContain(defaultExecutorTemplate.prompt);
});
});
it("clicking collapse button exits fullscreen", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
await user.click(screen.getByTestId("expand-view-default-executor"));
await waitFor(() => {
expect(screen.getByTestId("collapse-view-default-executor")).toBeTruthy();
});
await user.click(screen.getByTestId("collapse-view-default-executor"));
await waitFor(() => {
expect(screen.queryByTestId("collapse-view-default-executor")).toBeNull();
});
});
it("Escape key exits fullscreen", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
await user.click(screen.getByTestId("expand-view-default-executor"));
await waitFor(() => {
expect(screen.getByTestId("collapse-view-default-executor")).toBeTruthy();
});
fireEvent.keyDown(screen.getByRole("dialog"), { key: "Escape" });
await waitFor(() => {
expect(screen.queryByTestId("collapse-view-default-executor")).toBeNull();
});
});
it("custom template card has expand button", () => {
const config: AgentPromptsConfig = {
templates: [
{
id: "my-custom-template",
name: "My Custom Template",
description: "Custom template for testing",
role: "executor",
prompt: "Custom prompt content",
builtIn: false,
},
],
};
render(
<AgentPromptsManager
value={config}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
expect(screen.getByTestId("expand-view-my-custom-template")).toBeTruthy();
});
it("only one template fullscreen at a time", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
await user.click(screen.getByTestId("expand-view-default-executor"));
await waitFor(() => {
expect(screen.getByTestId("collapse-view-default-executor")).toBeTruthy();
});
await user.click(screen.getByTestId("expand-view-default-triage"));
await waitFor(() => {
expect(screen.queryByTestId("collapse-view-default-executor")).toBeNull();
expect(screen.getByTestId("collapse-view-default-triage")).toBeTruthy();
});
});
it("fullscreen view remains singular when custom template overrides a built-in ID", async () => {
const user = userEvent.setup();
const config: AgentPromptsConfig = {
templates: [
{
id: "default-executor",
name: "Custom Override Executor",
description: "Overrides built-in template",
role: "executor",
prompt: "Custom override prompt body for executor role.",
builtIn: false,
},
],
};
render(
<AgentPromptsManager
value={config}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
const expandButtons = screen.getAllByTestId("expand-view-default-executor");
expect(expandButtons.length).toBe(2);
await user.click(expandButtons[0]);
await waitFor(() => {
expect(screen.getAllByRole("dialog").length).toBe(1);
expect(screen.getByRole("dialog").textContent).toContain("Default Executor");
});
await user.click(expandButtons[1]);
await waitFor(() => {
expect(screen.getAllByRole("dialog").length).toBe(1);
expect(screen.getByRole("dialog").textContent).toContain("Custom Override Executor");
});
});
it("opening template card fullscreen closes template editor fullscreen", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
await user.click(screen.getByTestId("add-template-btn"));
await user.click(screen.getByTestId("template-prompt-fullscreen"));
await waitFor(() => {
expect(screen.getByTestId("template-prompt-input-fullscreen")).toBeTruthy();
});
await user.click(screen.getByTestId("expand-view-default-executor"));
await waitFor(() => {
expect(screen.queryByTestId("template-prompt-input-fullscreen")).toBeNull();
expect(screen.getByTestId("collapse-view-default-executor")).toBeTruthy();
});
});
it("shows fullscreen button in template editor", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Open template editor
await user.click(screen.getByTestId("add-template-btn"));
// Fullscreen button should be visible
expect(screen.getByTestId("template-prompt-fullscreen")).toBeTruthy();
});
it("clicking fullscreen button opens fullscreen view for template prompt", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Open template editor
await user.click(screen.getByTestId("add-template-btn"));
// Click fullscreen button
await user.click(screen.getByTestId("template-prompt-fullscreen"));
// Fullscreen container should be visible
await waitFor(() => {
expect(screen.getByTestId("template-prompt-input-fullscreen")).toBeTruthy();
expect(screen.getByTestId("template-prompt-collapse")).toBeTruthy();
});
});
it("Escape key exits template prompt fullscreen", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Open template editor and go fullscreen
await user.click(screen.getByTestId("add-template-btn"));
await user.click(screen.getByTestId("template-prompt-fullscreen"));
await waitFor(() => {
expect(screen.getByTestId("template-prompt-input-fullscreen")).toBeTruthy();
});
// Press Escape
const textarea = screen.getByTestId("template-prompt-input-fullscreen") as HTMLTextAreaElement;
fireEvent.keyDown(textarea, { key: "Escape" });
// Fullscreen should be gone
await waitFor(() => {
expect(screen.queryByTestId("template-prompt-input-fullscreen")).toBeNull();
});
});
it("saving template resets fullscreen state", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Open template editor and go fullscreen
await user.click(screen.getByTestId("add-template-btn"));
await user.click(screen.getByTestId("template-prompt-fullscreen"));
await waitFor(() => {
expect(screen.getByTestId("template-prompt-input-fullscreen")).toBeTruthy();
});
// Fill in name and save
await user.type(screen.getByTestId("template-name-input"), "My Template");
await user.click(screen.getByTestId("save-template-btn"));
// Verify fullscreen is gone after save
await waitFor(() => {
expect(screen.queryByTestId("template-prompt-input-fullscreen")).toBeNull();
expect(screen.queryByTestId("template-editor")).toBeNull();
});
});
it("canceling template edit resets fullscreen state", async () => {
const user = userEvent.setup();
render(
<AgentPromptsManager
value={defaultConfig}
onChange={onChange}
promptOverrides={{}}
onPromptOverridesChange={onPromptOverridesChange}
/>,
);
// Open template editor and go fullscreen
await user.click(screen.getByTestId("add-template-btn"));
await user.click(screen.getByTestId("template-prompt-fullscreen"));
await waitFor(() => {
expect(screen.getByTestId("template-prompt-input-fullscreen")).toBeTruthy();
});
// Cancel
await user.click(screen.getByTestId("cancel-template-btn"));
// Verify fullscreen is gone after cancel
await waitFor(() => {
expect(screen.queryByTestId("template-prompt-input-fullscreen")).toBeNull();
expect(screen.queryByTestId("template-editor")).toBeNull();
});
});
});
});
});