test(adb): fix browser tests (#4700)
This commit is contained in:
		
							parent
							
								
									f89dcc7ba7
								
							
						
					
					
						commit
						1596b53da2
					
				| 
						 | 
				
			
			@ -232,7 +232,7 @@ jobs:
 | 
			
		|||
        name: video-${{ matrix.browser }}-linux-test-results
 | 
			
		||||
        path: test-results
 | 
			
		||||
  test_android:
 | 
			
		||||
    name: Android on macOS
 | 
			
		||||
    name: Android Emulator
 | 
			
		||||
    runs-on: macos-10.15
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v2
 | 
			
		||||
| 
						 | 
				
			
			@ -250,6 +250,7 @@ jobs:
 | 
			
		|||
      env:
 | 
			
		||||
        FOLIO_JSON_OUTPUT_NAME: "test-results/report.json"
 | 
			
		||||
        PW_ANDROID_TESTS: 1
 | 
			
		||||
        DEBUG: pw:api
 | 
			
		||||
    - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json
 | 
			
		||||
      if: always() && github.ref == 'refs/heads/master'
 | 
			
		||||
    - uses: actions/upload-artifact@v1
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -145,7 +145,7 @@ export class AndroidDevice extends EventEmitter {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  async open(command: string): Promise<SocketBackend> {
 | 
			
		||||
    return await this._backend.open(`shell:${command}`);
 | 
			
		||||
    return await this._backend.open(`${command}`);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async _driver(): Promise<Transport> {
 | 
			
		||||
| 
						 | 
				
			
			@ -167,18 +167,7 @@ export class AndroidDevice extends EventEmitter {
 | 
			
		|||
 | 
			
		||||
    debug('pw:android')('Starting the new driver');
 | 
			
		||||
    this.shell(`am instrument -w com.microsoft.playwright.androiddriver.test/androidx.test.runner.AndroidJUnitRunner`);
 | 
			
		||||
 | 
			
		||||
    debug('pw:android')('Polling the socket');
 | 
			
		||||
    let socket;
 | 
			
		||||
    while (!socket) {
 | 
			
		||||
      try {
 | 
			
		||||
        socket = await this._backend.open(`localabstract:playwright_android_driver_socket`);
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        await new Promise(f => setTimeout(f, 100));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    debug('pw:android')('Connected to driver');
 | 
			
		||||
    const socket = await this._waitForLocalAbstract('playwright_android_driver_socket');
 | 
			
		||||
    const transport = new Transport(socket, socket, socket, 'be');
 | 
			
		||||
    transport.onmessage = message => {
 | 
			
		||||
      const response = JSON.parse(message);
 | 
			
		||||
| 
						 | 
				
			
			@ -197,6 +186,20 @@ export class AndroidDevice extends EventEmitter {
 | 
			
		|||
    return this._driverPromise;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async _waitForLocalAbstract(socketName: string): Promise<SocketBackend> {
 | 
			
		||||
    let socket: SocketBackend | undefined;
 | 
			
		||||
    debug('pw:android')(`Polling the socket localabstract:${socketName}`);
 | 
			
		||||
    while (!socket) {
 | 
			
		||||
      try {
 | 
			
		||||
        socket = await this._backend.open(`localabstract:${socketName}`);
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        await new Promise(f => setTimeout(f, 250));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    debug('pw:android')(`Connected to localabstract:${socketName}`);
 | 
			
		||||
    return socket;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async send(method: string, params: any): Promise<any> {
 | 
			
		||||
    const driver = await this._driver();
 | 
			
		||||
    const id = ++this._lastId;
 | 
			
		||||
| 
						 | 
				
			
			@ -224,20 +227,11 @@ export class AndroidDevice extends EventEmitter {
 | 
			
		|||
    debug('pw:android')('Force-stopping', pkg);
 | 
			
		||||
    await this._backend.runCommand(`shell:am force-stop ${pkg}`);
 | 
			
		||||
 | 
			
		||||
    const socketName = createGuid();
 | 
			
		||||
    const socketName = 'playwright-' + createGuid();
 | 
			
		||||
    const commandLine = `_ --disable-fre --no-default-browser-check --no-first-run --remote-debugging-socket-name=${socketName}`;
 | 
			
		||||
    debug('pw:android')('Starting', pkg, commandLine);
 | 
			
		||||
    await this._backend.runCommand(`shell:echo "${commandLine}" > /data/local/tmp/chrome-command-line`);
 | 
			
		||||
    await this._backend.runCommand(`shell:am start -n ${pkg}/com.google.android.apps.chrome.Main about:blank`);
 | 
			
		||||
 | 
			
		||||
    debug('pw:android')('Polling for socket', socketName);
 | 
			
		||||
    while (true) {
 | 
			
		||||
      const net = await this._backend.runCommand(`shell:cat /proc/net/unix | grep ${socketName}$`);
 | 
			
		||||
      if (net)
 | 
			
		||||
        break;
 | 
			
		||||
      await new Promise(f => setTimeout(f, 100));
 | 
			
		||||
    }
 | 
			
		||||
    debug('pw:android')('Got the socket, connecting');
 | 
			
		||||
    return await this._connectToBrowser(socketName, options);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -249,8 +243,9 @@ export class AndroidDevice extends EventEmitter {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  private async _connectToBrowser(socketName: string, options: types.BrowserContextOptions = {}): Promise<BrowserContext> {
 | 
			
		||||
    const androidBrowser = new AndroidBrowser(this, socketName);
 | 
			
		||||
    await androidBrowser._open();
 | 
			
		||||
    const socket = await this._waitForLocalAbstract(socketName);
 | 
			
		||||
    const androidBrowser = new AndroidBrowser(this, socket);
 | 
			
		||||
    await androidBrowser._init();
 | 
			
		||||
    this._browserConnections.add(androidBrowser);
 | 
			
		||||
 | 
			
		||||
    const browserOptions: BrowserOptions = {
 | 
			
		||||
| 
						 | 
				
			
			@ -357,17 +352,22 @@ export class AndroidDevice extends EventEmitter {
 | 
			
		|||
 | 
			
		||||
class AndroidBrowser extends EventEmitter {
 | 
			
		||||
  readonly device: AndroidDevice;
 | 
			
		||||
  readonly socketName: string;
 | 
			
		||||
  private _socket: SocketBackend | undefined;
 | 
			
		||||
  private _socket: SocketBackend;
 | 
			
		||||
  private _receiver: stream.Writable;
 | 
			
		||||
  private _waitForNextTask = makeWaitForNextTask();
 | 
			
		||||
  onmessage?: (message: any) => void;
 | 
			
		||||
  onclose?: () => void;
 | 
			
		||||
 | 
			
		||||
  constructor(device: AndroidDevice, socketName: string) {
 | 
			
		||||
  constructor(device: AndroidDevice, socket: SocketBackend) {
 | 
			
		||||
    super();
 | 
			
		||||
    this.device = device;
 | 
			
		||||
    this.socketName = socketName;
 | 
			
		||||
    this._socket = socket;
 | 
			
		||||
    this._socket.on('close', () => {
 | 
			
		||||
      this._waitForNextTask(() => {
 | 
			
		||||
        if (this.onclose)
 | 
			
		||||
          this.onclose();
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    this._receiver = new (ws as any).Receiver() as stream.Writable;
 | 
			
		||||
    this._receiver.on('message', message => {
 | 
			
		||||
      this._waitForNextTask(() => {
 | 
			
		||||
| 
						 | 
				
			
			@ -377,14 +377,7 @@ class AndroidBrowser extends EventEmitter {
 | 
			
		|||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async _open() {
 | 
			
		||||
    this._socket = await this.device._backend.open(`localabstract:${this.socketName}`);
 | 
			
		||||
    this._socket.on('close', () => {
 | 
			
		||||
      this._waitForNextTask(() => {
 | 
			
		||||
        if (this.onclose)
 | 
			
		||||
          this.onclose();
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  async _init() {
 | 
			
		||||
    await this._socket.write(Buffer.from(`GET /devtools/browser HTTP/1.1\r
 | 
			
		||||
Upgrade: WebSocket\r
 | 
			
		||||
Connection: Upgrade\r
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@ if (process.env.PW_ANDROID_TESTS) {
 | 
			
		|||
  });
 | 
			
		||||
 | 
			
		||||
  it('should open a ADB socket', async function({ device }) {
 | 
			
		||||
    const socket = await device.open('/bin/cat');
 | 
			
		||||
    const socket = await device.open('shell:/bin/cat');
 | 
			
		||||
    await socket.write(Buffer.from('321\n'));
 | 
			
		||||
    const output = await new Promise(resolve => socket.on('data', resolve));
 | 
			
		||||
    expect(output.toString()).toBe('321\n');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,5 +10,5 @@ fi
 | 
			
		|||
 | 
			
		||||
${ANDROID_HOME}/tools/bin/avdmanager delete avd --name android30 || true
 | 
			
		||||
echo "y" | ${ANDROID_HOME}/tools/bin/sdkmanager --install "system-images;android-30;google_apis;x86"
 | 
			
		||||
echo "no" | ${ANDROID_HOME}/tools/bin/avdmanager create avd --force --name android30 --device "Nexus 5X" -k 'system-images;android-30;google_apis;x86'
 | 
			
		||||
echo "no" | ${ANDROID_HOME}/tools/bin/avdmanager create avd --force --name android30 --device pixel_4 --package "system-images;android-30;google_apis;x86"
 | 
			
		||||
${ANDROID_HOME}/emulator/emulator -list-avds
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,7 @@ if [[ -z "${ANDROID_HOME}" ]]; then
 | 
			
		|||
fi
 | 
			
		||||
 | 
			
		||||
echo "Killing previous emulators"
 | 
			
		||||
adb devices | grep emulator | cut -f1 | while read line; do adb -s $line emu kill; done
 | 
			
		||||
${ANDROID_HOME}/platform-tools/adb devices | grep emulator | cut -f1 | while read line; do adb -s $line emu kill; done
 | 
			
		||||
 | 
			
		||||
echo "Starting emulator"
 | 
			
		||||
nohup ${ANDROID_HOME}/emulator/emulator -avd android30 -no-audio -no-snapshot -no-window -gpu swiftshader_indirect &
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue