| ... | ... | @@ -236,7 +236,10 @@ function createBaseServerConfig(): ServerConfig { |
| 236 | 236 | }; |
| 237 | 237 | } |
| 238 | 238 | |
| 239 | | function createOutdatedProvider(driver: string): ServerProvider { |
| 239 | function createOutdatedProvider( |
| 240 | driver: string, |
| 241 | updateCommand = "npm install -g openai/codex@latest", |
| 242 | ): ServerProvider { |
| 240 | 243 | return { |
| 241 | 244 | instanceId: ProviderInstanceId.make(driver), |
| 242 | 245 | driver: ProviderDriverKind.make(driver), |
| ... | ... | @@ -255,7 +258,7 @@ function createOutdatedProvider(driver: string): ServerProvider { |
| 255 | 258 | latestVersion: "1.1.0", |
| 256 | 259 | message: "Update available.", |
| 257 | 260 | checkedAt: "2026-05-04T10:00:00.000Z", |
| 258 | | updateCommand: "npm install -g openai/codex@latest", |
| 261 | updateCommand, |
| 259 | 262 | canUpdate: true, |
| 260 | 263 | }, |
| 261 | 264 | }; |
| ... | ... | @@ -1155,6 +1158,47 @@ describe("GeneralSettingsPanel observability", () => { |
| 1155 | 1158 | instanceId: ProviderInstanceId.make("codex"), |
| 1156 | 1159 | }); |
| 1157 | 1160 | }); |
| 1161 | |
| 1162 | it("keeps long provider update commands inside the fixed-width popover", async () => { |
| 1163 | const longUpdateCommand = |
| 1164 | "npm install -g @anthropic-ai/claude-code@latest --registry=https://registry.npmjs.org --cache=/tmp/t3code-provider-update-cache"; |
| 1165 | |
| 1166 | setServerConfigSnapshot({ |
| 1167 | ...createBaseServerConfig(), |
| 1168 | providers: [createOutdatedProvider("codex", longUpdateCommand)], |
| 1169 | }); |
| 1170 | |
| 1171 | mounted = await render( |
| 1172 | <AppAtomRegistryProvider> |
| 1173 | <ProviderSettingsPanel /> |
| 1174 | </AppAtomRegistryProvider>, |
| 1175 | ); |
| 1176 | |
| 1177 | await page.getByRole("button", { name: "Update available — view details" }).click(); |
| 1178 | await expect.element(page.getByText(longUpdateCommand)).toBeInTheDocument(); |
| 1179 | |
| 1180 | await vi.waitFor(() => { |
| 1181 | const popup = document.querySelector<HTMLElement>('[data-slot="popover-popup"]'); |
| 1182 | const commandCode = Array.from(document.querySelectorAll<HTMLElement>("code")).find( |
| 1183 | (element) => element.textContent === longUpdateCommand, |
| 1184 | ); |
| 1185 | const scrollViewport = commandCode?.closest<HTMLElement>( |
| 1186 | '[data-slot="scroll-area-viewport"]', |
| 1187 | ); |
| 1188 | |
| 1189 | expect(popup).toBeTruthy(); |
| 1190 | expect(commandCode).toBeTruthy(); |
| 1191 | expect(scrollViewport).toBeTruthy(); |
| 1192 | |
| 1193 | const popupRect = popup!.getBoundingClientRect(); |
| 1194 | const viewportRect = scrollViewport!.getBoundingClientRect(); |
| 1195 | |
| 1196 | expect(popupRect.width).toBeGreaterThan(300); |
| 1197 | expect(popupRect.width).toBeLessThanOrEqual(337); |
| 1198 | expect(viewportRect.right).toBeLessThanOrEqual(popupRect.right + 0.5); |
| 1199 | expect(scrollViewport!.scrollWidth).toBeGreaterThan(scrollViewport!.clientWidth); |
| 1200 | }); |
| 1201 | }); |
| 1158 | 1202 | }); |
| 1159 | 1203 | |
| 1160 | 1204 | describe("SourceControlSettingsPanel discovery states", () => { |