Skip to content
Source
Sign inSign up

workspace-connection-atoms.test.ts

98 lines3.6 KB

1import { describe, expect, it } from "@effect/vitest";
2import {
3 PrimaryConnectionTarget,
4 type EnvironmentPresentation,
5 type NetworkStatus,
6} from "@t3tools/client-runtime/connection";
7import type { EnvironmentCatalogState } from "@t3tools/client-runtime/state/connections";
8import type { EnvironmentShellSummary } from "@t3tools/client-runtime/state/shell";
9import { EnvironmentId, type ServerConfig } from "@t3tools/contracts";
10import * as Option from "effect/Option";
11import { Atom, AtomRegistry } from "effect/reactivity";
12​
13import { createWorkspaceConnectionAtoms } from "./workspace-connection-atoms";
14import { projectWorkspaceState } from "./workspaceModel";
15import { projectEnvironmentConnectionSummary as projectWorkspaceEnvironment } from "@t3tools/client-runtime/state/presentation";
16​
17const ID = EnvironmentId.make("environment-1");
18function presentation(): EnvironmentPresentation {
19 return {
20 entry: {
21 target: new PrimaryConnectionTarget({
22 environmentId: ID,
23 label: "Mac",
24 httpBaseUrl: "https://example.test",
25 wsBaseUrl: "wss://example.test",
26 }),
27 enabled: true,
28 profile: Option.none(),
29 },
30 connection: { phase: "connected", error: null, traceId: null },
31 serverConfig: null,
32 };
34function harness() {
35 const source = Atom.make<EnvironmentPresentation | null>(presentation());
36 const catalog = Atom.make<EnvironmentCatalogState>({
37 isReady: true,
38 entries: new Map([[ID, presentation().entry]]),
39 });
40 const network = Atom.make<NetworkStatus>("online");
41 const atoms = createWorkspaceConnectionAtoms({
42 catalogValueAtom: catalog,
43 networkStatusValueAtom: network,
44 presentationAtom: () => source,
45 });
46 const registry = AtomRegistry.make();
47 return { source, catalog, network, registry, ...atoms };
49​
50describe("workspace connection subscriptions", () => {
51 it("keeps connection consumers stable across shell and provider updates", () => {
52 const h = harness();
53 const shell = Atom.make<EnvironmentShellSummary>({
54 hasSnapshot: true,
55 hasSynchronizingShell: false,
56 firstError: null,
57 });
58 const broadState = Atom.make((get) =>
59 projectWorkspaceState({
60 isReady: get(h.catalog).isReady,
61 networkStatus: get(h.network),
62 environments: [projectWorkspaceEnvironment(ID, get(h.source)!)],
63 shellSummary: get(shell),
64 hasSyncingConnectedEnvironment: false,
65 }),
66 );
67 const initial = h.registry.get(h.stateAtom);
68 const initialEnvironments = h.registry.get(h.environmentsAtom);
69 let broadChanges = 0;
70 let connectionChanges = 0;
71 const stopBroad = h.registry.subscribe(broadState, () => broadChanges++);
72 const stopNarrow = h.registry.subscribe(h.stateAtom, () => connectionChanges++);
73 try {
74 for (let index = 0; index < 20; index++) {
75 h.registry.set(shell, {
76 ...h.registry.get(shell),
77 hasSynchronizingShell: index % 2 === 0,
78 });
79 h.registry.get(broadState);
80 h.registry.get(h.stateAtom);
81 }
82 expect(broadChanges).toBe(20);
83 expect(connectionChanges).toBe(0);
84 for (let index = 0; index < 4; index++) {
85 const config = { cwd: `/workspace-${index}` } as ServerConfig;
86 h.registry.set(h.source, { ...presentation(), serverConfig: config });
87 expect(h.registry.get(h.source)?.serverConfig).toBe(config);
88 expect(h.registry.get(h.stateAtom)).toBe(initial);
89 expect(h.registry.get(h.environmentsAtom)).toBe(initialEnvironments);
90 }
91 expect(connectionChanges).toBe(0);
92 } finally {
93 stopBroad();
94 stopNarrow();
95 h.registry.dispose();
96 }
97 });
98});