Skip to content
File

Blob: tests/client/hooks/use-sync.dom.test.tsx

typescript72 lines
1import { act } from "react";
2import { createRoot, type Root } from "react-dom/client";
3import { afterEach, describe, expect, it } from "vitest";
4import type { Awareness } from "y-protocols/awareness";
5import { useAwareness, type AwarenessState } from "@/client/hooks/use-sync";
6 
7class FakeAwareness {
8 private states = new Map<number, AwarenessState>();
9 private listeners = new Set<() => void>();
10 
11 getStates() {
12 return this.states;
13 }
14 
15 on(event: "change", listener: () => void) {
16 if (event === "change") this.listeners.add(listener);
17 }
18 
19 off(event: "change", listener: () => void) {
20 if (event === "change") this.listeners.delete(listener);
21 }
22 
23 setState(clientId: number, state: AwarenessState, emit = true) {
24 this.states = new Map(this.states).set(clientId, state);
25 if (emit) {
26 for (const listener of this.listeners) listener();
27 }
28 }
29}
30 
31afterEach(() => {
32 document.body.innerHTML = "";
33});
34 
35describe("useAwareness", () => {
36 it("reads the current external state even when a change happened before subscription", async () => {
37 const awareness = new FakeAwareness();
38 awareness.setState(2, { user: { userId: "user-a" } }, false);
39 
40 function Probe({ tick }: { tick: number }) {
41 const states = useAwareness(awareness as unknown as Awareness);
42 return <output>{`${tick}:${states.get(2)?.user?.userId ?? "missing"}`}</output>;
43 }
44 
45 const host = document.createElement("div");
46 document.body.appendChild(host);
47 let root: Root | null = createRoot(host);
48 
49 try {
50 await act(async () => {
51 root!.render(<Probe tick={0} />);
52 });
53 
54 expect(host.textContent).toBe("0:user-a");
55 
56 awareness.setState(2, { user: { userId: "user-b" } }, false);
57 
58 await act(async () => {
59 root!.render(<Probe tick={1} />);
60 });
61 
62 expect(host.textContent).toBe("1:user-b");
63 } finally {
64 await act(async () => {
65 root?.unmount();
66 });
67 root = null;
68 host.remove();
69 }
70 });
71});