Open History to see the last commit
1import { Atom, AsyncResult } from "effect/reactivity";
2import * as Cause from "effect/Cause";
3import type { AtomCommandResult } from "@t3tools/client-runtime/state/runtime";
4import { useState } from "react";
5import { page, userEvent } from "vite-plus/test/browser";
6import { describe, expect, it, vi } from "vite-plus/test";
7
8import { render, stubGlobal } from "../../../test/render";
9import { AppAtomRegistryProvider } from "../../rpc/atomRegistry";
10
11const mocks = vi.hoisted(() => ({
12 connectSshEnvironment: vi.fn<() => Promise<AtomCommandResult<void, Error>>>(async () =>
13 AsyncResult.success(undefined),
14 ),
15 refresh: () => {},
16}));
17
18vi.mock(import("../../state/use-atom-command"), async (original) => ({
19 ...(await original()),
20 useAtomCommand: ((command: unknown) => command) as never,
21}));
22vi.mock(import("~/connection/onboarding"), async (original) => ({
23 ...(await original()),
24 connectSshEnvironment: mocks.connectSshEnvironment as never,
25}));
26vi.mock(import("~/state/query"), async (original) => ({
27 ...(await original()),
28 useEnvironmentQuery: (() => ({
29 data: [],
30 isPending: false,
31 error: null,
32 refresh: mocks.refresh,
33 })) as never,
34}));
35vi.mock(import("~/state/environments"), async (original) => ({
36 ...(await original()),
37 useRelayEnvironmentDiscovery: (() => ({ environments: new Map() })) as never,
38}));
39vi.mock(import("~/state/server"), async (original) => ({
40 ...(await original()),
41 primaryServerKeybindingsAtom: Atom.make([]) as never,
42}));
43
44import { AddEnvironmentDialog } from "./AddEnvironmentDialog";
45
46function Owner() {
47 const [open, setOpen] = useState(false);
48 const [error, setError] = useState<string | null>(null);
49 return (
50 <AppAtomRegistryProvider>
51 <AddEnvironmentDialog
52 open={open}
53 routeTarget={null}
54 error={error}
55 savedEnvironments={[]}
56 onOpenChange={setOpen}
57 onErrorChange={setError}
58 />
59 </AppAtomRegistryProvider>
60 );
61}
62
63function setup() {
64 mocks.connectSshEnvironment.mockClear();
65 return stubGlobal("desktopBridge", {});
66}
67
68const remoteCard = () => page.getByRole("button", { name: /Remote link/ });
69const sshCard = () => page.getByRole("button", { name: /^SSH/ });
70
71async function openDialogOnSsh() {
72 await userEvent.click(page.getByRole("button", { name: "Add environment" }));
73 await userEvent.click(sshCard());
74 await expect.element(sshCard()).toHaveAttribute("aria-pressed", "true");
75}
76
77async function expectDefaultModeAfterReopen() {
78 await expect.element(page.getByRole("dialog")).not.toBeInTheDocument();
79 await userEvent.click(page.getByRole("button", { name: "Add environment" }));
80 await expect.element(remoteCard()).toHaveAttribute("aria-pressed", "true");
81 await expect.element(sshCard()).toHaveAttribute("aria-pressed", "false");
82 await expect.element(page.getByPlaceholder("backend.example.com")).toBeInTheDocument();
83}
84
85describe("AddEnvironmentDialog", () => {
86 it("reopens on Remote link after adding an SSH environment", async () => {
87 using _bridge = setup();
88 await using _screen = await render(<Owner />);
89
90 await openDialogOnSsh();
91 await userEvent.fill(page.getByPlaceholder("Search hosts or type devbox"), "devbox");
92 await userEvent.click(
93 page.getByRole("dialog").getByRole("button", { name: "Add environment" }),
94 );
95 expect(mocks.connectSshEnvironment).toHaveBeenCalledOnce();
96
97 await expectDefaultModeAfterReopen();
98 });
99
100 it("clears the form after dismissing it on SSH", async () => {
101 using _bridge = setup();
102 await using _screen = await render(<Owner />);
103
104 await openDialogOnSsh();
105 await userEvent.click(remoteCard());
106 await userEvent.fill(page.getByPlaceholder("backend.example.com"), "devbox.example.com");
107 await userEvent.fill(page.getByPlaceholder("PAIRCODE"), "PAIRCODE");
108 await userEvent.click(sshCard());
109 await userEvent.fill(page.getByPlaceholder("Search hosts or type devbox"), "devbox");
110 await userEvent.fill(page.getByPlaceholder("root"), "maria");
111 await userEvent.fill(page.getByPlaceholder("22"), "2222");
112 await userEvent.keyboard("{Escape}");
113
114 await expectDefaultModeAfterReopen();
115 await expect.element(page.getByPlaceholder("backend.example.com")).toHaveValue("");
116 await expect.element(page.getByPlaceholder("PAIRCODE")).toHaveValue("");
117 await userEvent.click(sshCard());
118 await expect.element(page.getByPlaceholder("Search hosts or type devbox")).toHaveValue("");
119 await expect.element(page.getByPlaceholder("root")).toHaveValue("");
120 await expect.element(page.getByPlaceholder("22")).toHaveValue("");
121
122 let finishConnection!: (result: AtomCommandResult<void, Error>) => void;
123 const pending = new Promise<AtomCommandResult<void, Error>>((resolve) => {
124 finishConnection = resolve;
125 });
126 mocks.connectSshEnvironment.mockImplementationOnce(() => pending);
127 await userEvent.fill(page.getByPlaceholder("Search hosts or type devbox"), "devbox");
128 await userEvent.click(
129 page.getByRole("dialog").getByRole("button", { name: "Add environment" }),
130 );
131 await userEvent.keyboard("{Escape}");
132 await expectDefaultModeAfterReopen();
133 finishConnection(AsyncResult.failure(Cause.fail(new Error("dismissed SSH attempt"))));
134 await expect
135 .element(page.getByRole("dialog").getByRole("button", { name: "Add environment" }))
136 .toBeEnabled();
137 await expect.element(page.getByText(/dismissed SSH attempt/)).not.toBeInTheDocument();
138 });
139});