| 1 | import type { EnvironmentId, ScopedThreadRef, ThreadId } from "@t3tools/contracts"; |
| 2 | import { act } from "react"; |
| 3 | import { create, type ReactTestRenderer } from "react-test-renderer"; |
| 4 | import { afterEach, beforeEach, describe, expect, it, vi } from "vite-plus/test"; |
| 5 | |
| 6 | import { useActiveThreadRef } from "./useActiveThreadRef"; |
| 7 | |
| 8 | type ThreadLike = { environmentId: EnvironmentId; id: ThreadId; status: string } | null; |
| 9 | |
| 10 | let renderer: ReactTestRenderer | null = null; |
| 11 | let observed: Array<ScopedThreadRef | null> = []; |
| 12 | |
| 13 | function Probe({ thread }: { thread: ThreadLike }) { |
| 14 | observed.push(useActiveThreadRef(thread)); |
| 15 | return null; |
| 16 | } |
| 17 | |
| 18 | const thread = (id: string, status = "idle"): ThreadLike => ({ |
| 19 | environmentId: "env-1" as EnvironmentId, |
| 20 | id: id as ThreadId, |
| 21 | status, |
| 22 | }); |
| 23 | |
| 24 | async function render(value: ThreadLike) { |
| 25 | await act(() => { |
| 26 | if (renderer) renderer.update(<Probe thread={value} />); |
| 27 | else renderer = create(<Probe thread={value} />); |
| 28 | }); |
| 29 | return observed.at(-1); |
| 30 | } |
| 31 | |
| 32 | beforeEach(() => { |
| 33 | observed = []; |
| 34 | vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true); |
| 35 | }); |
| 36 | |
| 37 | afterEach(async () => { |
| 38 | await act(() => renderer?.unmount()); |
| 39 | renderer = null; |
| 40 | vi.unstubAllGlobals(); |
| 41 | }); |
| 42 | |
| 43 | describe("useActiveThreadRef", () => { |
| 44 | it("keeps the same ref while the thread object is replaced during a run", async () => { |
| 45 | const first = await render(thread("t1", "running")); |
| 46 | const afterUpdate = await render(thread("t1", "waiting")); |
| 47 | |
| 48 | expect(first).toEqual({ environmentId: "env-1", threadId: "t1" }); |
| 49 | expect(afterUpdate).toBe(first); |
| 50 | }); |
| 51 | |
| 52 | it("returns a new ref when the thread changes or goes away", async () => { |
| 53 | const first = await render(thread("t1")); |
| 54 | const switched = await render(thread("t2")); |
| 55 | const gone = await render(null); |
| 56 | |
| 57 | expect(switched).not.toBe(first); |
| 58 | expect(switched).toEqual({ environmentId: "env-1", threadId: "t2" }); |
| 59 | expect(gone).toBeNull(); |
| 60 | }); |
| 61 | }); |