diff options
| author | Adam Malczewski <[email protected]> | 2026-06-27 01:13:28 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-27 01:13:31 +0900 |
| commit | 2fa03f8d7410c2b8d6be8e10ad088863e83d7177 (patch) | |
| tree | 94e1923180ae38d571d34b578afecb0a18913c24 /src/features/tabs/ui.test.ts | |
| parent | 80f99665034a0e510300793205c162fc7a46769f (diff) | |
| parent | 08b12478636f4a5c86a1f3c40a843f2906b7c82f (diff) | |
| download | dispatch-web-2fa03f8d7410c2b8d6be8e10ad088863e83d7177.tar.gz dispatch-web-2fa03f8d7410c2b8d6be8e10ad088863e83d7177.zip | |
Merge branch 'dev' into feature/heartbeat
# Conflicts:
# src/app/App.svelte
# src/app/store.svelte.ts
# src/app/store.test.ts
# src/features/workspaces/ui/WorkspaceCard.test.ts
Diffstat (limited to 'src/features/tabs/ui.test.ts')
| -rw-r--r-- | src/features/tabs/ui.test.ts | 404 |
1 files changed, 202 insertions, 202 deletions
diff --git a/src/features/tabs/ui.test.ts b/src/features/tabs/ui.test.ts index a46b692..087b28c 100644 --- a/src/features/tabs/ui.test.ts +++ b/src/features/tabs/ui.test.ts @@ -5,209 +5,209 @@ import type { Tab } from "./tabs"; import TabBar from "./ui/TabBar.svelte"; const sampleTabs: readonly Tab[] = [ - { conversationId: "c1", model: "openai/gpt-4", title: "First", workspaceId: "default" }, - { conversationId: "c2", model: "anthropic/claude-3", title: "Second", workspaceId: "default" }, - { conversationId: "c3", model: "google/gemini", title: "Third", workspaceId: "default" }, + { conversationId: "c1", model: "openai/gpt-4", title: "First", workspaceId: "default" }, + { conversationId: "c2", model: "anthropic/claude-3", title: "Second", workspaceId: "default" }, + { conversationId: "c3", model: "google/gemini", title: "Third", workspaceId: "default" }, ]; describe("TabBar", () => { - it("renders one role=tab element per tab showing each title", () => { - render(TabBar, { - props: { - tabs: sampleTabs, - activeConversationId: "c1", - onSelect: vi.fn(), - onClose: vi.fn(), - onNewDraft: vi.fn(), - }, - }); - - const tabs = screen.getAllByRole("tab"); - expect(tabs).toHaveLength(sampleTabs.length); - expect(tabs[0]).toHaveTextContent("First"); - expect(tabs[1]).toHaveTextContent("Second"); - expect(tabs[2]).toHaveTextContent("Third"); - }); - - it("applies tab-active to the active tab only", () => { - render(TabBar, { - props: { - tabs: sampleTabs, - activeConversationId: "c2", - onSelect: vi.fn(), - onClose: vi.fn(), - onNewDraft: vi.fn(), - }, - }); - - const tabs = screen.getAllByRole("tab"); - expect(tabs[0]).not.toHaveClass("tab-active"); - expect(tabs[1]).toHaveClass("tab-active"); - expect(tabs[2]).not.toHaveClass("tab-active"); - }); - - it("applies tab-active to New chat button when activeConversationId is null", () => { - render(TabBar, { - props: { - tabs: sampleTabs, - activeConversationId: null, - onSelect: vi.fn(), - onClose: vi.fn(), - onNewDraft: vi.fn(), - }, - }); - - const newChat = screen.getByRole("button", { name: "New chat" }); - expect(newChat).toHaveClass("tab-active"); - }); - - it("calls onSelect with the conversationId when a tab is clicked", async () => { - const onSelect = vi.fn(); - const onClose = vi.fn(); - const user = userEvent.setup(); - - render(TabBar, { - props: { - tabs: sampleTabs, - activeConversationId: "c1", - onSelect, - onClose, - onNewDraft: vi.fn(), - }, - }); - - const tabs = screen.getAllByRole("tab"); - const secondTab = tabs[1]; - if (!secondTab) throw new Error("second tab not found"); - await user.click(secondTab); - - expect(onSelect).toHaveBeenCalledTimes(1); - expect(onSelect).toHaveBeenCalledWith("c2"); - expect(onClose).not.toHaveBeenCalled(); - }); - - it("calls onClose when the close button is clicked and does not call onSelect", async () => { - const onSelect = vi.fn(); - const onClose = vi.fn(); - const user = userEvent.setup(); - - render(TabBar, { - props: { - tabs: sampleTabs, - activeConversationId: "c1", - onSelect, - onClose, - onNewDraft: vi.fn(), - }, - }); - - const closeButtons = screen.getAllByRole("button", { name: "Close tab" }); - const firstClose = closeButtons[0]; - if (!firstClose) throw new Error("first close button not found"); - await user.click(firstClose); - - expect(onClose).toHaveBeenCalledTimes(1); - expect(onClose).toHaveBeenCalledWith("c1"); - expect(onSelect).not.toHaveBeenCalled(); - }); - - it("calls onNewDraft when the New chat button is clicked", async () => { - const onNewDraft = vi.fn(); - const user = userEvent.setup(); - - render(TabBar, { - props: { - tabs: sampleTabs, - activeConversationId: "c1", - onSelect: vi.fn(), - onClose: vi.fn(), - onNewDraft, - }, - }); - - const newChat = screen.getByRole("button", { name: "New chat" }); - await user.click(newChat); - - expect(onNewDraft).toHaveBeenCalledTimes(1); - }); - - it("the New chat button has the sticky class", () => { - render(TabBar, { - props: { - tabs: sampleTabs, - activeConversationId: "c1", - onSelect: vi.fn(), - onClose: vi.fn(), - onNewDraft: vi.fn(), - }, - }); - - const newChat = screen.getByRole("button", { name: "New chat" }); - expect(newChat).toHaveClass("sticky"); - }); - - it("shows visible 'New Chat' text when activeConversationId is null", () => { - render(TabBar, { - props: { - tabs: sampleTabs, - activeConversationId: null, - onSelect: vi.fn(), - onClose: vi.fn(), - onNewDraft: vi.fn(), - }, - }); - - const newChat = screen.getByRole("button", { name: "New chat" }); - expect(newChat).toHaveTextContent("New Chat"); - }); - - it("does not show 'New Chat' text when a real tab is active", () => { - render(TabBar, { - props: { - tabs: sampleTabs, - activeConversationId: "c1", - onSelect: vi.fn(), - onClose: vi.fn(), - onNewDraft: vi.fn(), - }, - }); - - const newChat = screen.getByRole("button", { name: "New chat" }); - expect(newChat).not.toHaveTextContent("New Chat"); - }); - - it("renders a short-handle tab ID badge (shortest unique prefix) per tab", () => { - const tabs: readonly Tab[] = [ - { conversationId: "3f9a1b2c-1111", model: "m", title: "Alpha", workspaceId: "default" }, - { conversationId: "7c2db4e5-2222", model: "m", title: "Beta", workspaceId: "default" }, - ]; - render(TabBar, { - props: { - tabs, - activeConversationId: "3f9a1b2c-1111", - onSelect: vi.fn(), - onClose: vi.fn(), - onNewDraft: vi.fn(), - }, - }); - - expect(screen.getByText("3f9a")).toBeInTheDocument(); - expect(screen.getByText("7c2d")).toBeInTheDocument(); - }); - - it("renders fixed-width tabs", () => { - render(TabBar, { - props: { - tabs: sampleTabs, - activeConversationId: "c1", - onSelect: vi.fn(), - onClose: vi.fn(), - onNewDraft: vi.fn(), - }, - }); - - for (const t of screen.getAllByRole("tab")) { - expect(t).toHaveClass("w-48"); - } - }); + it("renders one role=tab element per tab showing each title", () => { + render(TabBar, { + props: { + tabs: sampleTabs, + activeConversationId: "c1", + onSelect: vi.fn(), + onClose: vi.fn(), + onNewDraft: vi.fn(), + }, + }); + + const tabs = screen.getAllByRole("tab"); + expect(tabs).toHaveLength(sampleTabs.length); + expect(tabs[0]).toHaveTextContent("First"); + expect(tabs[1]).toHaveTextContent("Second"); + expect(tabs[2]).toHaveTextContent("Third"); + }); + + it("applies tab-active to the active tab only", () => { + render(TabBar, { + props: { + tabs: sampleTabs, + activeConversationId: "c2", + onSelect: vi.fn(), + onClose: vi.fn(), + onNewDraft: vi.fn(), + }, + }); + + const tabs = screen.getAllByRole("tab"); + expect(tabs[0]).not.toHaveClass("tab-active"); + expect(tabs[1]).toHaveClass("tab-active"); + expect(tabs[2]).not.toHaveClass("tab-active"); + }); + + it("applies tab-active to New chat button when activeConversationId is null", () => { + render(TabBar, { + props: { + tabs: sampleTabs, + activeConversationId: null, + onSelect: vi.fn(), + onClose: vi.fn(), + onNewDraft: vi.fn(), + }, + }); + + const newChat = screen.getByRole("button", { name: "New chat" }); + expect(newChat).toHaveClass("tab-active"); + }); + + it("calls onSelect with the conversationId when a tab is clicked", async () => { + const onSelect = vi.fn(); + const onClose = vi.fn(); + const user = userEvent.setup(); + + render(TabBar, { + props: { + tabs: sampleTabs, + activeConversationId: "c1", + onSelect, + onClose, + onNewDraft: vi.fn(), + }, + }); + + const tabs = screen.getAllByRole("tab"); + const secondTab = tabs[1]; + if (!secondTab) throw new Error("second tab not found"); + await user.click(secondTab); + + expect(onSelect).toHaveBeenCalledTimes(1); + expect(onSelect).toHaveBeenCalledWith("c2"); + expect(onClose).not.toHaveBeenCalled(); + }); + + it("calls onClose when the close button is clicked and does not call onSelect", async () => { + const onSelect = vi.fn(); + const onClose = vi.fn(); + const user = userEvent.setup(); + + render(TabBar, { + props: { + tabs: sampleTabs, + activeConversationId: "c1", + onSelect, + onClose, + onNewDraft: vi.fn(), + }, + }); + + const closeButtons = screen.getAllByRole("button", { name: "Close tab" }); + const firstClose = closeButtons[0]; + if (!firstClose) throw new Error("first close button not found"); + await user.click(firstClose); + + expect(onClose).toHaveBeenCalledTimes(1); + expect(onClose).toHaveBeenCalledWith("c1"); + expect(onSelect).not.toHaveBeenCalled(); + }); + + it("calls onNewDraft when the New chat button is clicked", async () => { + const onNewDraft = vi.fn(); + const user = userEvent.setup(); + + render(TabBar, { + props: { + tabs: sampleTabs, + activeConversationId: "c1", + onSelect: vi.fn(), + onClose: vi.fn(), + onNewDraft, + }, + }); + + const newChat = screen.getByRole("button", { name: "New chat" }); + await user.click(newChat); + + expect(onNewDraft).toHaveBeenCalledTimes(1); + }); + + it("the New chat button has the sticky class", () => { + render(TabBar, { + props: { + tabs: sampleTabs, + activeConversationId: "c1", + onSelect: vi.fn(), + onClose: vi.fn(), + onNewDraft: vi.fn(), + }, + }); + + const newChat = screen.getByRole("button", { name: "New chat" }); + expect(newChat).toHaveClass("sticky"); + }); + + it("shows visible 'New Chat' text when activeConversationId is null", () => { + render(TabBar, { + props: { + tabs: sampleTabs, + activeConversationId: null, + onSelect: vi.fn(), + onClose: vi.fn(), + onNewDraft: vi.fn(), + }, + }); + + const newChat = screen.getByRole("button", { name: "New chat" }); + expect(newChat).toHaveTextContent("New Chat"); + }); + + it("does not show 'New Chat' text when a real tab is active", () => { + render(TabBar, { + props: { + tabs: sampleTabs, + activeConversationId: "c1", + onSelect: vi.fn(), + onClose: vi.fn(), + onNewDraft: vi.fn(), + }, + }); + + const newChat = screen.getByRole("button", { name: "New chat" }); + expect(newChat).not.toHaveTextContent("New Chat"); + }); + + it("renders a short-handle tab ID badge (shortest unique prefix) per tab", () => { + const tabs: readonly Tab[] = [ + { conversationId: "3f9a1b2c-1111", model: "m", title: "Alpha", workspaceId: "default" }, + { conversationId: "7c2db4e5-2222", model: "m", title: "Beta", workspaceId: "default" }, + ]; + render(TabBar, { + props: { + tabs, + activeConversationId: "3f9a1b2c-1111", + onSelect: vi.fn(), + onClose: vi.fn(), + onNewDraft: vi.fn(), + }, + }); + + expect(screen.getByText("3f9a")).toBeInTheDocument(); + expect(screen.getByText("7c2d")).toBeInTheDocument(); + }); + + it("renders fixed-width tabs", () => { + render(TabBar, { + props: { + tabs: sampleTabs, + activeConversationId: "c1", + onSelect: vi.fn(), + onClose: vi.fn(), + onNewDraft: vi.fn(), + }, + }); + + for (const t of screen.getAllByRole("tab")) { + expect(t).toHaveClass("w-48"); + } + }); }); |
