Fix model config smoke test flake (#323304)

This commit is contained in:
Paul
2026-06-27 19:51:22 -07:00
committed by GitHub
parent 7fb1d82170
commit 12149dcfef
2 changed files with 52 additions and 24 deletions
+9 -6
View File
@@ -570,12 +570,15 @@ export class AgentsWindow {
// `force` bypasses the transient `context-view-pointerBlock` overlay
// that intercepts pointer events while the action widget animates open.
await row.click({ force: true });
// The picker dismisses after a selection (aria-expanded flips to false).
await page.waitForFunction(
(sel: string) => { const n = document.querySelector(sel); return !n || n.getAttribute('aria-expanded') !== 'true'; },
ACTIVE_SESSION_MODEL_PICKER_NAME,
{ timeout: 15_000 },
);
// Confirm the selection actually committed: the picker name button
// must now display the chosen model. A non-committing click (e.g.
// absorbed by the animating pointer-block overlay) silently leaves the
// previous model selected and the picker dismissed, so waiting only
// for the popup to close would miss it. Scope to `:visible` so a hidden
// overflow duplicate of the name button can't produce a false positive.
await page.locator(`${ACTIVE_SESSION_MODEL_PICKER_NAME}:visible`, { hasText: modelName })
.first()
.waitFor({ state: 'visible', timeout: 15_000 });
return;
} catch (error) {
lastError = error;
+43 -18
View File
@@ -234,27 +234,52 @@ export class Chat {
* Opens the model picker (in the panel chat input) and selects the model
* whose displayed name contains `modelName`. Clicks the model-picker name
* button to open the popup, waits for the matching row to appear (models may
* still be registering), clicks it, then waits for the popup to dismiss.
* still be registering), clicks it, then confirms the selection committed.
*
* The row click can occasionally fail to commit — e.g. absorbed by the
* action-widget's animating `context-view-pointerBlock` overlay — silently
* leaving the previous model (often "Auto") selected. That model advertises
* no configurable options, so the config button never appears and a later
* `openModelConfig` wedges. To absorb this, re-open the picker and retry until
* the name button reflects the chosen model or `timeoutMs` elapses.
*/
async selectModel(modelName: string): Promise<void> {
async selectModel(modelName: string, timeoutMs: number = 60_000): Promise<void> {
const page = this.code.driver.currentPage;
await page.locator(`${CHAT_MODEL_PICKER_NAME}:visible`).first().click();
await this.code.waitForElement(ACTION_WIDGET);
// The picker opens with a focused filter input. Type the model name to
// narrow the list — otherwise the model may be hidden in a collapsed
// "Other Models" section.
await page.keyboard.type(modelName);
const nameButton = page.locator(`${CHAT_MODEL_PICKER_NAME}:visible`).first();
const row = page.locator(ACTION_WIDGET_ROW, { hasText: modelName }).first();
await row.waitFor({ state: 'visible', timeout: 30_000 });
// `force` bypasses the transient `context-view-pointerBlock` overlay that
// intercepts pointer events while the action widget is animating open.
await row.click({ force: true });
// The picker dismisses after a selection (aria-expanded flips back to false).
await page.waitForFunction(
(sel: string) => { const n = document.querySelector(sel); return !n || n.getAttribute('aria-expanded') !== 'true'; },
CHAT_MODEL_PICKER_NAME,
{ timeout: 15_000 },
);
const deadline = Date.now() + timeoutMs;
let lastError: unknown;
while (Date.now() < deadline) {
try {
await nameButton.click();
await this.code.waitForElement(ACTION_WIDGET);
// The picker opens with a focused filter input. Type the model name to
// narrow the list — otherwise the model may be hidden in a collapsed
// "Other Models" section.
await page.keyboard.type(modelName);
await row.waitFor({ state: 'visible', timeout: 10_000 });
// `force` bypasses the transient `context-view-pointerBlock` overlay
// that intercepts pointer events while the action widget animates open.
await row.click({ force: true });
// Confirm the selection actually committed: the picker name button must
// now display the chosen model. (A non-committing click leaves the old
// model selected and the picker dismissed, so waiting only for the
// popup to close would miss it.) Scope to `:visible` so a hidden overflow
// duplicate of the name button can't produce a false positive.
await page.locator(`${CHAT_MODEL_PICKER_NAME}:visible`, { hasText: modelName })
.first()
.waitFor({ state: 'visible', timeout: 10_000 });
return;
} catch (error) {
lastError = error;
// Dismiss the (possibly empty / stale) picker so the next attempt
// re-opens a freshly-populated one.
try { await page.keyboard.press('Escape'); } catch { /* picker already gone */ }
await new Promise(r => setTimeout(r, 500));
}
}
throw new Error(`Timed out selecting model "${modelName}". Last error: ${lastError instanceof Error ? lastError.message : String(lastError)}`);
}
/**