| 1 | // @vitest-environment jsdom |
| 2 | import { |
| 3 | EnvironmentId, |
| 4 | ProviderDriverKind, |
| 5 | ProviderInstanceId, |
| 6 | type ServerProvider, |
| 7 | } from "@t3tools/contracts"; |
| 8 | import { AsyncResult, Atom } from "effect/reactivity"; |
| 9 | import { act } from "react"; |
| 10 | import { createRoot, type Root } from "react-dom/client"; |
| 11 | import { afterEach, beforeEach, expect, it, vi } from "vite-plus/test"; |
| 12 | |
| 13 | import { appAtomRegistry, AppAtomRegistryProvider } from "~/rpc/atomRegistry"; |
| 14 | |
| 15 | const mocks = vi.hoisted(() => ({ |
| 16 | environments: [] as Array<{ |
| 17 | environmentId: EnvironmentId; |
| 18 | label: string; |
| 19 | connection: { phase: "connected" }; |
| 20 | serverConfig: { providers: ServerProvider[] }; |
| 21 | }>, |
| 22 | permissionAtom: vi.fn(), |
| 23 | update: vi.fn(), |
| 24 | })); |
| 25 | vi.mock("~/state/environments", () => ({ |
| 26 | useEnvironments: () => ({ environments: mocks.environments }), |
| 27 | })); |
| 28 | vi.mock("~/state/server", () => ({ |
| 29 | serverEnvironment: { updateProvider: { permissionAtom: mocks.permissionAtom } }, |
| 30 | })); |
| 31 | vi.mock("~/state/use-atom-command", () => ({ useAtomCommand: () => mocks.update })); |
| 32 | vi.mock("./ui/toast", () => ({ toastManager: { add: vi.fn() }, stackedThreadToast: vi.fn() })); |
| 33 | |
| 34 | import { useProviderUpdates } from "./ProviderUpdatesAction"; |
| 35 | |
| 36 | const home = EnvironmentId.make("home"); |
| 37 | const work = EnvironmentId.make("work"); |
| 38 | const homeAllowed = Atom.make(false).pipe(Atom.keepAlive); |
| 39 | const workAllowed = Atom.make(false).pipe(Atom.keepAlive); |
| 40 | let root: Root; |
| 41 | let container: HTMLDivElement; |
| 42 | |
| 43 | function Updates() { |
| 44 | const { machines, updateAll } = useProviderUpdates(); |
| 45 | return machines.length > 0 ? ( |
| 46 | <button onClick={() => void updateAll({ quiet: true })}>Update all</button> |
| 47 | ) : null; |
| 48 | } |
| 49 | |
| 50 | beforeEach(() => { |
| 51 | const provider: ServerProvider = { |
| 52 | instanceId: ProviderInstanceId.make("codex-home"), |
| 53 | driver: ProviderDriverKind.make("codex"), |
| 54 | enabled: true, |
| 55 | installed: true, |
| 56 | version: "1.0.0", |
| 57 | status: "ready", |
| 58 | auth: { status: "authenticated" }, |
| 59 | checkedAt: "2026-10-15T12:00:00Z", |
| 60 | models: [], |
| 61 | slashCommands: [], |
| 62 | skills: [], |
| 63 | versionAdvisory: { |
| 64 | status: "behind_latest", |
| 65 | currentVersion: "1.0.0", |
| 66 | latestVersion: "1.1.0", |
| 67 | updateCommand: "npm install -g provider", |
| 68 | canUpdate: true, |
| 69 | checkedAt: "2026-10-15T12:00:00Z", |
| 70 | message: "Update available.", |
| 71 | }, |
| 72 | }; |
| 73 | mocks.environments = [home, work].map((environmentId) => ({ |
| 74 | environmentId, |
| 75 | label: environmentId, |
| 76 | connection: { phase: "connected" }, |
| 77 | serverConfig: { providers: [provider] }, |
| 78 | })); |
| 79 | mocks.permissionAtom.mockImplementation((id: EnvironmentId) => |
| 80 | id === home ? homeAllowed : workAllowed, |
| 81 | ); |
| 82 | mocks.update.mockReset().mockResolvedValue(AsyncResult.success(undefined)); |
| 83 | appAtomRegistry.set(homeAllowed, false); |
| 84 | appAtomRegistry.set(workAllowed, false); |
| 85 | container = document.createElement("div"); |
| 86 | document.body.append(container); |
| 87 | root = createRoot(container); |
| 88 | Object.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true }); |
| 89 | }); |
| 90 | |
| 91 | afterEach(async () => { |
| 92 | await act(async () => root.unmount()); |
| 93 | container.remove(); |
| 94 | }); |
| 95 | |
| 96 | it("offers and updates only permitted machines, reacting to permission changes", async () => { |
| 97 | await act(async () => |
| 98 | root.render( |
| 99 | <AppAtomRegistryProvider> |
| 100 | <Updates /> |
| 101 | </AppAtomRegistryProvider>, |
| 102 | ), |
| 103 | ); |
| 104 | expect(container.querySelector("button")).toBeNull(); |
| 105 | |
| 106 | await act(async () => appAtomRegistry.set(workAllowed, true)); |
| 107 | expect(container.querySelector("button")).not.toBeNull(); |
| 108 | await act(async () => container.querySelector("button")?.click()); |
| 109 | expect(mocks.update).toHaveBeenCalledExactlyOnceWith({ |
| 110 | environmentId: work, |
| 111 | input: { provider: "codex", instanceId: "codex-home" }, |
| 112 | }); |
| 113 | |
| 114 | await act(async () => appAtomRegistry.set(workAllowed, false)); |
| 115 | expect(container.querySelector("button")).toBeNull(); |
| 116 | }); |