Files
kandev/apps/web/components/settings/workspaces/workspace-settings-shell.test.tsx
2026-09-05 18:44:43 +00:00

210 lines
6.7 KiB
TypeScript

import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
import { cleanup, fireEvent, render, screen } from "@testing-library/react";
const navigationMock = vi.hoisted(() => ({ push: vi.fn() }));
vi.mock("@/lib/routing/client-router", () => ({
useRouter: () => ({ push: navigationMock.push }),
}));
// Same treatment as the sidebar picker's test: Radix dropdown primitives rely on
// pointer/portal behaviour jsdom doesn't model, so render them as plain elements
// and let `onSelect` fire on click.
vi.mock("@kandev/ui/dropdown-menu", () => ({
DropdownMenu: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
DropdownMenuTrigger: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
DropdownMenuContent: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
DropdownMenuItem: ({
children,
onSelect,
disabled,
"data-testid": testId,
}: {
children: React.ReactNode;
onSelect?: () => void;
disabled?: boolean;
"data-testid"?: string;
}) => (
<button type="button" disabled={disabled} data-testid={testId} onClick={() => onSelect?.()}>
{children}
</button>
),
DropdownMenuSeparator: () => <hr />,
}));
const storeState = {
features: { office: false, canvases: false },
workspaces: {
items: [
{ id: "w1", name: "Default Workspace", office_workflow_id: "" },
{ id: "w2", name: "Office Workspace", office_workflow_id: "wf-office" },
],
activeId: "w1",
},
setActiveWorkspace: vi.fn(),
};
vi.mock("@/components/state-provider", () => ({
useAppStore: (selector: (state: typeof storeState) => unknown) => selector(storeState),
}));
import { WorkspaceSettingsShell } from "./workspace-settings-shell";
const CURRENT_WORKSPACE_ITEM = "workspace-settings-switcher-item-w1";
const OTHER_WORKSPACE_ITEM = "workspace-settings-switcher-item-w2";
describe("WorkspaceSettingsShell — workspace switcher", () => {
beforeEach(() => {
navigationMock.push = vi.fn();
storeState.features.office = false;
storeState.features.canvases = false;
storeState.workspaces.activeId = "w1";
storeState.setActiveWorkspace = vi.fn();
});
afterEach(cleanup);
it("keeps the current tab when switching to another workspace", () => {
render(
<WorkspaceSettingsShell workspaceId="w1" activeTab="secrets">
<div />
</WorkspaceSettingsShell>,
);
fireEvent.click(screen.getByTestId(OTHER_WORKSPACE_ITEM));
expect(navigationMock.push).toHaveBeenCalledWith("/settings/workspaces/w2/secrets");
});
it("does not navigate when picking the workspace already open", () => {
render(
<WorkspaceSettingsShell workspaceId="w1" activeTab="repositories">
<div />
</WorkspaceSettingsShell>,
);
fireEvent.click(screen.getByTestId(CURRENT_WORKSPACE_ITEM));
expect(navigationMock.push).not.toHaveBeenCalled();
});
it("never changes the active workspace — this switcher only navigates", () => {
render(
<WorkspaceSettingsShell workspaceId="w2" activeTab="overview">
<div />
</WorkspaceSettingsShell>,
);
fireEvent.click(screen.getByTestId(CURRENT_WORKSPACE_ITEM));
expect(navigationMock.push).toHaveBeenCalledWith("/settings/workspaces/w1");
expect(storeState.setActiveWorkspace).not.toHaveBeenCalled();
});
it("badges the active workspace after its name, not the one being edited", () => {
storeState.workspaces.activeId = "w2";
render(
<WorkspaceSettingsShell workspaceId="w1" activeTab="overview">
<div />
</WorkspaceSettingsShell>,
);
const activeRow = screen.getByTestId(OTHER_WORKSPACE_ITEM).textContent ?? "";
expect(activeRow).toContain("Active");
expect(activeRow.indexOf("Active")).toBeGreaterThan(activeRow.indexOf("Office Workspace"));
expect(screen.getByTestId(CURRENT_WORKSPACE_ITEM).textContent).not.toContain("Active");
});
it("marks the header with the Active badge only on the active workspace's page", () => {
storeState.workspaces.activeId = "w1";
const { unmount } = render(
<WorkspaceSettingsShell workspaceId="w1" activeTab="overview">
<div />
</WorkspaceSettingsShell>,
);
expect(screen.getByTestId("workspace-settings-active-badge").textContent).toBe("Active");
unmount();
storeState.workspaces.activeId = "w2";
render(
<WorkspaceSettingsShell workspaceId="w1" activeTab="overview">
<div />
</WorkspaceSettingsShell>,
);
expect(screen.queryByTestId("workspace-settings-active-badge")).toBeNull();
});
it("names the open workspace on the trigger", () => {
render(
<WorkspaceSettingsShell workspaceId="w1" activeTab="overview">
<div />
</WorkspaceSettingsShell>,
);
const trigger = screen.getByTestId("workspace-settings-switcher");
expect(trigger.getAttribute("aria-label")).toBe("Switch workspace");
expect(trigger.textContent).toContain("Default Workspace");
});
it("falls back to a plain heading for an unknown workspace", () => {
render(
<WorkspaceSettingsShell workspaceId="missing" activeTab="overview">
<div />
</WorkspaceSettingsShell>,
);
expect(screen.queryByTestId("workspace-settings-switcher")).toBeNull();
expect(screen.getByRole("heading", { level: 2 }).textContent).toBe("Workspace");
});
it("offers the office create item only when the office feature is on", () => {
storeState.features.office = true;
render(
<WorkspaceSettingsShell workspaceId="w1" activeTab="overview">
<div />
</WorkspaceSettingsShell>,
);
fireEvent.click(screen.getByText("New office workspace"));
expect(navigationMock.push).toHaveBeenCalledWith("/office/setup?mode=new");
});
});
describe("WorkspaceSettingsShell canvas navigation", () => {
beforeEach(() => {
navigationMock.push = vi.fn();
storeState.features.office = false;
storeState.features.canvases = false;
storeState.workspaces.activeId = "w1";
storeState.setActiveWorkspace = vi.fn();
});
afterEach(cleanup);
it("shows the Canvases tab only while the canvas feature is enabled", () => {
storeState.features.canvases = true;
const { unmount } = render(
<WorkspaceSettingsShell workspaceId="w1" activeTab="canvases">
<div />
</WorkspaceSettingsShell>,
);
expect(screen.getByRole("link", { name: "Canvases" }).getAttribute("href")).toBe(
"/settings/workspaces/w1/canvases",
);
unmount();
storeState.features.canvases = false;
render(
<WorkspaceSettingsShell workspaceId="w1" activeTab="overview">
<div />
</WorkspaceSettingsShell>,
);
expect(screen.queryByRole("link", { name: "Canvases" })).toBeNull();
});
});