1import { EnvironmentId } from "@t3tools/contracts";
2import { AsyncResult, Atom, AtomRegistry } from "effect/reactivity";
3import { describe, expect, it, vi } from "vite-plus/test";
4
5import { createVcsStatusRevalidationAtomFamily } from "./vcsStatusRevalidation.ts";
6
7const environmentId = EnvironmentId.make("environment-1");
8
9function setup(options: { readonly connected?: boolean; readonly wake?: boolean }) {
10 const connectedAtom = Atom.make(options.connected ?? false);
11 const wakes = new Set<() => void>();
12 const run = vi.fn(async () => AsyncResult.success(null));
13 const family = createVcsStatusRevalidationAtomFamily({
14 refreshStatus: { label: "refresh-status", run },
15 ...(options.connected === undefined ? {} : { connected: () => connectedAtom }),
16 ...(options.wake
17 ? {
18 subscribeWake: (wake: () => void) => {
19 wakes.add(wake);
20 return () => wakes.delete(wake);
21 },
22 wakeDebounceMs: 250,
23 }
24 : {}),
25 });
26 const registry = AtomRegistry.make();
27 const wake = () => {
28 for (const listener of wakes) listener();
29 };
30 return { registry, family, connectedAtom, run, wakes, wake };
31}
32
33describe("createVcsStatusRevalidationAtomFamily", () => {
34 it("refreshes once per connection, shared by every subscriber, and again on reconnect", () => {
35 const { registry, family, connectedAtom, run } = setup({ connected: true });
36 const target = { environmentId, cwd: "/repo" };
37 const first = registry.mount(family(target));
38 const second = registry.mount(family({ environmentId, cwd: "/repo" }));
39 expect(run).toHaveBeenCalledTimes(1);
40 expect(run).toHaveBeenCalledWith(expect.anything(), { environmentId, input: { cwd: "/repo" } });
41
42 registry.set(connectedAtom, false);
43 expect(run).toHaveBeenCalledTimes(1);
44 registry.set(connectedAtom, true);
45 expect(run).toHaveBeenCalledTimes(2);
46
47 registry.mount(family({ environmentId, cwd: "/other" }))();
48 expect(run).toHaveBeenCalledTimes(3);
49 first();
50 second();
51 });
52
53 it("waits for the connection before the first refresh", () => {
54 const { registry, family, connectedAtom, run } = setup({ connected: false });
55 const unmount = registry.mount(family({ environmentId, cwd: "/repo" }));
56 expect(run).not.toHaveBeenCalled();
57 registry.set(connectedAtom, true);
58 expect(run).toHaveBeenCalledTimes(1);
59 unmount();
60 });
61
62 it("debounces wake signals and stops listening with the last subscriber", () => {
63 vi.useFakeTimers();
64 try {
65 const { registry, family, run, wakes, wake } = setup({ wake: true });
66 const unmount = registry.mount(family({ environmentId, cwd: "/repo" }));
67 expect(run).not.toHaveBeenCalled();
68
69 wake();
70 vi.advanceTimersByTime(100);
71 wake();
72 vi.advanceTimersByTime(249);
73 expect(run).not.toHaveBeenCalled();
74 vi.advanceTimersByTime(1);
75 expect(run).toHaveBeenCalledTimes(1);
76
77 wake();
78 unmount();
79 vi.runAllTimers();
80 expect(run).toHaveBeenCalledTimes(1);
81 expect(wakes.size).toBe(0);
82 } finally {
83 vi.useRealTimers();
84 }
85 });
86
87 it("does nothing for an idle target", () => {
88 const { registry, family, run, wakes } = setup({ connected: true, wake: true });
89 registry.mount(family(null))();
90 expect(run).not.toHaveBeenCalled();
91 expect(wakes.size).toBe(0);
92 });
93});