| 1 | import { describe, expect, it, vi } from "vite-plus/test"; |
| 2 | |
| 3 | import { registerThreadDismissal, withThreadDismissal } from "./thread-dismissal"; |
| 4 | |
| 5 | describe("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 | }); |