1import { EnvironmentId } from "@t3tools/contracts";
2import { act, useLayoutEffect } from "react";
3import { create, type ReactTestRenderer } from "react-test-renderer";
4import { afterEach, beforeEach, expect, it, vi } from "vite-plus/test";
5
6import { useEnvironmentDisconnectDelay } from "./useEnvironmentDisconnectDelay";
7
8const environmentId = EnvironmentId.make("remote");
9let renderer: ReactTestRenderer;
10let elapsed = false;
11
12function Probe({ unavailableId }: { unavailableId: EnvironmentId | null }) {
13 const value = useEnvironmentDisconnectDelay(unavailableId);
14 useLayoutEffect(() => {
15 elapsed = value;
16 });
17 return null;
18}
19
20beforeEach(() => {
21 vi.useFakeTimers();
22 vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
23 act(() => {
24 renderer = create(<Probe unavailableId={environmentId} />);
25 });
26});
27
28afterEach(() => {
29 act(() => renderer.unmount());
30 vi.useRealTimers();
31 vi.unstubAllGlobals();
32});
33
34it("waits 20 seconds without restarting on renders for the same environment", () => {
35 act(() => vi.advanceTimersByTime(10_000));
36 expect(elapsed).toBe(false);
37 act(() => renderer.update(<Probe unavailableId={environmentId} />));
38 act(() => vi.advanceTimersByTime(9_999));
39 expect(elapsed).toBe(false);
40 act(() => vi.advanceTimersByTime(1));
41 expect(elapsed).toBe(true);
42});
43
44it("cancels a brief outage and starts a fresh delay on the next outage", () => {
45 act(() => vi.advanceTimersByTime(10_000));
46 act(() => renderer.update(<Probe unavailableId={null} />));
47 act(() => vi.advanceTimersByTime(20_000));
48 expect(elapsed).toBe(false);
49 act(() => renderer.update(<Probe unavailableId={environmentId} />));
50 act(() => vi.advanceTimersByTime(19_999));
51 expect(elapsed).toBe(false);
52 act(() => vi.advanceTimersByTime(1));
53 expect(elapsed).toBe(true);
54 act(() => renderer.update(<Probe unavailableId={null} />));
55 expect(elapsed).toBe(false);
56});
57
58it("does not carry elapsed time to another environment", () => {
59 act(() => vi.advanceTimersByTime(20_000));
60 expect(elapsed).toBe(true);
61 act(() => renderer.update(<Probe unavailableId={EnvironmentId.make("another-remote")} />));
62 expect(elapsed).toBe(false);
63 act(() => vi.advanceTimersByTime(20_000));
64 expect(elapsed).toBe(true);
65});