diff --git a/tests/e2e/browser-address-bar-narrow-toolbar.spec.ts b/tests/e2e/browser-address-bar-narrow-toolbar.spec.ts index de24f0f4e6d..4c75f9cdd35 100644 --- a/tests/e2e/browser-address-bar-narrow-toolbar.spec.ts +++ b/tests/e2e/browser-address-bar-narrow-toolbar.spec.ts @@ -24,8 +24,8 @@ import { BROWSER_ADDRESS_BAR_MIN_INLINE_WIDTH } from '../../src/renderer/src/com // the middle of that band rather than a fixed window width, because how much // chrome flanks the pane (left sidebar, and a right sidebar that other startup // paths may re-open) varies between runs. -const TARGET_TOOLBAR_WIDTH = 420 -const MIN_USABLE_TOOLBAR_WIDTH = BROWSER_ADDRESS_BAR_MIN_INLINE_WIDTH + 100 +const TARGET_TOOLBAR_WIDTH = 260 +const MIN_USABLE_TOOLBAR_WIDTH = BROWSER_ADDRESS_BAR_MIN_INLINE_WIDTH + 20 const NARROW_WINDOW_HEIGHT = 800 async function startDestinationServer(): Promise<{ url: string; close: () => Promise }> { @@ -62,6 +62,8 @@ async function setWindowWidth(electronApp: ElectronApplication, width: number): if (!window) { throw new Error('No Electron window') } + // Window minimums otherwise mask the narrow-pane state on some runners. + window.setMinimumSize(0, 0) window.setSize(size.width, size.height) }, { width: Math.round(width), height: NARROW_WINDOW_HEIGHT } @@ -118,8 +120,11 @@ async function settleToSqueezedRestingState( // Chrome flanking the pane is everything the toolbar didn't get. await setWindowWidth(electronApp, innerWidth - toolbar + TARGET_TOOLBAR_WIDTH) await addressBarInput(page).evaluate((node) => node.blur()) + const measuredToolbar = await toolbarWidth(page) return { - toolbar: (await toolbarWidth(page)) > MIN_USABLE_TOOLBAR_WIDTH, + toolbar: + measuredToolbar > MIN_USABLE_TOOLBAR_WIDTH && + measuredToolbar <= TARGET_TOOLBAR_WIDTH + 5, collapsed: (await addressBarOverlay(page).count()) === 0 } }, diff --git a/tests/e2e/helpers/daemon-generation-runtime-fixture.ts b/tests/e2e/helpers/daemon-generation-runtime-fixture.ts index 88111024368..332d21aa271 100644 --- a/tests/e2e/helpers/daemon-generation-runtime-fixture.ts +++ b/tests/e2e/helpers/daemon-generation-runtime-fixture.ts @@ -1,4 +1,12 @@ -import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs' +import { + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync +} from 'node:fs' import { homedir, tmpdir } from 'node:os' import path from 'node:path' import { build } from 'esbuild' @@ -109,6 +117,12 @@ export async function createDaemonGenerationRuntime( const reconnectClientEntryPath = path.join(rootDir, 'daemon-generation-reconnect-client.cjs') const legacyCloseClientEntryPath = path.join(rootDir, 'daemon-generation-legacy-close-client.cjs') const repoRoot = process.cwd() + // ESM imports in the bundled fixture resolve from its temp directory, not NODE_PATH. + symlinkSync( + path.join(repoRoot, 'node_modules'), + path.join(rootDir, 'node_modules'), + process.platform === 'win32' ? 'junction' : 'dir' + ) await buildFixtureEntry( path.join(repoRoot, 'tests/e2e/fixtures/daemon-generation-entry.ts'), entryPath diff --git a/tests/e2e/native-chat-history-prepend-anchor.spec.ts b/tests/e2e/native-chat-history-prepend-anchor.spec.ts index d299cadae6e..236d30c4475 100644 --- a/tests/e2e/native-chat-history-prepend-anchor.spec.ts +++ b/tests/e2e/native-chat-history-prepend-anchor.spec.ts @@ -138,6 +138,13 @@ test.describe('Native chat transcript anchoring', () => { sessionId, transcriptPath }) + // Exercise the supported manual paging fallback while the reader stays mid-transcript. + await orcaPage.evaluate(() => { + Object.defineProperty(window, 'IntersectionObserver', { + value: undefined, + configurable: true + }) + }) await toggleTerminalTabToChatView(orcaPage, { tabId, worktreeId: descriptor.worktreeId diff --git a/tests/e2e/native-chat-message-rail.spec.ts b/tests/e2e/native-chat-message-rail.spec.ts index 25ca0a4745b..16d01060224 100644 --- a/tests/e2e/native-chat-message-rail.spec.ts +++ b/tests/e2e/native-chat-message-rail.spec.ts @@ -143,7 +143,7 @@ test.describe('Native chat message rail', () => { // Activating the hover preview transfers focus into the prompt picker. await rail.press('Enter') - await expect(panel.getByRole('button').first()).toBeFocused() + await expect(panel.locator('button[data-current="true"]')).toBeFocused() await panel.getByRole('button', { name: 'Question 5:', exact: false }).click() await expect(panel).not.toBeVisible() const target = transcriptWindow.locator('[data-index="10"]') diff --git a/tests/e2e/terminal-hidden-view-parking.spec.ts b/tests/e2e/terminal-hidden-view-parking.spec.ts index 6cf877c6257..f050a0e4280 100644 --- a/tests/e2e/terminal-hidden-view-parking.spec.ts +++ b/tests/e2e/terminal-hidden-view-parking.spec.ts @@ -20,7 +20,7 @@ import { } from './helpers/terminal' import { parkHiddenTabBehindDecoy, waitForTabParked } from './helpers/terminal-hidden-parking' import { waitForPtyShellEcho } from './terminal-pty-readiness' -import { TERMINAL_TAB_PARK_FLIP_BURST_WINDOW_MS } from '../../src/renderer/src/components/terminal-pane/terminal-park-verdict-flip-telemetry' +import { TERMINAL_TAB_PARK_FLIP_WINDOW_MS } from '../../src/renderer/src/components/terminal-pane/terminal-park-verdict-flip-telemetry' // Why: the parking wiring registers this handle (dev/exposeStore builds only) // so tests can detect that hidden-view parking is compiled in and which delay @@ -43,7 +43,7 @@ test.use({ const PARKED_FRAME_SCRIPT_DELAY_MS = 750 const PARKED_FRAME_COUNT = 25 -const PARK_VERDICT_BURST_SETTLE_MS = TERMINAL_TAB_PARK_FLIP_BURST_WINDOW_MS * 4 +const PARK_VERDICT_WINDOW_SETTLE_MS = Math.ceil(TERMINAL_TAB_PARK_FLIP_WINDOW_MS / 5) function parkedTuiFrame(runId: string, frame: number): string { const progress = `${'█'.repeat((frame % 8) + 1)}${'░'.repeat(8 - ((frame % 8) + 1))}` @@ -478,7 +478,7 @@ test.describe('Terminal hidden view parking', () => { orcaPage, testRepoPath }, testInfo: TestInfo) => { - test.setTimeout(180_000) + test.setTimeout(420_000) await waitForSessionReady(orcaPage) const setup = await setUpParkableTabA(orcaPage) const { worktreeId, tabAId, tabAPtyId } = setup @@ -542,8 +542,8 @@ test.describe('Terminal hidden view parking', () => { const mismatches: string[] = [] for (let cycle = 1; cycle < CYCLES; cycle++) { // Why: each cycle intentionally flips this tab's rendered verdict twice. - // Let the production anti-churn burst window lapse before the next one. - await orcaPage.waitForTimeout(PARK_VERDICT_BURST_SETTLE_MS) + // Keep each tab below the 12-flip sustained-churn pin in a 60s window. + await orcaPage.waitForTimeout(PARK_VERDICT_WINDOW_SETTLE_MS) const rows = await runOneParkRevealCycle(cycle) if (JSON.stringify(rows) !== JSON.stringify(referenceRows)) { mismatches.push( diff --git a/tests/e2e/worktree-scroll-to-current.spec.ts b/tests/e2e/worktree-scroll-to-current.spec.ts index 07f9f87d05c..cdb39420ef0 100644 --- a/tests/e2e/worktree-scroll-to-current.spec.ts +++ b/tests/e2e/worktree-scroll-to-current.spec.ts @@ -40,7 +40,7 @@ test.describe('Reveal active workspace button', () => { // (not a scenario real users hit). Reveal-into-view is covered robustly by // the "outside the virtualized window" test below. - test('clears sidebar filters before revealing a hidden current workspace', async ({ + test('adjusts sidebar filters before revealing a hidden current workspace', async ({ orcaPage, testRepoPath }, testInfo) => { @@ -94,6 +94,13 @@ test.describe('Reveal active workspace button', () => { if (!targetId) { throw new Error('Seeded secondary worktree is missing') } + const targetRepoId = await orcaPage.evaluate( + (repoPath) => window.__store!.getState().repos.find((repo) => repo.path === repoPath)?.id, + testRepoPath + ) + if (!targetRepoId) { + throw new Error('Seeded repository is missing') + } const targetRows = orcaPage.locator( `[data-worktree-sidebar] [data-worktree-id=${JSON.stringify(targetId)}]` @@ -132,7 +139,7 @@ test.describe('Reveal active workspace button', () => { await revealButton.click() await orcaPage .getByRole('dialog', { name: 'Reveal hidden workspace?' }) - .getByRole('button', { name: 'Clear filters and reveal' }) + .getByRole('button', { name: 'Adjust filters and reveal' }) .click() await expect(targetRow).toBeVisible() @@ -149,10 +156,11 @@ test.describe('Reveal active workspace button', () => { }), { timeout: 10_000, - message: 'Reveal button should clear repo filters that hide the current workspace' + message: + 'Reveal button should preserve selected repos while revealing the current workspace' } ) - .toEqual([]) + .toEqual([filterRepoId, targetRepoId]) }) test('reveals the current workspace when it starts outside the virtualized window', async ({