1import { describe, expect, it, vi } from "vite-plus/test";
2
3import { registerThreadDismissal, withThreadDismissal } from "./thread-dismissal";
4
5describe("thread dismissal", () => {
6 it("waits for every visible copy before changing thread state", async () => {
7 const home = Promise.withResolvers<void>();
8 const sidebar = Promise.withResolvers<void>();
9 const restore = vi.fn();
10 const unregisterHome = registerThreadDismissal("env:thread", () => ({
11 finished: home.promise,
12 restore,
13 }));
14 const unregisterSidebar = registerThreadDismissal("env:thread", () => ({
15 finished: sidebar.promise,
16 restore,
17 }));
18 const command = vi.fn(async () => true);
19 try {
20 const result = withThreadDismissal("env:thread", command, Boolean);
21 expect(command).not.toHaveBeenCalled();
22 home.resolve();
23 await home.promise;
24 expect(command).not.toHaveBeenCalled();
25 sidebar.resolve();
26 expect(await result).toBe(true);
27 expect(command).toHaveBeenCalledOnce();
28 expect(restore).not.toHaveBeenCalled();
29 } finally {
30 unregisterHome();
31 unregisterSidebar();
32 }
33 });
34
35 it.each([false, "throw"])(
36 "restores dismissed rows when the command returns %s",
37 async (outcome) => {
38 const restore = vi.fn();
39 const unregister = registerThreadDismissal("env:thread", () => ({
40 finished: Promise.resolve(),
41 restore,
42 }));
43 try {
44 const result = withThreadDismissal(
45 "env:thread",
46 async () => {
47 if (outcome === "throw") throw new Error("Disconnected");
48 return outcome;
49 },
50 Boolean,
51 );
52 if (outcome === "throw") await expect(result).rejects.toThrow("Disconnected");
53 else expect(await result).toBe(false);
54 expect(restore).toHaveBeenCalledOnce();
55 } finally {
56 unregister();
57 }
58 },
59 );
60
61 it("does not animate another environment or a recycled row", async () => {
62 const dismiss = vi.fn(() => ({ finished: Promise.resolve(), restore: vi.fn() }));
63 const unregisterOther = registerThreadDismissal("other:thread", dismiss);
64 const unregisterRecycled = registerThreadDismissal("env:thread", dismiss);
65 unregisterRecycled();
66 try {
67 expect(await withThreadDismissal("env:thread", async () => true, Boolean)).toBe(true);
68 expect(dismiss).not.toHaveBeenCalled();
69 } finally {
70 unregisterOther();
71 }
72 });
73});