theo-agent-dashboard

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

TopicItem.test.tsx (4059B)


      1 import { describe, it, expect, vi, beforeEach } from "vitest";
      2 import { render, screen, fireEvent } from "@testing-library/react";
      3 import { TopicItem } from "./TopicItem";
      4 import { useTopicStore } from "../../store/topic";
      5 
      6 const mockTopic = {
      7   id: "t1",
      8   name: "Work",
      9   color: "#6366f1",
     10   sort_order: 0,
     11   created_at: Date.now(),
     12   session_count: 3,
     13 };
     14 
     15 beforeEach(() => {
     16   useTopicStore.setState({
     17     topics: [mockTopic],
     18     selectedTopicId: null,
     19   });
     20   vi.restoreAllMocks();
     21 });
     22 
     23 describe("TopicItem", () => {
     24   it("renders topic name", () => {
     25     render(<TopicItem topic={mockTopic} isSelected={false} onSelect={vi.fn()} />);
     26     expect(screen.getByText("Work")).toBeInTheDocument();
     27   });
     28 
     29   it("renders session count", () => {
     30     render(<TopicItem topic={mockTopic} isSelected={false} onSelect={vi.fn()} />);
     31     expect(screen.getByText("3")).toBeInTheDocument();
     32   });
     33 
     34   it("renders color indicator", () => {
     35     const { container } = render(
     36       <TopicItem topic={mockTopic} isSelected={false} onSelect={vi.fn()} />,
     37     );
     38     const colorDot = container.querySelector("[style*='background-color']");
     39     expect(colorDot).toBeInTheDocument();
     40   });
     41 
     42   it("calls onSelect when clicked", () => {
     43     const onSelect = vi.fn();
     44     render(<TopicItem topic={mockTopic} isSelected={false} onSelect={onSelect} />);
     45     fireEvent.click(screen.getByText("Work"));
     46     expect(onSelect).toHaveBeenCalled();
     47   });
     48 
     49   it("applies selected styling when isSelected is true", () => {
     50     const { container } = render(
     51       <TopicItem topic={mockTopic} isSelected={true} onSelect={vi.fn()} />,
     52     );
     53     const wrapper = container.firstElementChild;
     54     expect(wrapper?.className).toContain("bg-gray-700");
     55     expect(wrapper?.className).toContain("text-white");
     56   });
     57 
     58   it("applies unselected styling when isSelected is false", () => {
     59     const { container } = render(
     60       <TopicItem topic={mockTopic} isSelected={false} onSelect={vi.fn()} />,
     61     );
     62     const wrapper = container.firstElementChild;
     63     expect(wrapper?.className).toContain("text-gray-400");
     64   });
     65 
     66   it("opens context menu on right click", () => {
     67     render(<TopicItem topic={mockTopic} isSelected={false} onSelect={vi.fn()} />);
     68     fireEvent.contextMenu(screen.getByText("Work"));
     69     expect(screen.getByText("Rename")).toBeInTheDocument();
     70     expect(screen.getByText("Delete")).toBeInTheDocument();
     71   });
     72 
     73   it("clicking Rename enables editing mode", () => {
     74     render(<TopicItem topic={mockTopic} isSelected={false} onSelect={vi.fn()} />);
     75     fireEvent.contextMenu(screen.getByText("Work"));
     76     fireEvent.click(screen.getByText("Rename"));
     77     const input = screen.getByDisplayValue("Work");
     78     expect(input).toBeInTheDocument();
     79   });
     80 
     81   it("clicking Delete calls deleteTopic", async () => {
     82     vi.spyOn(useTopicStore.getState(), "deleteTopic").mockResolvedValue(undefined);
     83     render(<TopicItem topic={mockTopic} isSelected={false} onSelect={vi.fn()} />);
     84     fireEvent.contextMenu(screen.getByText("Work"));
     85     fireEvent.click(screen.getByText("Delete"));
     86     expect(useTopicStore.getState().deleteTopic).toHaveBeenCalledWith("t1");
     87   });
     88 
     89   it("clicking a color button calls updateTopic with new color", async () => {
     90     vi.spyOn(useTopicStore.getState(), "updateTopic").mockResolvedValue(undefined);
     91     render(<TopicItem topic={mockTopic} isSelected={false} onSelect={vi.fn()} />);
     92     fireEvent.contextMenu(screen.getByText("Work"));
     93 
     94     const colorButtons = screen.getAllByRole("button").filter(
     95       (btn) => btn.className.includes("rounded-full") && btn.style.backgroundColor,
     96     );
     97     expect(colorButtons.length).toBeGreaterThan(0);
     98     fireEvent.click(colorButtons[0]);
     99     expect(useTopicStore.getState().updateTopic).toHaveBeenCalledWith("t1", {
    100       color: expect.any(String),
    101     });
    102   });
    103 
    104   it("renders session_count as 0 when null", () => {
    105     const topic = { ...mockTopic, session_count: null };
    106     render(<TopicItem topic={topic} isSelected={false} onSelect={vi.fn()} />);
    107     expect(screen.getByText("0")).toBeInTheDocument();
    108   });
    109 });