fix(adb): minor fixes (#4678)

This commit is contained in:
Pavel Feldman 2020-12-10 16:37:18 -08:00 committed by GitHub
parent 495085cbb2
commit 616df7d2f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 39 additions and 19 deletions

View File

@ -21,11 +21,12 @@ export interface AndroidDevice<BrowserContextOptions, BrowserContext, Page> exte
setDefaultTimeout(timeout: number): void; setDefaultTimeout(timeout: number): void;
on(event: 'webview', handler: (webView: AndroidWebView<Page>) => void): this; on(event: 'webview', handler: (webView: AndroidWebView<Page>) => void): this;
waitForEvent(event: string, predicate?: (data: any) => boolean): Promise<any>; waitForEvent(event: string, optionsOrPredicate?: (data: any) => boolean | { timeout?: number, predicate?: (data: any) => boolean }): Promise<any>;
serial(): string; serial(): string;
model(): string; model(): string;
webViews(): AndroidWebView<Page>[]; webViews(): AndroidWebView<Page>[];
webView(selector: { pkg: string }): Promise<AndroidWebView<Page>>;
shell(command: string): Promise<string>; shell(command: string): Promise<string>;
launchBrowser(options?: BrowserContextOptions & { packageName?: string }): Promise<BrowserContext>; launchBrowser(options?: BrowserContextOptions & { packageName?: string }): Promise<BrowserContext>;
close(): Promise<void>; close(): Promise<void>;

View File

@ -21,13 +21,10 @@ const { android } = require('playwright-android');
await device.shell('am force-stop org.chromium.webview_shell'); await device.shell('am force-stop org.chromium.webview_shell');
await device.shell('am start org.chromium.webview_shell/.WebViewBrowserActivity'); await device.shell('am start org.chromium.webview_shell/.WebViewBrowserActivity');
await device.fill({ res: 'org.chromium.webview_shell:id/url_field' }, 'github.com/microsoft/playwright'); const webview = await device.webView({ pkg: 'org.chromium.webview_shell' });
let [webview] = device.webViews();
if (!webview)
webview = await device.waitForEvent('webview');
const page = await webview.page(); const page = await webview.page();
await device.fill({ res: 'org.chromium.webview_shell:id/url_field' }, 'github.com/microsoft/playwright');
await Promise.all([ await Promise.all([
page.waitForNavigation(), page.waitForNavigation(),
device.press({ res: 'org.chromium.webview_shell:id/url_field' }, 'Enter') device.press({ res: 'org.chromium.webview_shell:id/url_field' }, 'Enter')

View File

@ -53,7 +53,7 @@ export class Android extends ChannelOwner<channels.AndroidChannel, channels.Andr
} }
} }
export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel, channels.AndroidDeviceInitializer> { export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel, channels.AndroidDeviceInitializer> implements apiInternal.AndroidDevice<types.BrowserContextOptions, BrowserContext, Page> {
readonly _timeoutSettings: TimeoutSettings; readonly _timeoutSettings: TimeoutSettings;
private _webViews = new Map<number, AndroidWebView>(); private _webViews = new Map<number, AndroidWebView>();
@ -101,6 +101,16 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel, c
return [...this._webViews.values()]; return [...this._webViews.values()];
} }
async webView(selector: { pkg: string }, options?: types.TimeoutOptions): Promise<AndroidWebView> {
const webView = [...this._webViews.values()].find(v => v.pkg() === selector.pkg);
if (webView)
return webView;
return this.waitForEvent('webview', {
...options,
predicate: (view: AndroidWebView) => view.pkg() === selector.pkg
});
}
async wait(selector: apiInternal.AndroidSelector, options?: { state?: 'gone' } & types.TimeoutOptions) { async wait(selector: apiInternal.AndroidSelector, options?: { state?: 'gone' } & types.TimeoutOptions) {
await this._wrapApiCall('androidDevice.wait', async () => { await this._wrapApiCall('androidDevice.wait', async () => {
await this._channel.wait({ selector: toSelectorChannel(selector), ...options }); await this._channel.wait({ selector: toSelectorChannel(selector), ...options });

View File

@ -40,6 +40,7 @@ export interface Backend {
export interface DeviceBackend { export interface DeviceBackend {
serial: string; serial: string;
status: string;
close(): Promise<void>; close(): Promise<void>;
init(): Promise<void>; init(): Promise<void>;
runCommand(command: string): Promise<string>; runCommand(command: string): Promise<string>;
@ -65,7 +66,7 @@ export class Android {
} }
async devices(): Promise<AndroidDevice[]> { async devices(): Promise<AndroidDevice[]> {
const devices = await this._backend.devices(); const devices = (await this._backend.devices()).filter(d => d.status === 'device');
return await Promise.all(devices.map(d => AndroidDevice.create(this, d))); return await Promise.all(devices.map(d => AndroidDevice.create(this, d)));
} }
} }
@ -117,7 +118,9 @@ export class AndroidDevice extends EventEmitter {
} }
async shell(command: string): Promise<string> { async shell(command: string): Promise<string> {
return await this._backend.runCommand(`shell:${command}`); const result = await this._backend.runCommand(`shell:${command}`);
await this._refreshWebViews();
return result;
} }
private async _driver(): Promise<Transport> { private async _driver(): Promise<Transport> {
@ -245,7 +248,7 @@ export class AndroidDevice extends EventEmitter {
const browser = await CRBrowser.connect(androidBrowser, browserOptions); const browser = await CRBrowser.connect(androidBrowser, browserOptions);
const controller = new ProgressController(); const controller = new ProgressController();
await controller.run(async progress => { await controller.run(async progress => {
await browser._defaultContext!._loadDefaultContext(progress); await browser._defaultContext!._loadDefaultContextAsIs(progress);
}); });
return browser._defaultContext!; return browser._defaultContext!;
} }
@ -278,7 +281,7 @@ export class AndroidDevice extends EventEmitter {
const p = match[1]; const p = match[1];
if (+p !== pid) if (+p !== pid)
continue; continue;
pkg = proc.substring(proc.lastIndexOf(' ')); pkg = proc.substring(proc.lastIndexOf(' ') + 1);
} }
const webView = { pid, pkg }; const webView = { pid, pkg };
this._webViews.set(pid, webView); this._webViews.set(pid, webView);

View File

@ -24,16 +24,20 @@ export class AdbBackend implements Backend {
async devices(): Promise<DeviceBackend[]> { async devices(): Promise<DeviceBackend[]> {
const result = await runCommand('host:devices'); const result = await runCommand('host:devices');
const lines = result.toString().trim().split('\n'); const lines = result.toString().trim().split('\n');
const serials = lines.map(line => line.split('\t')[0]); return lines.map(line => {
return serials.map(serial => new AdbDevice(serial)); const [serial, status] = line.trim().split('\t');
return new AdbDevice(serial, status);
});
} }
} }
class AdbDevice implements DeviceBackend { class AdbDevice implements DeviceBackend {
readonly serial: string; readonly serial: string;
readonly status: string;
constructor(serial: string) { constructor(serial: string, status: string) {
this.serial = serial; this.serial = serial;
this.status = status;
} }
async init() { async init() {

View File

@ -222,7 +222,7 @@ export abstract class BrowserContext extends EventEmitter {
this._timeoutSettings.setDefaultTimeout(timeout); this._timeoutSettings.setDefaultTimeout(timeout);
} }
async _loadDefaultContext(progress: Progress) { async _loadDefaultContextAsIs(progress: Progress): Promise<Page[]> {
if (!this.pages().length) { if (!this.pages().length) {
const waitForEvent = helper.waitForEvent(progress, this, BrowserContext.Events.Page); const waitForEvent = helper.waitForEvent(progress, this, BrowserContext.Events.Page);
progress.cleanupWhenAborted(() => waitForEvent.dispose); progress.cleanupWhenAborted(() => waitForEvent.dispose);
@ -230,6 +230,11 @@ export abstract class BrowserContext extends EventEmitter {
} }
const pages = this.pages(); const pages = this.pages();
await pages[0].mainFrame()._waitForLoadState(progress, 'load'); await pages[0].mainFrame()._waitForLoadState(progress, 'load');
return pages;
}
async _loadDefaultContext(progress: Progress) {
const pages = await this._loadDefaultContextAsIs(progress);
if (pages.length !== 1 || pages[0].mainFrame().url() !== 'about:blank') if (pages.length !== 1 || pages[0].mainFrame().url() !== 'about:blank')
throw new Error(`Arguments can not specify page to be opened (first url is ${pages[0].mainFrame().url()})`); throw new Error(`Arguments can not specify page to be opened (first url is ${pages[0].mainFrame().url()})`);
if (this._options.isMobile || this._options.locale) { if (this._options.isMobile || this._options.locale) {

View File

@ -10,8 +10,8 @@ mkdir ${SDKDIR}/cmdline-tools
echo Downloading Android SDK... echo Downloading Android SDK...
cd ${SDKDIR}/cmdline-tools cd ${SDKDIR}/cmdline-tools
curl https://dl.google.com/android/repository/commandlinetools-mac-6858069_latest.zip -o commandlinetools-mac-6858069_latest.zip curl https://dl.google.com/android/repository/commandlinetools-linux-6858069_latest.zip -o commandlinetools-linux-6858069_latest.zip
unzip commandlinetools-mac-6858069_latest.zip unzip commandlinetools-linux-6858069_latest.zip
mv cmdline-tools latest mv cmdline-tools latest
echo Installing emulator... echo Installing emulator...

View File

@ -5,4 +5,4 @@ export ANDROID_SDK_ROOT=${SDKDIR}
export ANDROID_HOME=${SDKDIR} export ANDROID_HOME=${SDKDIR}
export ANDROID_AVD_HOME=${SDKDIR}/avd export ANDROID_AVD_HOME=${SDKDIR}/avd
${SDKDIR}/emulator/emulator -avd android30 ${SDKDIR}/emulator/emulator -avd android30 -gpu guest