Open History to see the last commit
1import { userEvent } from "vite-plus/test/browser";
2import { describe, expect, it, vi } from "vite-plus/test";
3
4import { render } from "../../../test/render";
5import { ProviderEnvironmentSection } from "./ProviderInstanceCard";
6
7const savedSecret = {
8 name: "FAKE_API_KEY",
9 value: "",
10 sensitive: true,
11 valueRedacted: true,
12} as const;
13
14describe("ProviderEnvironmentSection saved secrets", () => {
15 it("requires a replacement before renaming or unlocking a stored secret", async () => {
16 const onChange = vi.fn();
17 await using screen = await render(
18 <ProviderEnvironmentSection environment={[savedSecret]} onChange={onChange} />,
19 );
20 const name = screen.getByRole("textbox", { name: "Environment variable name 1" });
21 const value = screen.getByLabelText("Environment variable value 1");
22 const lock = screen.getByRole("button", {
23 name: "Mark environment variable FAKE_API_KEY as sensitive",
24 });
25
26 await expect.element(name).toBeDisabled();
27 await expect.element(lock).toBeDisabled();
28 await userEvent.fill(value, "unused-draft");
29 await userEvent.clear(value);
30 await userEvent.tab();
31 expect(onChange).not.toHaveBeenCalled();
32 await expect.element(name).toBeDisabled();
33 await expect.element(lock).toBeDisabled();
34
35 await userEvent.fill(value, "fake-replacement");
36 await userEvent.tab();
37 expect(onChange).toHaveBeenLastCalledWith([
38 { ...savedSecret, value: "fake-replacement", valueRedacted: false },
39 ]);
40 await expect.element(name).toBeEnabled();
41 await expect.element(lock).toBeEnabled();
42 await userEvent.fill(name, "RENAMED_KEY");
43 await userEvent.tab();
44 await userEvent.click(
45 screen.getByRole("button", { name: "Mark environment variable RENAMED_KEY as sensitive" }),
46 );
47 expect(onChange).toHaveBeenLastCalledWith([
48 { name: "RENAMED_KEY", value: "fake-replacement", sensitive: false, valueRedacted: false },
49 ]);
50 await userEvent.click(
51 screen.getByRole("button", { name: "Remove environment variable RENAMED_KEY" }),
52 );
53 expect(onChange).toHaveBeenLastCalledWith([]);
54 });
55});
56
57describe("ProviderEnvironmentSection external settings writes", () => {
58 it("keeps a typed unpublished row when an external write redelivers the environment", async () => {
59 const onChange = vi.fn();
60 await using screen = await render(
61 <ProviderEnvironmentSection environment={[]} onChange={onChange} />,
62 );
63
64 await userEvent.click(screen.getByRole("button", { name: "Add variable" }));
65 await userEvent.type(
66 screen.getByRole("textbox", { name: "Environment variable name 1" }),
67 "KEEP_ME_TYPED",
68 );
69 expect(onChange).not.toHaveBeenCalled();
70
71 // A settings write from elsewhere on the instance redelivers a redacted, stored variable.
72 await screen.rerender(
73 <ProviderEnvironmentSection
74 environment={[{ name: "OTHER_VAR", value: "", sensitive: true, valueRedacted: true }]}
75 onChange={onChange}
76 />,
77 );
78
79 await expect
80 .element(screen.getByRole("textbox", { name: "Environment variable name 2" }))
81 .toHaveValue("KEEP_ME_TYPED");
82 });
83
84 it("does not duplicate a redacted published row on the sibling reseed", async () => {
85 const onChange = vi.fn();
86 await using screen = await render(
87 <ProviderEnvironmentSection environment={[]} onChange={onChange} />,
88 );
89
90 await userEvent.click(screen.getByRole("button", { name: "Add variable" }));
91 await userEvent.fill(
92 screen.getByRole("textbox", { name: "Environment variable name 1" }),
93 "STORE_ME",
94 );
95 await userEvent.fill(screen.getByLabelText("Environment variable value 1"), "fake-secret");
96 await userEvent.tab();
97 expect(onChange).toHaveBeenLastCalledWith([
98 { name: "STORE_ME", value: "fake-secret", sensitive: true, valueRedacted: false },
99 ]);
100
101 await userEvent.click(screen.getByRole("button", { name: "Add variable" }));
102 await userEvent.type(
103 screen.getByRole("textbox", { name: "Environment variable name 2" }),
104 "UNPUBLISHED_ONE",
105 );
106
107 // The stored secret comes back redacted, so the rows reseed without matching the echo.
108 await screen.rerender(
109 <ProviderEnvironmentSection
110 environment={[{ name: "STORE_ME", value: "", sensitive: true, valueRedacted: true }]}
111 onChange={onChange}
112 />,
113 );
114
115 await expect
116 .element(screen.getByRole("textbox", { name: "Environment variable name 1" }))
117 .toHaveValue("STORE_ME");
118 await expect
119 .element(screen.getByRole("textbox", { name: "Environment variable name 2" }))
120 .toHaveValue("UNPUBLISHED_ONE");
121 });
122
123 it("keeps a committed but unpublishable row across an external write", async () => {
124 const onChange = vi.fn();
125 await using screen = await render(
126 <ProviderEnvironmentSection environment={[]} onChange={onChange} />,
127 );
128
129 await userEvent.click(screen.getByRole("button", { name: "Add variable" }));
130 await userEvent.fill(
131 screen.getByRole("textbox", { name: "Environment variable name 1" }),
132 "KEEP-ME",
133 );
134 await userEvent.tab();
135 expect(onChange).not.toHaveBeenCalled();
136
137 await screen.rerender(
138 <ProviderEnvironmentSection
139 environment={[{ name: "OTHER_VAR", value: "", sensitive: true, valueRedacted: true }]}
140 onChange={onChange}
141 />,
142 );
143 await expect
144 .element(screen.getByRole("textbox", { name: "Environment variable name 2" }))
145 .toHaveValue("KEEP-ME");
146 });
147
148 it("drops an acknowledged row when an external write removes it", async () => {
149 const onChange = vi.fn();
150 await using screen = await render(
151 <ProviderEnvironmentSection environment={[]} onChange={onChange} />,
152 );
153
154 await userEvent.click(screen.getByRole("button", { name: "Add variable" }));
155 await userEvent.fill(
156 screen.getByRole("textbox", { name: "Environment variable name 1" }),
157 "PUBLISH_ME",
158 );
159 await userEvent.tab();
160 expect(onChange).toHaveBeenLastCalledWith([{ name: "PUBLISH_ME", value: "", sensitive: true }]);
161
162 // The server echo acknowledges the publish and keeps the rows; nothing is republished.
163 await screen.rerender(
164 <ProviderEnvironmentSection
165 environment={[{ name: "PUBLISH_ME", value: "", sensitive: true }]}
166 onChange={onChange}
167 />,
168 );
169 expect(onChange).toHaveBeenCalledTimes(1);
170 const acknowledged = screen.getByRole("textbox", { name: "Environment variable name 1" });
171
172 // Another client deletes the variable. The row must not come back.
173 await screen.rerender(<ProviderEnvironmentSection environment={[]} onChange={onChange} />);
174 await expect.element(acknowledged).not.toBeInTheDocument();
175 });
176});