| @@ -236,7 +236,10 @@ function createBaseServerConfig(): ServerConfig { · 235 unmodified lines |
| 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 { · 12 unmodified lines |
| 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", () => { · 893 unmodified lines |
| 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", () => { |