From ae3a822d4e3f736c102972dad9a83958004c29f1 Mon Sep 17 00:00:00 2001 From: ethernet Date: Tue, 11 Aug 2026 22:51:31 -0400 Subject: [PATCH] ci(windows-e2e): driver installs its own pinned @playwright/test - never the app tree's Run 31553293275: the desktop leg from v2026.6.19 failed at '@playwright/test resolvable from installed apps/desktop' - that release predates the dependency, and newer releases move it around via workspace hoisting, so resolving it from the installed tree made the leg's tooling a function of the version under test. Install a pinned @playwright/test (param, default 1.58.2 - the repo lockfile's current version) into a scratch driver dir with the managed node/npm every run and launch the driver from there. The driver talks to the app over Playwright's inspection pipe, so its Playwright is independent of the app; every OLD ref now runs the exact same driver stack. --- tests/install/windows-desktop-gui-e2e.ps1 | 43 +++++++++++++++-------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/tests/install/windows-desktop-gui-e2e.ps1 b/tests/install/windows-desktop-gui-e2e.ps1 index ea0aff0d9e..03eba70aa7 100644 --- a/tests/install/windows-desktop-gui-e2e.ps1 +++ b/tests/install/windows-desktop-gui-e2e.ps1 @@ -95,7 +95,13 @@ param( [string]$WorkRoot = $(if ($env:HERMES_E2E_WORKROOT) { $env:HERMES_E2E_WORKROOT } else { Join-Path $env:TEMP "hermes-desktop-gui-e2e" }), - [string]$SetupExeUrl = "https://hermes-assets.nousresearch.com/Hermes-Setup.exe" + [string]$SetupExeUrl = "https://hermes-assets.nousresearch.com/Hermes-Setup.exe", + + # Pinned @playwright/test for the update-gui driver. Installed fresh + # into a scratch dir every run -- never resolved from the installed + # tree -- so the driver behaves identically for every OLD ref. Bump + # deliberately; keep roughly in step with the repo's own lockfile. + [string]$PlaywrightVersion = "1.58.2" ) $ErrorActionPreference = "Stop" @@ -521,29 +527,38 @@ function Invoke-GuiUpdateDesktopRoute([string]$TargetSha) { Remove-Item -LiteralPath $resultPath -Force -ErrorAction SilentlyContinue $node = Get-ManagedNode - $appsDesktop = Join-Path $InstallDir "apps\desktop" - # @playwright/test is a workspace devDependency; the root `npm ci` - # HOISTS it to the repo-root node_modules, not apps/desktop's. Resolve - # it the way Node will (walk up from apps/desktop) instead of asserting - # a hardcoded path that hoisting makes wrong. - $prevEap = $ErrorActionPreference; $ErrorActionPreference = "Continue" - & $node -e "require.resolve('@playwright/test', { paths: [process.argv[1]] })" $appsDesktop 2>&1 | Out-Null - $pwResolved = ($LASTEXITCODE -eq 0) - $ErrorActionPreference = $prevEap - Assert-True $pwResolved "@playwright/test resolvable from installed apps/desktop" + # The Playwright driver gets its OWN pinned @playwright/test in a + # scratch dir -- NEVER the installed tree's copy. The driver talks to + # the app over Playwright's inspection pipe, so its Playwright version + # is independent of the app under test; installing it ourselves makes + # the leg identical for every OLD ref (older releases predate the + # dependency entirely, and hoisting moves it around in newer ones). + $driverDir = Join-Path $WorkRoot "pw-driver" + New-Item -ItemType Directory -Path $driverDir -Force | Out-Null + $npmCli = Join-Path (Split-Path -Parent $node) "node_modules\npm\bin\npm-cli.js" + Assert-True (Test-Path -LiteralPath $npmCli) "managed npm exists beside the managed node" + Push-Location $driverDir + try { + & $node $npmCli install --no-save --no-audit --no-fund "@playwright/test@$PlaywrightVersion" 2>&1 | + Select-Object -Last 5 | ForEach-Object { Write-Host " npm| $_" } + $npmExit = $LASTEXITCODE + } finally { + Pop-Location + } + Assert-True ($npmExit -eq 0) "npm install @playwright/test@$PlaywrightVersion into the driver dir" $recorder = Start-DesktopRecorder (Join-Path $proof "desktop-frames") $recording = Start-ScreenRecording (Join-Path $proof "recording.mkv") try { # Launch the installed app and click through Settings -> About -> # Update now. Exit 0 = the app quit for the updater hand-off. - # Copy the driver INTO the installed apps/desktop first: Node resolves + # Copy the driver INTO $driverDir first: Node resolves # require('@playwright/test') from the SCRIPT's own directory upward, # so running it from the CI checkout would resolve the wrong (or no) # node_modules. - $driver = Join-Path $appsDesktop "e2e-drive-update.cjs" + $driver = Join-Path $driverDir "e2e-drive-update.cjs" Copy-Item (Join-Path $AssetsDir "drive-update.cjs") $driver -Force - Push-Location $appsDesktop + Push-Location $driverDir try { & $node $driver $desktopExe $proof 2>&1 | ForEach-Object { Write-Host " $_" }