fix(install-e2e): await zoom IPC outside Playwright's predicate
Playwright 1.58 accepts a Promise-valued waitForFunction predicate before its false result. Await each zoom read explicitly; cover delayed responses and fresh-install startup.
This commit is contained in:
@@ -1,14 +1,39 @@
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { readFileSync, unlinkSync, writeFileSync } from 'node:fs'
|
||||
import { createRequire } from 'node:module'
|
||||
import path from 'node:path'
|
||||
|
||||
import { setupNoProvider } from './fixtures'
|
||||
import { buildAppEnv, createSandbox, launchDesktop, setupNoProvider } from './fixtures'
|
||||
import { type ElectronApplication, expect, type Page, test } from './test'
|
||||
|
||||
const { prepareWindowForInput } = createRequire(import.meta.url)(
|
||||
'../../../tests/install/e2e-assets/window-input.cjs',
|
||||
) as { prepareWindowForInput: (app: ElectronApplication, page: Page) => Promise<void> }
|
||||
|
||||
test('input setup survives a fresh-install zoom restore before onboarding', async () => {
|
||||
const sandbox = createSandbox('cold-input')
|
||||
unlinkSync(path.join(sandbox.userDataDir, 'zoom-state.json'))
|
||||
writeFileSync(path.join(sandbox.hermesHome, 'config.yaml'), '# no provider\n', 'utf8')
|
||||
let app: ElectronApplication | undefined
|
||||
|
||||
try {
|
||||
const launched = await launchDesktop(buildAppEnv(sandbox))
|
||||
app = launched.app
|
||||
const page = launched.page
|
||||
await page.waitForSelector('button', { state: 'attached' })
|
||||
await prepareWindowForInput(app, page)
|
||||
const later = page.getByRole('button', { name: /choose a provider later/i })
|
||||
await expect(later).toBeVisible({ timeout: 60_000 })
|
||||
const appWindow = await app.browserWindow(page)
|
||||
await appWindow.evaluate(win => win.emit('focus'))
|
||||
await expect.poll(() => appWindow.evaluate(win => win.webContents.getZoomFactor())).toBeCloseTo(1)
|
||||
await later.click({ timeout: 5_000 })
|
||||
await expect(later).toBeHidden()
|
||||
} finally {
|
||||
await app?.close().catch(() => undefined)
|
||||
sandbox.cleanup()
|
||||
}
|
||||
})
|
||||
|
||||
// Exercise the install driver's input setup against the real renderer/backend,
|
||||
// with no installer, update, credentials, or live user data.
|
||||
for (const lifecycleEvent of ['focus', 'navigation'] as const) {
|
||||
@@ -17,6 +42,7 @@ for (const lifecycleEvent of ['focus', 'navigation'] as const) {
|
||||
const { app, page, sandbox } = fixture
|
||||
|
||||
try {
|
||||
await prepareWindowForInput(app, page)
|
||||
const later = page.getByRole('button', { name: /choose a provider later/i })
|
||||
await expect(later).toBeVisible({ timeout: 60_000 })
|
||||
const zoomFile = path.join(sandbox.userDataDir, 'zoom-state.json')
|
||||
|
||||
43
apps/desktop/e2e/window-input.unit.test.ts
Normal file
43
apps/desktop/e2e/window-input.unit.test.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { createRequire } from 'node:module'
|
||||
|
||||
import { expect, test } from 'vitest'
|
||||
|
||||
const { prepareWindowForInput } = createRequire(import.meta.url)(
|
||||
'../../../tests/install/e2e-assets/window-input.cjs',
|
||||
)
|
||||
|
||||
test('awaits the zoom response instead of accepting a truthy Promise', async () => {
|
||||
let reads = 0
|
||||
let factor = 0.9
|
||||
|
||||
const zoom = {
|
||||
setPercent: () => undefined,
|
||||
get: async () => {
|
||||
reads++
|
||||
|
||||
if (reads > 1) {factor = 1}
|
||||
|
||||
return { percent: factor * 100 }
|
||||
},
|
||||
}
|
||||
|
||||
const previous = (globalThis as any).hermesDesktop
|
||||
|
||||
;(globalThis as any).hermesDesktop = { zoom }
|
||||
const window = { evaluate: async (fn: any) => fn({ webContents: { getZoomFactor: () => factor } }) }
|
||||
|
||||
const page = {
|
||||
evaluate: async (fn: any) => fn(),
|
||||
// Playwright 1.58 accepts the predicate's Promise before it resolves.
|
||||
waitForFunction: async (fn: any) => { await fn() },
|
||||
waitForTimeout: async () => undefined,
|
||||
}
|
||||
|
||||
try {
|
||||
await prepareWindowForInput({ browserWindow: async () => window }, page)
|
||||
expect(reads).toBeGreaterThan(1)
|
||||
expect(factor).toBe(1)
|
||||
} finally {
|
||||
;(globalThis as any).hermesDesktop = previous
|
||||
}
|
||||
})
|
||||
@@ -11,10 +11,15 @@ async function prepareWindowForInput(app, page) {
|
||||
return true
|
||||
})
|
||||
if (persistent) {
|
||||
await page.waitForFunction(async () => {
|
||||
const state = await globalThis.hermesDesktop.zoom.get()
|
||||
return state.percent === 100
|
||||
}, undefined, { timeout: 15_000 })
|
||||
// Playwright 1.58 treats an async waitForFunction predicate's Promise as
|
||||
// truthy even when it resolves false. Await each IPC read on the driver.
|
||||
const deadline = Date.now() + 15_000
|
||||
for (;;) {
|
||||
const state = await page.evaluate(() => globalThis.hermesDesktop.zoom.get())
|
||||
if (state.percent === 100) break
|
||||
if (Date.now() >= deadline) throw new Error('timed out waiting for 100% app window zoom')
|
||||
await page.waitForTimeout(100)
|
||||
}
|
||||
} else {
|
||||
// Older sampled releases have no zoom preference bridge.
|
||||
await window.evaluate(win => win.webContents.setZoomLevel(0))
|
||||
|
||||
Reference in New Issue
Block a user