import { render, screen } from "@testing-library/react" import userEvent from "@testing-library/user-event" import { beforeEach, describe, expect, it, vi } from "vitest" import { ChatList } from "../../components/chat-list" import type { ChatListItem } from "../../types/chat" // Mock UI components vi.mock("@/components/ui/button", () => ({ Button: ({ children, onClick, disabled, ...props }: any) => ( ), })) vi.mock("@/components/ui/scroll-area", () => ({ ScrollArea: ({ children }: any) =>
{children}
, })) describe("ChatList Component", () => { const mockSessions: ChatListItem[] = [ { id: "1", title: "Как добавить эффект размытия?", lastMessageAt: new Date(), messageCount: 5, }, { id: "2", title: "Помоги с настройкой экспорта", lastMessageAt: new Date(Date.now() - 86400000), // Yesterday messageCount: 12, }, { id: "3", title: "Объясни работу с таймлайном", lastMessageAt: new Date(Date.now() - 172800000), // 2 days ago messageCount: 8, }, { id: "4", title: "Четвертый чат (скрыт по умолчанию)", lastMessageAt: new Date(Date.now() - 259200000), // 3 days ago messageCount: 3, }, ] const mockHandlers = { onSelectSession: vi.fn(), onDeleteSession: vi.fn(), onCopySession: vi.fn(), } const user = userEvent.setup() beforeEach(() => { vi.clearAllMocks() }) describe("Отображение", () => { it("должен отображать заголовок", () => { render() expect(screen.getByText("Previous Threads")).toBeInTheDocument() }) it("должен отображать только первые 3 чата по умолчанию", () => { render() expect(screen.getByText("Как добавить эффект размытия?")).toBeInTheDocument() expect(screen.getByText("Помоги с настройкой экспорта")).toBeInTheDocument() expect(screen.getByText("Объясни работу с таймлайном")).toBeInTheDocument() expect(screen.queryByText("Четвертый чат (скрыт по умолчанию)")).not.toBeInTheDocument() }) it("должен показывать кнопку 'Show more' если есть скрытые чаты", () => { render() expect(screen.getByText("Show 1 more...")).toBeInTheDocument() }) it("должен показывать все чаты после клика на 'Show more'", async () => { render() await user.click(screen.getByText("Show 1 more...")) expect(screen.getByText("Четвертый чат (скрыт по умолчанию)")).toBeInTheDocument() expect(screen.queryByText("Show 1 more...")).not.toBeInTheDocument() }) it("должен подсвечивать текущий чат", () => { render() const currentChat = screen.getByText("Помоги с настройкой экспорта").closest("div.group") expect(currentChat).toHaveClass("bg-muted") }) }) describe("Создание нового чата", () => { it("должен показывать спиннер при создании нового чата", () => { render() expect(screen.getByText("составь план рефакторинга")).toBeInTheDocument() expect(screen.getByTestId("loader2-icon")).toBeInTheDocument() expect(screen.getByTestId("loader2-icon")).toHaveClass("animate-spin") }) it("спиннер должен быть в начале списка", () => { render() const allItems = screen .getAllByRole("generic") .filter( (el) => el.textContent?.includes("составь план рефакторинга") || el.textContent?.includes("Как добавить эффект размытия?"), ) expect(allItems[0]).toHaveTextContent("составь план рефакторинга") }) }) describe("Взаимодействие", () => { it("должен вызывать onSelectSession при клике на чат", async () => { render() const chat = screen.getByText("Как добавить эффект размытия?").closest("div.group")! await user.click(chat) expect(mockHandlers.onSelectSession).toHaveBeenCalledWith("1") }) it("должен показывать кнопки действий при наведении", async () => { render() const chat = screen.getByText("Как добавить эффект размытия?").closest("div.group")! // До наведения кнопки не видны expect(screen.queryByTestId("copy-icon")).not.toBeInTheDocument() expect(screen.queryByTestId("trash2-icon")).not.toBeInTheDocument() // После наведения кнопки появляются await user.hover(chat) expect(screen.getByTestId("copy-icon")).toBeInTheDocument() expect(screen.getByTestId("trash2-icon")).toBeInTheDocument() }) it.skip("должен вызывать onCopySession при клике на кнопку копирования", async () => { render() const chat = screen.getByText("Как добавить эффект размытия?").closest("div.group")! await user.hover(chat) const copyButton = screen.getByTestId("copy-icon").closest("button")! expect(copyButton).toBeInTheDocument() // Создадим событие с stopPropagation const mockEvent = { stopPropagation: vi.fn() } // Вызовем onClick напрямую const onClickProp = copyButton.onclick || copyButton.getAttribute("onclick") if (typeof onClickProp === "function") { onClickProp.call(copyButton, mockEvent as any) } // Альтернативный вариант - просто кликнуть await user.click(copyButton) expect(mockHandlers.onCopySession).toHaveBeenCalledWith("1") expect(mockHandlers.onSelectSession).not.toHaveBeenCalled() }) it.skip("должен вызывать onDeleteSession при клике на кнопку удаления", async () => { render() const chat = screen.getByText("Как добавить эффект размытия?").closest("div.group")! await user.hover(chat) const deleteButton = screen.getByTestId("trash2-icon").closest("button")! await user.click(deleteButton) expect(mockHandlers.onDeleteSession).toHaveBeenCalledWith("1") expect(mockHandlers.onSelectSession).not.toHaveBeenCalled() }) }) describe("Форматирование даты", () => { it("должен показывать 'Today' для сегодняшних чатов", () => { render() const chat = screen.getByText("Как добавить эффект размытия?").closest("div.group")! expect(chat).toHaveTextContent("Today") }) it("должен показывать 'Yesterday' для вчерашних чатов", () => { render() const chat = screen.getByText("Помоги с настройкой экспорта").closest("div.group")! expect(chat).toHaveTextContent("Yesterday") }) it("должен показывать количество дней для недавних чатов", () => { render() const chat = screen.getByText("Объясни работу с таймлайном").closest("div.group")! expect(chat).toHaveTextContent("2 days ago") }) }) describe("Количество сообщений", () => { it("должен показывать количество сообщений когда не наведено", () => { render() expect(screen.getByText("5 messages")).toBeInTheDocument() }) it("должен скрывать количество сообщений при наведении", async () => { render() const chat = screen.getByText("Как добавить эффект размытия?").closest("div.group")! await user.hover(chat) expect(screen.queryByText("5 messages")).not.toBeInTheDocument() }) }) })