From 37c280d59c2921717ed64d194fac88f761ea028a Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Wed, 14 Oct 2026 18:25:16 -0700 Subject: [PATCH 1/3] test: skip user activation file chooser tests where the engine differs Chromium 148 in Electron 42 and Chrome on the Android emulator open a second file chooser instead of consuming the user activation. Under the frozen clock, page timers are fired from evaluate calls that carry user activation, so input.click() and showPicker() succeed without a gesture. Failing runs: https://github.com/microsoft/playwright/actions/runs/38660724131 https://github.com/microsoft/playwright/actions/runs/38660427709 https://github.com/microsoft/playwright/actions/runs/38658323573 --- tests/page/page-filechooser.spec.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/page/page-filechooser.spec.ts b/tests/page/page-filechooser.spec.ts index ddc52be4e1743..25c35f4d5b28f 100644 --- a/tests/page/page-filechooser.spec.ts +++ b/tests/page/page-filechooser.spec.ts @@ -407,6 +407,7 @@ test.describe('user activation', () => { test('should not open file chooser without user activation', async ({ page, server, browserName }) => { test.fixme(browserName === 'webkit', 'WebKit opens the file chooser from input.click() without user activation'); + test.skip(process.env.PW_CLOCK === 'frozen', 'The fake clock fires page timers from evaluate calls, which carry user activation'); let choosers = 0; page.on('filechooser', () => choosers++); @@ -439,8 +440,9 @@ test.describe('user activation', () => { expect(await page.evaluate(() => (window as any).showPicker())).toBe('ok'); }); - test('should consume user activation when opening file chooser', async ({ page, server, browserName }) => { + test('should consume user activation when opening file chooser', async ({ page, server, browserName, isElectron, isAndroid }) => { test.fixme(browserName === 'webkit', 'WebKit does not consume user activation when opening the file chooser'); + test.fixme(isElectron || isAndroid, 'Chromium 148 in Electron 42 and Chrome on the Android emulator do not consume user activation'); let choosers = 0; page.on('filechooser', () => choosers++); await page.goto(server.PREFIX + '/activation.html'); From 4627e25308feeb66f072275452a99535f7898215 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Wed, 14 Oct 2026 19:53:00 -0700 Subject: [PATCH 2/3] test: wait for a console message instead of polling in the activation test Under the frozen clock the 0ms timer fires after page.waitForFunction has started polling, and polling evaluates with a user gesture that grants activation. Waiting for a console message avoids evaluating in the page, so the test no longer needs a skip for that configuration. --- tests/page/page-filechooser.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/page/page-filechooser.spec.ts b/tests/page/page-filechooser.spec.ts index 25c35f4d5b28f..2975884bacc92 100644 --- a/tests/page/page-filechooser.spec.ts +++ b/tests/page/page-filechooser.spec.ts @@ -397,7 +397,7 @@ test.describe('user activation', () => { if (location.search === '?click') setTimeout(() => input.click(), 0); if (location.search === '?showPicker') - setTimeout(() => window.showPickerResult = window.showPicker(), 0); + setTimeout(() => console.log('showPicker:' + window.showPicker()), 0); `; @@ -407,7 +407,6 @@ test.describe('user activation', () => { test('should not open file chooser without user activation', async ({ page, server, browserName }) => { test.fixme(browserName === 'webkit', 'WebKit opens the file chooser from input.click() without user activation'); - test.skip(process.env.PW_CLOCK === 'frozen', 'The fake clock fires page timers from evaluate calls, which carry user activation'); let choosers = 0; page.on('filechooser', () => choosers++); @@ -415,9 +414,10 @@ test.describe('user activation', () => { await page.waitForTimeout(500); expect(choosers).toBe(0); + // Wait for a console message instead of polling with waitForFunction, because evaluating in the page grants user activation. + const result = page.waitForEvent('console', msg => msg.text().startsWith('showPicker:')); await page.goto(server.PREFIX + '/activation.html?showPicker'); - await page.waitForFunction(() => !!(window as any).showPickerResult); - expect(await page.evaluate(() => (window as any).showPickerResult)).toBe('NotAllowedError'); + expect((await result).text()).toBe('showPicker:NotAllowedError'); expect(choosers).toBe(0); }); From 5abd4f2be798b0404f3d12cbd7ed254a533e14ea Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Wed, 14 Oct 2026 19:56:44 -0700 Subject: [PATCH 3/3] test: clarify the comment about polling and user activation --- tests/page/page-filechooser.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/page/page-filechooser.spec.ts b/tests/page/page-filechooser.spec.ts index 2975884bacc92..8fddde2b7d3a9 100644 --- a/tests/page/page-filechooser.spec.ts +++ b/tests/page/page-filechooser.spec.ts @@ -414,7 +414,8 @@ test.describe('user activation', () => { await page.waitForTimeout(500); expect(choosers).toBe(0); - // Wait for a console message instead of polling with waitForFunction, because evaluating in the page grants user activation. + // Do not poll with waitForFunction: each poll evaluates in the page with a user gesture, + // which grants transient user activation and would let showPicker() succeed. const result = page.waitForEvent('console', msg => msg.text().startsWith('showPicker:')); await page.goto(server.PREFIX + '/activation.html?showPicker'); expect((await result).text()).toBe('showPicker:NotAllowedError');