Files
fusion/packages/dashboard/app/components/Header.test.tsx
gsxdsm 650b8ccfc3 fix(KB-096): restore usage button in dashboard header
- 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
2026-03-30 04:58:50 -07:00

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();
});
});
});