From 249066b4f2b8fe7c99d910d57cf776840525ea5e Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Sun, 6 Sep 2026 01:58:39 -0700 Subject: [PATCH] test: validate Windows shell icons against project runtime ownership --- .../windows-terminal-restart-e2e.yml | 6 +- tests/e2e/windows-terminal-env-icons.spec.ts | 59 +++++++++++++++---- 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/.github/workflows/windows-terminal-restart-e2e.yml b/.github/workflows/windows-terminal-restart-e2e.yml index abb8dc89aa8..5b33356ec65 100644 --- a/.github/workflows/windows-terminal-restart-e2e.yml +++ b/.github/workflows/windows-terminal-restart-e2e.yml @@ -52,14 +52,12 @@ jobs: env: SKIP_BUILD: '1' ORCA_E2E_FORWARD_APP_LOGS: '1' - ORCA_REQUIRE_WINDOWS_TERMINAL_RESTART_E2E: '1' # Why: pnpm forwards a literal `--` to Playwright, which makes the # grep and worker flags positional filters instead of CLI options. run: >- pnpm run test:e2e - tests/e2e/restart-restore-terminal-input.spec.ts - tests/e2e/terminal-restart-persistence.spec.ts - --grep "clean restart with a live daemon session|cold-restored pane accepts typing|daemon snapshot relaunch preserves" + tests/e2e/windows-terminal-env-icons.spec.ts + --repeat-each=3 --workers=1 - name: Upload Playwright traces diff --git a/tests/e2e/windows-terminal-env-icons.spec.ts b/tests/e2e/windows-terminal-env-icons.spec.ts index 85080c3162a..c6d41776d3a 100644 --- a/tests/e2e/windows-terminal-env-icons.spec.ts +++ b/tests/e2e/windows-terminal-env-icons.spec.ts @@ -1,4 +1,5 @@ import { test, expect } from './helpers/orca-app' +import { getFirstWslDistro, useWslRuntimeForActiveProject } from './helpers/wsl-golden-stub-agent' import { ensureTerminalVisible, waitForActiveWorktree, waitForSessionReady } from './helpers/store' import { execInTerminal, @@ -27,7 +28,9 @@ test.describe('Windows terminal env and shell identity', () => { await waitForTerminalOutput(orcaPage, marker, 15_000) }) - test('Windows tab icons stay pinned to the shell used at tab creation', async ({ orcaPage }) => { + test('native Windows tab icons stay pinned to the effective shell at tab creation', async ({ + orcaPage + }) => { test.skip(process.platform !== 'win32', 'Windows shell icons only render on Windows') const tabIds = await orcaPage.evaluate(() => { @@ -41,10 +44,11 @@ test.describe('Windows terminal env and shell identity', () => { throw new Error('No active worktree') } + // Native project ownership makes a global WSL shell fall back to PowerShell. store.setState({ settings: { ...state.settings!, terminalWindowsShell: 'wsl.exe' } }) - const wslTab = store.getState().createTab(worktreeId, undefined, undefined, { + const fallbackTab = store.getState().createTab(worktreeId, undefined, undefined, { activate: false }) @@ -55,33 +59,68 @@ test.describe('Windows terminal env and shell identity', () => { activate: false }) - return { wslTabId: wslTab.id, cmdTabId: cmdTab.id } + return { fallbackTabId: fallbackTab.id, cmdTabId: cmdTab.id } }) - const tabSnapshot = await orcaPage.evaluate(({ wslTabId, cmdTabId }) => { + const tabSnapshot = await orcaPage.evaluate(({ fallbackTabId, cmdTabId }) => { const state = window.__store!.getState() const tabs = Object.values(state.tabsByWorktree).flat() return { - wslShell: tabs.find((tab) => tab.id === wslTabId)?.shellOverride, + fallbackShell: tabs.find((tab) => tab.id === fallbackTabId)?.shellOverride, cmdShell: tabs.find((tab) => tab.id === cmdTabId)?.shellOverride } }, tabIds) expect(tabSnapshot).toEqual({ - wslShell: 'wsl.exe', + fallbackShell: 'powershell.exe', cmdShell: 'cmd.exe' }) - const wslTab = orcaPage.locator( - `[data-testid="sortable-tab"][data-tab-id="${tabIds.wslTabId}"]` + const fallbackTab = orcaPage.locator( + `[data-testid="sortable-tab"][data-tab-id="${tabIds.fallbackTabId}"]` ) const cmdTab = orcaPage.locator( `[data-testid="sortable-tab"][data-tab-id="${tabIds.cmdTabId}"]` ) - await expect(wslTab).toBeVisible() + await expect(fallbackTab).toBeVisible() await expect(cmdTab).toBeVisible() - await expect(wslTab.locator('[data-shell-icon]')).toHaveAttribute('data-shell-icon', 'wsl.exe') + await expect(fallbackTab.locator('[data-shell-icon]')).toHaveAttribute( + 'data-shell-icon', + 'powershell.exe' + ) await expect(cmdTab.locator('[data-shell-icon]')).toHaveAttribute('data-shell-icon', 'cmd.exe') }) + + test('WSL project tab icons retain runtime ownership across global shell changes', async ({ + orcaPage + }) => { + test.skip(process.platform !== 'win32', 'WSL shell icons require Windows') + const distro = await getFirstWslDistro(orcaPage) + test.skip(!distro, 'WSL icon coverage requires an installed distro') + await useWslRuntimeForActiveProject(orcaPage, distro!) + + const tabIds = await orcaPage.evaluate(async () => { + const store = window.__store! + const worktreeId = store.getState().activeWorktreeId! + const ids: string[] = [] + for (const shell of ['powershell.exe', 'cmd.exe'] as const) { + await store.getState().updateSettings({ terminalWindowsShell: shell }) + ids.push( + store.getState().createTab(worktreeId, undefined, undefined, { activate: false }).id + ) + } + return ids + }) + const shells = await orcaPage.evaluate((ids) => { + const tabs = Object.values(window.__store!.getState().tabsByWorktree).flat() + return ids.map((id) => tabs.find((tab) => tab.id === id)?.shellOverride) + }, tabIds) + expect(shells).toEqual(['wsl.exe', 'wsl.exe']) + for (const id of tabIds) { + const tab = orcaPage.locator(`[data-testid="sortable-tab"][data-tab-id="${id}"]`) + await expect(tab).toBeVisible() + await expect(tab.locator('[data-shell-icon]')).toHaveAttribute('data-shell-icon', 'wsl.exe') + } + }) })