test: fix android tests (#32932)

One test is removed, since it's impossible to fix. Hopefully, the rest
will pass.
This commit is contained in:
Dmitry Gozman 2024-10-03 03:37:43 -07:00 committed by GitHub
parent 3c5967d4f5
commit 0ffac886e8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 38 additions and 61 deletions

View File

@ -103,7 +103,9 @@ export class AndroidDeviceDispatcher extends Dispatcher<AndroidDevice, channels.
}
async info(params: channels.AndroidDeviceTapParams): Promise<channels.AndroidDeviceInfoResult> {
return { info: await this._object.send('info', params) };
const info = await this._object.send('info', params);
fixupAndroidElementInfo(info);
return { info };
}
async inputType(params: channels.AndroidDeviceInputTypeParams) {
@ -305,3 +307,14 @@ const keyMap = new Map<string, number>([
['Copy', 278],
['Paste', 279],
]);
function fixupAndroidElementInfo(info: channels.AndroidElementInfo) {
// Some of the properties are nullable, see https://developer.android.com/reference/androidx/test/uiautomator/UiObject2.
info.clazz = info.clazz || '';
info.pkg = info.pkg || '';
info.res = info.res || '';
info.desc = info.desc || '';
info.text = info.text || '';
for (const child of info.children || [])
fixupAndroidElementInfo(child);
}

View File

@ -19,23 +19,32 @@ import type { PageTestFixtures, PageWorkerFixtures } from '../page/pageTestApi';
import type { AndroidDevice, BrowserContext } from 'playwright-core';
export { expect } from '@playwright/test';
type AndroidWorkerFixtures = PageWorkerFixtures & {
type AndroidTestFixtures = {
androidDevice: AndroidDevice;
};
type AndroidWorkerFixtures = PageWorkerFixtures & {
androidDeviceWorker: AndroidDevice;
androidContext: BrowserContext;
};
export const androidTest = baseTest.extend<PageTestFixtures, AndroidWorkerFixtures>({
androidDevice: [async ({ playwright }, run) => {
async function closeAllActivities(device: AndroidDevice) {
await device.shell('am force-stop com.google.android.googlequicksearchbox');
await device.shell('am force-stop org.chromium.webview_shell');
await device.shell('am force-stop com.android.chrome');
}
export const androidTest = baseTest.extend<PageTestFixtures & AndroidTestFixtures, AndroidWorkerFixtures>({
androidDeviceWorker: [async ({ playwright }, run) => {
const device = (await playwright._android.devices())[0];
await device.shell('am force-stop org.chromium.webview_shell');
await device.shell('am force-stop com.android.chrome');
await closeAllActivities(device);
device.setDefaultTimeout(90000);
await run(device);
await device.close();
}, { scope: 'worker' }],
browserVersion: [async ({ androidDevice }, run) => {
const browserVersion = (await androidDevice.shell('dumpsys package com.android.chrome'))
browserVersion: [async ({ androidDeviceWorker }, run) => {
const browserVersion = (await androidDeviceWorker.shell('dumpsys package com.android.chrome'))
.toString('utf8')
.split('\n')
.find(line => line.includes('versionName='))!
@ -53,8 +62,14 @@ export const androidTest = baseTest.extend<PageTestFixtures, AndroidWorkerFixtur
electronMajorVersion: [0, { scope: 'worker' }],
isWebView2: [false, { scope: 'worker' }],
androidContext: [async ({ androidDevice }, run) => {
const context = await androidDevice.launchBrowser();
androidDevice: async ({ androidDeviceWorker }, use) => {
await closeAllActivities(androidDeviceWorker);
await use(androidDeviceWorker);
await closeAllActivities(androidDeviceWorker);
},
androidContext: [async ({ androidDeviceWorker }, run) => {
const context = await androidDeviceWorker.launchBrowser();
const [page] = context.pages();
await page.goto('data:text/html,Default page');
await run(context);

View File

@ -17,10 +17,6 @@
import fs from 'fs';
import { androidTest as test, expect } from './androidTest';
test.afterAll(async ({ androidDevice }) => {
await androidDevice.shell('am force-stop com.android.chrome');
});
test('androidDevice.model', async function({ androidDevice }) {
expect(androidDevice.model()).toContain('sdk_gphone');
expect(androidDevice.model()).toContain('x86_64');

View File

@ -15,7 +15,6 @@
*/
import fs from 'fs';
import { join } from 'path';
import { PNG } from 'playwright-core/lib/utilsBundle';
import { androidTest as test, expect } from './androidTest';
@ -55,40 +54,7 @@ test('androidDevice.push', async function({ androidDevice }) {
});
test('androidDevice.fill', async function({ androidDevice }) {
test.fixme(true, 'Hangs on the bots');
await androidDevice.shell('am start org.chromium.webview_shell/.WebViewBrowserActivity');
await androidDevice.fill({ res: 'org.chromium.webview_shell:id/url_field' }, 'Hello');
expect((await androidDevice.info({ res: 'org.chromium.webview_shell:id/url_field' })).text).toBe('Hello');
});
test('androidDevice.options.omitDriverInstall', async function({ playwright }) {
test.skip(true, 'Android._driverPromise gets cached and is in a closed state. Its stored inside the androidDevice worker fixture.');
const devices = await playwright._android.devices({ omitDriverInstall: true });
const androidDevice = devices[0];
await androidDevice.shell(`cmd package uninstall com.microsoft.playwright.androiddriver`);
await androidDevice.shell(`cmd package uninstall com.microsoft.playwright.androiddriver.test`);
await androidDevice.shell('am start -a android.intent.action.VIEW -d about:blank com.android.chrome');
let fillStatus = '';
androidDevice.fill({ res: 'com.android.chrome:id/url_bar' }, 'Hello').then(() => {
fillStatus = 'success';
}).catch(() => {
fillStatus = 'error';
});
// install and start driver
for (const file of ['android-driver.apk', 'android-driver-target.apk']) {
const filePath = join(require.resolve('playwright-core'), '..', 'bin', file);
await androidDevice.installApk(await fs.promises.readFile(filePath));
}
androidDevice.shell('am instrument -w com.microsoft.playwright.androiddriver.test/androidx.test.runner.AndroidJUnitRunner').catch(e => console.error(e));
// wait for finishing fill operation
while (!fillStatus)
await new Promise(f => setTimeout(f, 200));
expect(fillStatus).toBe('success');
});

View File

@ -16,17 +16,7 @@
import { androidTest as test, expect } from './androidTest';
test.beforeEach(async ({ androidDevice }) => {
await androidDevice.shell('am force-stop com.google.android.googlequicksearchbox');
});
test.afterEach(async ({ androidDevice }) => {
await androidDevice.shell('am force-stop org.chromium.webview_shell');
await androidDevice.shell('am force-stop com.android.chrome');
});
test('androidDevice.webView', async function({ androidDevice }) {
test.slow();
expect(androidDevice.webViews().length).toBe(0);
await androidDevice.shell('am start org.chromium.webview_shell/.WebViewBrowserActivity');
const webview = await androidDevice.webView({ pkg: 'org.chromium.webview_shell' });
@ -52,8 +42,6 @@ test('should navigate page internally', async function({ androidDevice }) {
});
test('should navigate page externally', async function({ androidDevice }) {
test.fixme(true, 'Hangs on the bots');
expect(androidDevice.webViews().length).toBe(0);
await androidDevice.shell('am start org.chromium.webview_shell/.WebViewBrowserActivity');
const webview = await androidDevice.webView({ pkg: 'org.chromium.webview_shell' });
@ -68,7 +56,6 @@ test('should navigate page externally', async function({ androidDevice }) {
});
test('select webview from socketName', async function({ androidDevice }) {
test.slow();
const context = await androidDevice.launchBrowser();
const newPage = await context.newPage();
await newPage.goto('about:blank');