From 26b2117bc23418c08ea258d309e2e8df0414e44f Mon Sep 17 00:00:00 2001 From: Lazizbek Ergashev Date: Fri, 21 Aug 2026 10:55:58 +0500 Subject: [PATCH 1/5] fix(android): include the 'from' point in the swipe path --- packages/playwright-core/src/client/android.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/playwright-core/src/client/android.ts b/packages/playwright-core/src/client/android.ts index bad1546eab08b..400547e7a159b 100644 --- a/packages/playwright-core/src/client/android.ts +++ b/packages/playwright-core/src/client/android.ts @@ -335,7 +335,7 @@ export class AndroidInput implements api.AndroidInput { } async swipe(from: types.Point, segments: types.Point[], steps: number) { - await this._device._channel.inputSwipe({ segments, steps }, kNoTimeout); + await this._device._channel.inputSwipe({ segments: [from, ...segments], steps }, kNoTimeout); } async drag(from: types.Point, to: types.Point, steps: number) { From c65878646b7eb504c1ae3015eae04569a69a5883 Mon Sep 17 00:00:00 2001 From: Lazizbek Ergashev Date: Fri, 21 Aug 2026 21:59:50 +0500 Subject: [PATCH 2/5] test(android): cover swipe starting from the given point --- tests/android/input.spec.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 tests/android/input.spec.ts diff --git a/tests/android/input.spec.ts b/tests/android/input.spec.ts new file mode 100644 index 0000000000000..e3fae1b66b872 --- /dev/null +++ b/tests/android/input.spec.ts @@ -0,0 +1,26 @@ +/** + * Copyright 2020 Microsoft Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { androidTest as test, expect } from './androidTest'; + +test('androidInput.swipe should start from the given point', async ({ androidDevice }) => { + const context = await androidDevice.launchBrowser(); + const [page] = context.pages(); + await page.setContent(`
${'line
'.repeat(200)}
`); + await androidDevice.input.swipe({ x: 250, y: 1500 }, [{ x: 250, y: 500 }], 30); + await expect.poll(() => page.evaluate(() => window.scrollY)).toBeGreaterThan(0); + await context.close(); +}); From 9b39365bf925c113251a88fc659eb769bdd546b3 Mon Sep 17 00:00:00 2001 From: Lazizbek Ergashev Date: Sat, 22 Aug 2026 06:00:52 +0500 Subject: [PATCH 3/5] test(android): wait for content to render before swiping CI showed the swipe assertion timing out with scrollY stuck at 0 on every retry, even though the swipe call itself completed without error. androidDevice.input.swipe() injects a raw touch event through the OS input pipeline, independent of the CDP channel used by setContent(), so the gesture can land before the new content is actually composited and presented on the device screen. Wait for two animation frames after setContent() so the swipe reliably hits the rendered page. --- tests/android/input.spec.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/android/input.spec.ts b/tests/android/input.spec.ts index e3fae1b66b872..50b916f6bece3 100644 --- a/tests/android/input.spec.ts +++ b/tests/android/input.spec.ts @@ -20,6 +20,11 @@ test('androidInput.swipe should start from the given point', async ({ androidDev const context = await androidDevice.launchBrowser(); const [page] = context.pages(); await page.setContent(`
${'line
'.repeat(200)}
`); + // androidDevice.input.swipe() injects a raw touch event straight into the OS input + // pipeline, independent of the CDP connection used by setContent() above. Wait for + // the new content to actually be composited and presented on the device screen, + // otherwise the swipe can land on the previous (blank) frame and never scroll anything. + await page.evaluate(() => new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve)))); await androidDevice.input.swipe({ x: 250, y: 1500 }, [{ x: 250, y: 500 }], 30); await expect.poll(() => page.evaluate(() => window.scrollY)).toBeGreaterThan(0); await context.close(); From 6de3e9018a638a16529bc6f7eef5cef26a68a8f8 Mon Sep 17 00:00:00 2001 From: Lazizbek Ergashev Date: Mon, 24 Aug 2026 22:34:32 +0500 Subject: [PATCH 4/5] test(android): use rafraf helper and current license header --- tests/android/input.spec.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/android/input.spec.ts b/tests/android/input.spec.ts index 50b916f6bece3..c26f63c9b81e1 100644 --- a/tests/android/input.spec.ts +++ b/tests/android/input.spec.ts @@ -1,11 +1,11 @@ /** - * Copyright 2020 Microsoft Corporation. All rights reserved. + * Copyright (c) Microsoft Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -15,6 +15,7 @@ */ import { androidTest as test, expect } from './androidTest'; +import { rafraf } from '../config/utils'; test('androidInput.swipe should start from the given point', async ({ androidDevice }) => { const context = await androidDevice.launchBrowser(); @@ -24,7 +25,7 @@ test('androidInput.swipe should start from the given point', async ({ androidDev // pipeline, independent of the CDP connection used by setContent() above. Wait for // the new content to actually be composited and presented on the device screen, // otherwise the swipe can land on the previous (blank) frame and never scroll anything. - await page.evaluate(() => new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve)))); + await rafraf(page); await androidDevice.input.swipe({ x: 250, y: 1500 }, [{ x: 250, y: 500 }], 30); await expect.poll(() => page.evaluate(() => window.scrollY)).toBeGreaterThan(0); await context.close(); From 332d29154f357d1169be2a5c5c3a50e8efc4207c Mon Sep 17 00:00:00 2001 From: Lazizbek Ergashev Date: Mon, 31 Aug 2026 21:35:20 +0500 Subject: [PATCH 5/5] test(android): remove the swipe test that cannot run on the emulator --- tests/android/input.spec.ts | 32 -------------------------------- 1 file changed, 32 deletions(-) delete mode 100644 tests/android/input.spec.ts diff --git a/tests/android/input.spec.ts b/tests/android/input.spec.ts deleted file mode 100644 index c26f63c9b81e1..0000000000000 --- a/tests/android/input.spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { androidTest as test, expect } from './androidTest'; -import { rafraf } from '../config/utils'; - -test('androidInput.swipe should start from the given point', async ({ androidDevice }) => { - const context = await androidDevice.launchBrowser(); - const [page] = context.pages(); - await page.setContent(`
${'line
'.repeat(200)}
`); - // androidDevice.input.swipe() injects a raw touch event straight into the OS input - // pipeline, independent of the CDP connection used by setContent() above. Wait for - // the new content to actually be composited and presented on the device screen, - // otherwise the swipe can land on the previous (blank) frame and never scroll anything. - await rafraf(page); - await androidDevice.input.swipe({ x: 250, y: 1500 }, [{ x: 250, y: 500 }], 30); - await expect.poll(() => page.evaluate(() => window.scrollY)).toBeGreaterThan(0); - await context.close(); -});