import { afterEach, describe, expect, it, rs } from "@rstest/core"; import { QueryClient, QueryClientProvider, useMutation, } from "@tanstack/react-query"; import { cleanup, fireEvent, render, screen, waitFor, } from "@testing-library/react"; import { toast } from "sonner"; import { ThreadDeleteDialogProvider, useThreadDeleteDialog, } from "@/components/workspace/thread-delete-dialog"; import { DEFAULT_LOCALE } from "@/core/i18n"; import { I18nProvider } from "@/core/i18n/context"; const { deleteThread } = rs.hoisted(() => ({ deleteThread: rs.fn() })); rs.mock("next/navigation", () => ({ useRouter: () => ({ replace: rs.fn() }), usePathname: () => "/workspace/chats/new", useParams: () => ({}), })); rs.mock("sonner", () => ({ toast: { error: rs.fn() } })); rs.mock("@/components/workspace/chats/use-thread-chat", () => ({ resetThreadChatAfterDelete: rs.fn(), })); rs.mock("@/core/threads/hooks", () => ({ useDeleteThread: () => useMutation({ mutationFn: deleteThread }), })); function Trigger() { const requestDelete = useThreadDeleteDialog(); return ( ); } afterEach(() => { cleanup(); rs.restoreAllMocks(); }); describe("thread deletion failure feedback", () => { for (const [name, error, message] of [ ["specific error", new Error("Permission denied"), "Permission denied"], ["empty error", new Error(""), "Failed to delete chat. Please try again."], ["non-Error rejection", null, "Failed to delete chat. Please try again."], ] as const) { it(`reports ${name} and restores Cancel focus`, async () => { deleteThread.mockRejectedValueOnce(error); const log = rs .spyOn(console, "error") .mockImplementation(() => undefined); const client = new QueryClient({ defaultOptions: { mutations: { retry: false } }, }); render( , ); fireEvent.click(screen.getByRole("button", { name: "Open deletion" })); const cancel = await screen.findByRole("button", { name: "Cancel", }); const del = screen.getByRole("button", { name: "Delete" }); del.focus(); fireEvent.click(del); await waitFor(() => expect(toast.error).toHaveBeenCalledWith(message)); await waitFor(() => expect(document.activeElement).toBe(cancel)); expect(log).toHaveBeenCalledWith("Failed to delete chat:", error); expect(screen.getByRole("dialog")).not.toBeNull(); fireEvent.click(cancel); await waitFor(() => expect(screen.queryByRole("dialog")).toBeNull()); client.clear(); }); } });