From 2c5021ff6089a5fe4b0e924baa4b3a847dff4450 Mon Sep 17 00:00:00 2001 From: wenshao Date: Fri, 24 Jul 2026 21:03:39 +0800 Subject: [PATCH 1/3] test(web-shell): capture the git-mode new-branch sub-state in the visuals suite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `git mode selector` visuals scenario captured the composer chip and the opened three-mode popover, but stopped there: selecting an option used to dismiss the popover ~100ms later (the click bubbled through the React tree out of the portaled content to the composer surface's onClick → core.focus() → Radix focus-outside close), so the branch-name sub-state couldn't be shot stably. #7668 fixed that dismissal, so it now can. Extend the scenario to click "New branch", fill a valid branch name, and capture the revealed input (validated) with its Create-branch affordance, in both themes. All six git-mode captures are byte-stable across runs (0% pixel diff). Match the option by role — its label is split across a name and a description span, so getByText('New branch') is ambiguous (also fixed in #7668). Beyond covering a state the preview never showed, this doubles as a visual regression guard for #7668: if the popover ever dismisses on option-click again, the input goes missing and the assertion fails here, not only in the screenshot. --- .../client/e2e/visuals/screenshots.spec.ts | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/packages/web-shell/client/e2e/visuals/screenshots.spec.ts b/packages/web-shell/client/e2e/visuals/screenshots.spec.ts index cb400f69947..97e5c52af65 100644 --- a/packages/web-shell/client/e2e/visuals/screenshots.spec.ts +++ b/packages/web-shell/client/e2e/visuals/screenshots.spec.ts @@ -423,16 +423,31 @@ for (const theme of THEMES) { // Open: the three-mode popover (current / new branch / worktree). Assert // an option is visible (not just the chip's aria-label) so a regression // that fails to open the popover fails here, not only in the visually - // reviewed screenshot. The branch-name sub-state is intentionally not - // captured: its input autoFocuses, and the popover then dismisses on the - // idle frame captureScreenshot waits for — so it can't be shot stably - // through this pipeline (the functional web-shell.git-mode.spec.ts drives - // that path). The chip + open popover already show the new UI head-only. + // reviewed screenshot. await chip.click(); await expect( page.getByText('Current branch', { exact: true }), ).toBeVisible(); await captureScreenshot(page, `git-mode-popover-${theme}`); + + // New-branch mode: reveals the branch-name input (validated ✓) and the + // Create-branch affordance. Selecting an option once dismissed the popover + // — the click bubbled through the React tree (portaled content) to the + // composer surface's onClick → core.focus() → Radix focus-outside close — + // until #7668 stopped that propagation on PopoverContent. So this capture + // both shows the sub-state the previous revision couldn't and stands as a + // visual regression guard: if that dismissal ever returns, the input goes + // missing and this assertion fails here, not just in the screenshot. + // Match the option by role — its label is split across a name + a + // description span, so getByText('New branch') is ambiguous (#7668). + await page.getByRole('radio', { name: /New branch/ }).click(); + const branchInput = page.locator('[data-testid="git-mode-branch-input"]'); + await expect(branchInput).toBeVisible(); + await branchInput.fill('feat/my-feature'); + await expect( + page.locator('[data-testid="git-mode-confirm-branch"]'), + ).toBeVisible(); + await captureScreenshot(page, `git-mode-branch-${theme}`); }); test(`slash menu`, async ({ page }, testInfo) => { From ad804e7b5c4264d0e348f525db6ad21cb9db0090 Mon Sep 17 00:00:00 2001 From: qwen-code-ci-bot Date: Fri, 24 Jul 2026 18:41:17 +0000 Subject: [PATCH 2/3] test(web-shell): strengthen git-mode branch assertion and trim comment (#7672) --- .../client/e2e/visuals/screenshots.spec.ts | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/web-shell/client/e2e/visuals/screenshots.spec.ts b/packages/web-shell/client/e2e/visuals/screenshots.spec.ts index 97e5c52af65..6747ad2719b 100644 --- a/packages/web-shell/client/e2e/visuals/screenshots.spec.ts +++ b/packages/web-shell/client/e2e/visuals/screenshots.spec.ts @@ -430,23 +430,15 @@ for (const theme of THEMES) { ).toBeVisible(); await captureScreenshot(page, `git-mode-popover-${theme}`); - // New-branch mode: reveals the branch-name input (validated ✓) and the - // Create-branch affordance. Selecting an option once dismissed the popover - // — the click bubbled through the React tree (portaled content) to the - // composer surface's onClick → core.focus() → Radix focus-outside close — - // until #7668 stopped that propagation on PopoverContent. So this capture - // both shows the sub-state the previous revision couldn't and stands as a - // visual regression guard: if that dismissal ever returns, the input goes - // missing and this assertion fails here, not just in the screenshot. - // Match the option by role — its label is split across a name + a - // description span, so getByText('New branch') is ambiguous (#7668). + // #7668 keeps this sub-state open; its input is the visual regression guard. + // Match by role — the label spans multiple elements, so getByText is ambiguous. await page.getByRole('radio', { name: /New branch/ }).click(); const branchInput = page.locator('[data-testid="git-mode-branch-input"]'); await expect(branchInput).toBeVisible(); await branchInput.fill('feat/my-feature'); await expect( page.locator('[data-testid="git-mode-confirm-branch"]'), - ).toBeVisible(); + ).toBeEnabled(); await captureScreenshot(page, `git-mode-branch-${theme}`); }); From d4f39757c1cae88aebccf8d026ee49e2903550b2 Mon Sep 17 00:00:00 2001 From: qwen-code-ci-bot Date: Fri, 24 Jul 2026 19:51:41 +0000 Subject: [PATCH 3/3] test(web-shell): harden git-mode branch capture into a real #7668 guard Scope the New branch option to the popover locator and settle past the ~100ms dismissal window before re-asserting the popover and input stay visible, so a regression of #7668 hard-fails here instead of only producing a wrong (visually reviewed) screenshot. Mirrors the proven guard in web-shell.git-mode.spec.ts. --- .../client/e2e/visuals/screenshots.spec.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/web-shell/client/e2e/visuals/screenshots.spec.ts b/packages/web-shell/client/e2e/visuals/screenshots.spec.ts index 6747ad2719b..cc4b8a5034f 100644 --- a/packages/web-shell/client/e2e/visuals/screenshots.spec.ts +++ b/packages/web-shell/client/e2e/visuals/screenshots.spec.ts @@ -430,12 +430,20 @@ for (const theme of THEMES) { ).toBeVisible(); await captureScreenshot(page, `git-mode-popover-${theme}`); - // #7668 keeps this sub-state open; its input is the visual regression guard. - // Match by role — the label spans multiple elements, so getByText is ambiguous. - await page.getByRole('radio', { name: /New branch/ }).click(); + // #7668 keeps this sub-state open. Match the option by role — its label + // spans a name + description span, so getByText is ambiguous. + const popover = page.locator('[data-slot="popover-content"]'); + await popover.getByRole('radio', { name: /New branch/ }).click(); const branchInput = page.locator('[data-testid="git-mode-branch-input"]'); await expect(branchInput).toBeVisible(); await branchInput.fill('feat/my-feature'); + // Regression guard for #7668: the input flashes visible on click, but the + // pre-fix dismissal landed ~100ms later, so an immediate assertion still + // passed. Settle past that window and re-assert, so a re-dismissal hard-fails + // here — mirroring the functional web-shell.git-mode.spec.ts. + await page.waitForTimeout(300); + await expect(popover).toBeVisible(); + await expect(branchInput).toBeVisible(); await expect( page.locator('[data-testid="git-mode-confirm-branch"]'), ).toBeEnabled();