diff --git a/packages/playwright-core/src/server/android/android.ts b/packages/playwright-core/src/server/android/android.ts index 7819f2af1a..1263bfa58f 100644 --- a/packages/playwright-core/src/server/android/android.ts +++ b/packages/playwright-core/src/server/android/android.ts @@ -266,7 +266,8 @@ export class AndroidDevice extends SdkObject { const socketName = isUnderTest() ? 'webview_devtools_remote_playwright_test' : ('playwright-' + createGuid()); const commandLine = this._defaultArgs(options, socketName).join(' '); debug('pw:android')('Starting', pkg, commandLine); - await this._backend.runCommand(`shell:echo "${commandLine}" > /data/local/tmp/chrome-command-line`); + // encode commandLine to base64 to avoid issues (bash encoding) with special characters + await this._backend.runCommand(`shell:echo "${Buffer.from(commandLine).toString('base64')}" | base64 -d > /data/local/tmp/chrome-command-line`); await this._backend.runCommand(`shell:am start -a android.intent.action.VIEW -d about:blank ${pkg}`); return await this._connectToBrowser(socketName, options); } diff --git a/tests/android/browser.spec.ts b/tests/android/browser.spec.ts index 9a189fe16a..5ec09c6a57 100644 --- a/tests/android/browser.spec.ts +++ b/tests/android/browser.spec.ts @@ -32,12 +32,19 @@ test('androidDevice.launchBrowser', async function({ androidDevice }) { await context.close(); }); -test('androidDevice.launchBrowser should pass args with spaces', async ({ androidDevice }) => { - const context = await androidDevice.launchBrowser({ args: ['--user-agent=I am Foo'] }); - const page = await context.newPage(); - const userAgent = await page.evaluate(() => navigator.userAgent); - await context.close(); - expect(userAgent).toBe('I am Foo'); +test('androidDevice.launchBrowser should treat args correctly', async ({ androidDevice }) => { + for (const arg of [ + "--user-agent='I am Foo'", + '--user-agent="I am Foo"', + ]) { + await test.step(`arg: ${arg}`, async () => { + const context = await androidDevice.launchBrowser({ args: [arg] }); + const page = await context.newPage(); + const userAgent = await page.evaluate(() => navigator.userAgent); + await context.close(); + expect(userAgent).toBe('I am Foo'); + }); + } }); test('androidDevice.launchBrowser should throw for bad proxy server value', async ({ androidDevice }) => { @@ -48,12 +55,12 @@ test('androidDevice.launchBrowser should throw for bad proxy server value', asyn expect(error.message).toContain('proxy.server: expected string, got number'); }); -test('androidDevice.launchBrowser should pass proxy config', async ({ androidDevice, server, mode }) => { +test('androidDevice.launchBrowser should pass proxy config', async ({ androidDevice, server, mode, loopback }) => { test.skip(mode === 'docker', 'proxy is not supported for remote connection'); server.setRoute('/target.html', async (req, res) => { res.end('