story-kit: merge 340_story_web_ui_rebuild_and_restart_button
This commit is contained in:
@@ -1,7 +1,13 @@
|
||||
import { fireEvent, render, screen } from "@testing-library/react";
|
||||
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { ChatHeader } from "./ChatHeader";
|
||||
|
||||
vi.mock("../api/client", () => ({
|
||||
api: {
|
||||
rebuildAndRestart: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
interface ChatHeaderProps {
|
||||
projectPath: string;
|
||||
onCloseProject: () => void;
|
||||
@@ -14,6 +20,7 @@ interface ChatHeaderProps {
|
||||
onModelChange: (model: string) => void;
|
||||
enableTools: boolean;
|
||||
onToggleTools: (enabled: boolean) => void;
|
||||
wsConnected: boolean;
|
||||
}
|
||||
|
||||
function makeProps(overrides: Partial<ChatHeaderProps> = {}): ChatHeaderProps {
|
||||
@@ -29,6 +36,7 @@ function makeProps(overrides: Partial<ChatHeaderProps> = {}): ChatHeaderProps {
|
||||
onModelChange: vi.fn(),
|
||||
enableTools: true,
|
||||
onToggleTools: vi.fn(),
|
||||
wsConnected: false,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
@@ -211,4 +219,96 @@ describe("ChatHeader", () => {
|
||||
expect(sessionBtn.style.backgroundColor).toBe("rgb(47, 47, 47)");
|
||||
expect(sessionBtn.style.color).toBe("rgb(136, 136, 136)");
|
||||
});
|
||||
|
||||
// ── Rebuild button ────────────────────────────────────────────────────────
|
||||
|
||||
it("renders rebuild button", () => {
|
||||
render(<ChatHeader {...makeProps()} />);
|
||||
expect(
|
||||
screen.getByTitle("Rebuild and restart the server"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows confirmation dialog when rebuild button is clicked", () => {
|
||||
render(<ChatHeader {...makeProps()} />);
|
||||
fireEvent.click(screen.getByTitle("Rebuild and restart the server"));
|
||||
expect(screen.getByText("Rebuild and restart?")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("hides confirmation dialog when cancel is clicked", () => {
|
||||
render(<ChatHeader {...makeProps()} />);
|
||||
fireEvent.click(screen.getByTitle("Rebuild and restart the server"));
|
||||
fireEvent.click(screen.getByText("Cancel"));
|
||||
expect(screen.queryByText("Rebuild and restart?")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("calls api.rebuildAndRestart and shows Building... when confirmed", async () => {
|
||||
const { api } = await import("../api/client");
|
||||
vi.mocked(api.rebuildAndRestart).mockReturnValue(new Promise(() => {}));
|
||||
|
||||
render(<ChatHeader {...makeProps()} />);
|
||||
fireEvent.click(screen.getByTitle("Rebuild and restart the server"));
|
||||
fireEvent.click(screen.getByText("Rebuild"));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("Building...")).toBeInTheDocument();
|
||||
});
|
||||
expect(api.rebuildAndRestart).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("shows Reconnecting... when rebuild triggers a network error", async () => {
|
||||
const { api } = await import("../api/client");
|
||||
vi.mocked(api.rebuildAndRestart).mockRejectedValue(
|
||||
new TypeError("Failed to fetch"),
|
||||
);
|
||||
|
||||
render(<ChatHeader {...makeProps()} />);
|
||||
fireEvent.click(screen.getByTitle("Rebuild and restart the server"));
|
||||
fireEvent.click(screen.getByText("Rebuild"));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("Reconnecting...")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it("shows error when rebuild returns a failure message", async () => {
|
||||
const { api } = await import("../api/client");
|
||||
vi.mocked(api.rebuildAndRestart).mockResolvedValue(
|
||||
"error[E0308]: mismatched types",
|
||||
);
|
||||
|
||||
render(<ChatHeader {...makeProps()} />);
|
||||
fireEvent.click(screen.getByTitle("Rebuild and restart the server"));
|
||||
fireEvent.click(screen.getByText("Rebuild"));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("⚠ Rebuild failed")).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText("error[E0308]: mismatched types"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it("clears reconnecting state when wsConnected transitions to true", async () => {
|
||||
const { api } = await import("../api/client");
|
||||
vi.mocked(api.rebuildAndRestart).mockRejectedValue(
|
||||
new TypeError("Failed to fetch"),
|
||||
);
|
||||
|
||||
const { rerender } = render(
|
||||
<ChatHeader {...makeProps({ wsConnected: false })} />,
|
||||
);
|
||||
fireEvent.click(screen.getByTitle("Rebuild and restart the server"));
|
||||
fireEvent.click(screen.getByText("Rebuild"));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("Reconnecting...")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
rerender(<ChatHeader {...makeProps({ wsConnected: true })} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("↺ Rebuild")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user