106 lines · 3.2 KB · TypeScript
RawDownload
import { EnvironmentId, ThreadId } from "@t3tools/contracts";import { afterEach, describe, expect, it, vi } from "vite-plus/test"; import {  navigateAfterThreadDeletion,  requestThreadUnpinConfirmation,  ThreadArchiveBlockedError,} from "./useThreadActions";import { toastManager } from "../components/ui/toast"; describe("navigateAfterThreadDeletion", () => {  afterEach(() => vi.restoreAllMocks());   it("reports a rejected navigation without failing the completed deletion", async () => {    const addToast = vi.spyOn(toastManager, "add").mockReturnValue("navigation-error");     await expect(      navigateAfterThreadDeletion(() => Promise.reject(new Error("route unavailable"))),    ).resolves.toBeUndefined();     expect(addToast).toHaveBeenCalledOnce();    expect(addToast).toHaveBeenCalledWith(      expect.objectContaining({        title: "Thread deleted, but navigation failed",        description: "route unavailable",      }),    );  });   it("does not report an error after successful navigation", async () => {    const addToast = vi.spyOn(toastManager, "add");     await navigateAfterThreadDeletion(() => Promise.resolve());     expect(addToast).not.toHaveBeenCalled();  });}); describe("ThreadArchiveBlockedError", () => {  it("keeps the blocked thread context with the fixed message", () => {    const error = new ThreadArchiveBlockedError({      environmentId: EnvironmentId.make("environment-1"),      threadId: ThreadId.make("thread-1"),    });     expect(error).toMatchObject({      environmentId: "environment-1",      threadId: "thread-1",    });    expect(error.message).toBe("Cannot archive a running thread.");  });}); describe("requestThreadUnpinConfirmation", () => {  it("skips the dialog when confirmation is disabled", async () => {    let callCount = 0;    const result = await requestThreadUnpinConfirmation({      enabled: false,      title: "Pinned thread",      confirm: async () => {        callCount += 1;        return false;      },    });     expect(result).toMatchObject({ _tag: "Success", value: true });    expect(callCount).toBe(0);  });   it("degrades gracefully when dialogs are unavailable", async () => {    const result = await requestThreadUnpinConfirmation({      enabled: true,      title: "Pinned thread",      confirm: null,    });     expect(result).toMatchObject({ _tag: "Success", value: true });  });   it("uses the thread title and returns the user's decision", async () => {    let message = "";    const result = await requestThreadUnpinConfirmation({      enabled: true,      title: "Release prep",      confirm: async (nextMessage) => {        message = nextMessage;        return false;      },    });     expect(message).toBe(      'Unpin thread "Release prep"?\nThis will move the thread out of your pinned section.',    );    expect(result).toMatchObject({ _tag: "Success", value: false });  });   it("keeps dialog failures observable", async () => {    const result = await requestThreadUnpinConfirmation({      enabled: true,      title: "Pinned thread",      confirm: () => Promise.reject(new Error("dialog unavailable")),    });     expect(result._tag).toBe("Failure");  });});