- Add the optional usage action back to the dashboard Header component - Preserve the existing board search UI while restoring the usage button wiring - Add Header tests for usage button rendering and click behavior - Add a patch changeset for the restored header usage action
194 lines
6.7 KiB
TypeScript
194 lines
6.7 KiB
TypeScript
import { describe, it, expect, vi } from "vitest";
|
|
import { render, screen, fireEvent } from "@testing-library/react";
|
|
import { Header } from "./Header";
|
|
|
|
const noop = () => {};
|
|
|
|
function renderHeader(props = {}) {
|
|
return render(
|
|
<Header
|
|
onOpenSettings={noop}
|
|
onOpenGitHubImport={noop}
|
|
globalPaused={false}
|
|
enginePaused={false}
|
|
onToggleGlobalPause={noop}
|
|
onToggleEnginePause={noop}
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
|
|
describe("Header", () => {
|
|
it("renders the logo and brand", () => {
|
|
renderHeader();
|
|
expect(screen.getByText("Fusion")).toBeDefined();
|
|
expect(screen.getByText("tasks")).toBeDefined();
|
|
});
|
|
|
|
it("renders action buttons", () => {
|
|
renderHeader();
|
|
expect(screen.getByTitle("Import from GitHub")).toBeDefined();
|
|
expect(screen.getByTitle("Settings")).toBeDefined();
|
|
});
|
|
|
|
it("calls onOpenSettings when settings button is clicked", () => {
|
|
const onOpenSettings = vi.fn();
|
|
renderHeader({ onOpenSettings });
|
|
fireEvent.click(screen.getByTitle("Settings"));
|
|
expect(onOpenSettings).toHaveBeenCalled();
|
|
});
|
|
|
|
it("calls onOpenGitHubImport when import button is clicked", () => {
|
|
const onOpenGitHubImport = vi.fn();
|
|
renderHeader({ onOpenGitHubImport });
|
|
fireEvent.click(screen.getByTitle("Import from GitHub"));
|
|
expect(onOpenGitHubImport).toHaveBeenCalled();
|
|
});
|
|
|
|
describe("view toggle", () => {
|
|
it("does not render view toggle when onChangeView is not provided", () => {
|
|
renderHeader();
|
|
expect(screen.queryByTitle("Board view")).toBeNull();
|
|
expect(screen.queryByTitle("List view")).toBeNull();
|
|
});
|
|
|
|
it("renders view toggle when onChangeView is provided", () => {
|
|
renderHeader({ onChangeView: noop });
|
|
expect(screen.getByTitle("Board view")).toBeDefined();
|
|
expect(screen.getByTitle("List view")).toBeDefined();
|
|
});
|
|
|
|
it("shows board view as active by default", () => {
|
|
renderHeader({ onChangeView: noop });
|
|
const boardBtn = screen.getByTitle("Board view");
|
|
const listBtn = screen.getByTitle("List view");
|
|
expect(boardBtn.className).toContain("active");
|
|
expect(listBtn.className).not.toContain("active");
|
|
});
|
|
|
|
it("shows list view as active when view is 'list'", () => {
|
|
renderHeader({ onChangeView: noop, view: "list" });
|
|
const boardBtn = screen.getByTitle("Board view");
|
|
const listBtn = screen.getByTitle("List view");
|
|
expect(boardBtn.className).not.toContain("active");
|
|
expect(listBtn.className).toContain("active");
|
|
});
|
|
|
|
it("calls onChangeView with 'board' when clicking board view button", () => {
|
|
const onChangeView = vi.fn();
|
|
renderHeader({ onChangeView, view: "list" });
|
|
fireEvent.click(screen.getByTitle("Board view"));
|
|
expect(onChangeView).toHaveBeenCalledWith("board");
|
|
});
|
|
|
|
it("calls onChangeView with 'list' when clicking list view button", () => {
|
|
const onChangeView = vi.fn();
|
|
renderHeader({ onChangeView, view: "board" });
|
|
fireEvent.click(screen.getByTitle("List view"));
|
|
expect(onChangeView).toHaveBeenCalledWith("list");
|
|
});
|
|
|
|
it("has correct aria attributes for accessibility", () => {
|
|
renderHeader({ onChangeView: noop, view: "board" });
|
|
const boardBtn = screen.getByTitle("Board view");
|
|
const listBtn = screen.getByTitle("List view");
|
|
expect(boardBtn.getAttribute("aria-pressed")).toBe("true");
|
|
expect(listBtn.getAttribute("aria-pressed")).toBe("false");
|
|
});
|
|
});
|
|
|
|
describe("terminal button", () => {
|
|
it("renders terminal button with correct title", () => {
|
|
renderHeader({ onToggleTerminal: noop });
|
|
expect(screen.getByTitle("Open Terminal")).toBeDefined();
|
|
});
|
|
|
|
it("calls onToggleTerminal when terminal button is clicked", () => {
|
|
const onToggleTerminal = vi.fn();
|
|
renderHeader({ onToggleTerminal });
|
|
fireEvent.click(screen.getByTitle("Open Terminal"));
|
|
expect(onToggleTerminal).toHaveBeenCalled();
|
|
});
|
|
|
|
it("is always enabled regardless of task state", () => {
|
|
renderHeader({ onToggleTerminal: noop });
|
|
const btn = screen.getByTitle("Open Terminal");
|
|
expect(btn.hasAttribute("disabled")).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("pause controls", () => {
|
|
it("renders pause button for engine pause", () => {
|
|
renderHeader();
|
|
expect(screen.getByTitle("Pause scheduling")).toBeDefined();
|
|
});
|
|
|
|
it("renders stop button for global pause", () => {
|
|
renderHeader();
|
|
expect(screen.getByTitle("Stop AI engine")).toBeDefined();
|
|
});
|
|
|
|
it("calls onToggleEnginePause when pause button is clicked", () => {
|
|
const onToggleEnginePause = vi.fn();
|
|
renderHeader({ onToggleEnginePause });
|
|
fireEvent.click(screen.getByTitle("Pause scheduling"));
|
|
expect(onToggleEnginePause).toHaveBeenCalled();
|
|
});
|
|
|
|
it("calls onToggleGlobalPause when stop button is clicked", () => {
|
|
const onToggleGlobalPause = vi.fn();
|
|
renderHeader({ onToggleGlobalPause });
|
|
fireEvent.click(screen.getByTitle("Stop AI engine"));
|
|
expect(onToggleGlobalPause).toHaveBeenCalled();
|
|
});
|
|
|
|
it("shows resume text when engine is paused", () => {
|
|
renderHeader({ enginePaused: true });
|
|
expect(screen.getByTitle("Resume scheduling")).toBeDefined();
|
|
});
|
|
|
|
it("shows start text when global is paused", () => {
|
|
renderHeader({ globalPaused: true });
|
|
expect(screen.getByTitle("Start AI engine")).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe("usage button", () => {
|
|
it("does not render usage button when onOpenUsage is not provided", () => {
|
|
renderHeader();
|
|
expect(screen.queryByTitle("View usage")).toBeNull();
|
|
});
|
|
|
|
it("renders usage button with correct title when onOpenUsage is provided", () => {
|
|
renderHeader({ onOpenUsage: vi.fn() });
|
|
expect(screen.getByTitle("View usage")).toBeDefined();
|
|
});
|
|
|
|
it("calls onOpenUsage when usage button is clicked", () => {
|
|
const onOpenUsage = vi.fn();
|
|
renderHeader({ onOpenUsage });
|
|
fireEvent.click(screen.getByTitle("View usage"));
|
|
expect(onOpenUsage).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe("planning button", () => {
|
|
it("renders planning button with correct title", () => {
|
|
renderHeader({ onOpenPlanning: vi.fn() });
|
|
expect(screen.getByTitle("Create a task with AI planning")).toBeDefined();
|
|
});
|
|
|
|
it("calls onOpenPlanning when planning button is clicked", () => {
|
|
const onOpenPlanning = vi.fn();
|
|
renderHeader({ onOpenPlanning });
|
|
fireEvent.click(screen.getByTitle("Create a task with AI planning"));
|
|
expect(onOpenPlanning).toHaveBeenCalled();
|
|
});
|
|
|
|
it("has correct data-testid for testing", () => {
|
|
renderHeader({ onOpenPlanning: vi.fn() });
|
|
expect(screen.getByTestId("planning-btn")).toBeDefined();
|
|
});
|
|
});
|
|
});
|