microsoft / playwright

Playwright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API.
https://playwright.dev
Apache License 2.0
64.93k stars 3.53k forks source link

[BUG] Chrome extension tests fail under docker when ran headless #26767

Closed atsakiridis closed 11 months ago

atsakiridis commented 12 months ago

System info

Source code

I'm afraid I can't share the full source code, but I could share some snippets if you tell me what you want to look at

Config file

// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

/**
 * See https://playwright.dev/docs/test-configuration.
 */
export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  reporter: 'html',
  use: {
    trace: 'on-first-retry',
  },

  projects: [
    {
      name: 'perform-actions-chrome',
      testMatch: 'perform-actions.spec.ts',
      use: { ...devices['Desktop Chrome'] },
    },
  ],
});

Steps

$ docker run -it --init -v /host/project/dir:/home/jenkins/workspace --ipc=host mcr.microsoft.com/playwright:v1.37.0-jammy /bin/bash
# cd /home/jenkins/workspace
# npm ci
# npx playwright test --workers=1
  1) [perform-actions-chrome] › perform-actions.spec.ts:106:5 › 

    Error: Wallet popup not opened

      75 |     }
      76 |   }
    > 77 |   throw new Error("Wallet popup not opened");
         |         ^
      78 | }
      79 |
      80 | async function importWallet(context, page) {

        at waitForPage (/home/jenkins/workspace/tests/perform-actions.spec.ts:77:9)
        at /home/jenkins/workspace/tests/perform-actions.spec.ts:122:28

  1 failed
    [perform-actions-chrome] › perform-actions.spec.ts:106:5 › 

Expected

I'm expecting the test to pass

Actual

Instead, the test times out waiting for the extension popup to come up

Important notes:

Comparing chrome logs between successful and failed runs, what stands out are these lines:

[919:934:0829/104942.494436:ERROR:bus.cc(399)] Failed to connect to the bus: Could not parse server address: Unknown 
...
[946:946:0829/104942.518869:WARNING:sandbox_linux.cc(393)] InitializeSandbox() called with multiple threads in process gpu-process.
[919:919:0829/104942.528474:ERROR:chrome_browser_cloud_management_controller.cc(163)] Cloud management controller initialization aborted as CBCM is not enabled.

Can you think of any reason why headless docker run might mess with extension popup or not allow it to come up?

aslushnikov commented 11 months ago

@atsakiridis If you're testing extension, you should use headless=new chromium mode, see https://playwright.dev/docs/next/chrome-extensions#headless-mode

This way chrome extension will always be loaded. Hope this helps!

atsakiridis commented 11 months ago

@aslushnikov thanks for your reply, but I'm already following playwright docs for extensions and using headless=new. Remember, the exact same tests pass in headless mode when not using docker as I mentioned. Here's the launch code in my fixture:

    ...
    const pathToExtension = 'extensions/efbglgofoippbgcjepnhiblaibcnclgk/1.6.16_0';
    const context = await chromium.launchPersistentContext('', {
      headless: false,
      args: [
        `--headless=new`,
        `--disable-extensions-except=${pathToExtension}`,
        `--load-extension=${pathToExtension}`,
      ]
    });

So it must be something specific for docker... Any clues?

aslushnikov commented 11 months ago

So it must be something specific for docker... Any clues?

@atsakiridis Some usual suspects are incorrectly mounted docker volumes, but I'm out of ideas otherwise. if you do think this is Playwright's fault, please file a new issue with a good repro for us to debug!

littlemyx commented 11 months ago

Seems like I have the same issue: an extension which tests are successful in local environment both for headless and headful modes, but failing inside Docker container. My research showed that the problem (at least for me) is in background service worker which is not starting. I'm using this code for getting extension's id and all tests failing on waiting for the serviceworker event due to exceeding timeout:

...
 extensionId: async ({ context }, use) => {
    let [background] = context.serviceWorkers();
    if (!background) background = await context.waitForEvent('serviceworker');

    const extensionId = background.url().split('/')[2];
    await use(extensionId);
  },
...
ajczyzewska commented 5 months ago

I've also experienced the same problem. However, there is a workaround for that.

You can use "user flow" and get id through UI. Here's how you can achieve that:

        await page.goto("chrome://extensions/");
        await page.locator("#detailsButton").click();
        const href = await page.evaluate(() => document.location.href);
        const url = new URLSearchParams(href);
        const extensionId = url.get("chrome://extensions/?id");
        await use(extensionId);

Side note: only one extension has to be installed (if you have more, you need to add more steps to filter extension you are interested in).

Tested on Docker and Gitlab CI in Headless mode and works.