Skip to content
File

Blob: test/tab-strip.test.ts

typescript91 lines
1// @vitest-environment jsdom
2 
3import { act, createElement } from "react";
4import { createRoot, type Root } from "react-dom/client";
5import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
6import { TabStrip } from "../src/client/components/tab-strip";
7import { useWorkspaceStore } from "../src/client/workspace/store";
8 
9let container: HTMLDivElement | null = null;
10let root: Root | null = null;
11const reactActEnvironment = globalThis as typeof globalThis & {
12 IS_REACT_ACT_ENVIRONMENT?: boolean;
13};
14 
15function resetStore(): void {
16 sessionStorage.clear();
17 useWorkspaceStore.setState(useWorkspaceStore.getInitialState());
18}
19 
20function renderTabStrip(): void {
21 if (!root) {
22 throw new Error("Root was not created");
23 }
24 
25 act(() => {
26 root!.render(createElement(TabStrip));
27 });
28}
29 
30beforeEach(() => {
31 reactActEnvironment.IS_REACT_ACT_ENVIRONMENT = true;
32 resetStore();
33 container = document.createElement("div");
34 document.body.appendChild(container);
35 root = createRoot(container);
36});
37 
38afterEach(() => {
39 if (root) {
40 act(() => {
41 root!.unmount();
42 });
43 }
44 root = null;
45 container?.remove();
46 container = null;
47 document.body.innerHTML = "";
48 resetStore();
49 delete reactActEnvironment.IS_REACT_ACT_ENVIRONMENT;
50 vi.restoreAllMocks();
51});
52 
53describe("TabStrip", () => {
54 it("renders the close control outside the tab button without nesting warnings", () => {
55 useWorkspaceStore.getState().newTab();
56 const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
57 
58 renderTabStrip();
59 
60 const closeButton = container?.querySelector('button[aria-label="Close Terminal 1"]');
61 expect(closeButton).toBeInstanceOf(HTMLButtonElement);
62 expect(closeButton?.closest('button[role="tab"]')).toBeNull();
63 
64 const nestedButtonWarning = errorSpy.mock.calls.some((args) =>
65 args.some((arg) => String(arg).includes("<button> cannot be a descendant of <button>")),
66 );
67 expect(nestedButtonWarning).toBe(false);
68 });
69 
70 it("closes an inactive tab without switching the active tab first", () => {
71 const store = useWorkspaceStore.getState();
72 store.newTab();
73 store.newTab();
74 const activeTabIdBeforeClose = useWorkspaceStore.getState().activeTabId;
75 
76 renderTabStrip();
77 
78 const closeButton = container?.querySelector('button[aria-label="Close Terminal 1"]');
79 expect(closeButton).toBeInstanceOf(HTMLButtonElement);
80 
81 act(() => {
82 closeButton!.dispatchEvent(new MouseEvent("click", { bubbles: true }));
83 });
84 
85 const { activeTabId, tabs } = useWorkspaceStore.getState();
86 expect(tabs).toHaveLength(2);
87 expect(tabs.some((tab) => tab.title === "Terminal 1")).toBe(false);
88 expect(activeTabId).toBe(activeTabIdBeforeClose);
89 });
90});