playwright icon indicating copy to clipboard operation
playwright copied to clipboard

[Bug]: Headless chromium media query (pointer: fine) changing on some web pages while running in docker image and native linux

Open kevswanberg opened this issue 1 year ago • 2 comments

Version

1.49.0

Steps to reproduce

In the playwright docker image container and on native linux Chromium, the media query for pointer type will change after going to certain pages.

Here is a test project going to several different pages, running the same media query before and after. Certain pages consistently fail.

  • Clone: https://github.com/kevswanberg/playwright_chromium_docker_issue
  • Run:

    docker run -it --rm  -v ./package.json:/home/somewhere/package.json -v ./tests:/home/somewhere/tests \ 
        -v  ./playwright.config.ts:/home/somewhere/playwright.config.ts mcr.microsoft.com/playwright:v1.49.0-noble \
        /bin/bash -c "cd /home/somewhere/ && npm i && npx playwright test"

The spec tests a bunch of different sites first evaling the media query, goto page, and evaluate the media query again. On most sites (pointer: fine) evaluates as true in both checks, however there are a few that don't.

Expected behavior

In headless chromium with given run settings the media query (pointer: fine) will be consistent regardless of the current web page.

Actual behavior

Some web pages change the value of the media query (pointer: fine) to false.

Additional context

Might be a bug in headless Chromium, it works in headed mode for both docker and native.

Possibly related: https://github.com/microsoft/playwright/issues/18777

This issues mentions headed mode, but it currently seems to work correctly in headed mode. https://issues.chromium.org/issues/40903645?pli=1

Environment

System:
    OS: Linux 6.8 Ubuntu 24.04.1 LTS 24.04.1 LTS (Noble Numbat)
    CPU: (2) arm64 unknown
    Memory: 1.61 GB / 1.91 GB
    Container: Yes
  Binaries:
    Node: 22.11.0 - /usr/bin/node
    Yarn: 1.22.22 - /usr/bin/yarn
    npm: 10.9.0 - /usr/bin/npm
  Languages:
    Bash: 5.2.21 - /usr/bin/bash

AND

 System:
    OS: Linux 6.8 Ubuntu 24.04.1 LTS 24.04.1 LTS (Noble Numbat)
    CPU: (4) x64 Intel(R) Core(TM) i5-6440HQ CPU @ 2.60GHz
    Memory: 12.05 GB / 15.36 GB
    Container: Yes
  Binaries:
    Node: 22.11.0 - ~/.nvm/versions/node/v22.11.0/bin/node
    Yarn: 1.22.11 - /usr/local/bin/yarn
    npm: 10.9.0 - ~/.nvm/versions/node/v22.11.0/bin/npm
  IDEs:
    VSCode: 1.69.2 - /usr/bin/code
  Languages:
    Bash: 5.2.21 - /usr/bin/bash
  npmPackages:
    @playwright/test: ^1.49.0 => 1.49.0 
    playwright: ^1.49.0 => 1.49.0

kevswanberg avatar Nov 23 '24 05:11 kevswanberg

Investigation, looks like 'cross-origin-opener-policy' header is causing the difference:

import { test, expect, Page } from "@playwright/test";

const doTest = async (site: string, page: Page) => {
  expect(await page.evaluate(() => window.matchMedia("(pointer: fine)").matches)).toBeTruthy();
  await page.goto(site);
  expect(await page.evaluate(() => window.matchMedia("(pointer: fine)").matches)).toBeTruthy();
};

for (const url of ["https://google.com", "https://facebook.com", "https://instagram.com", "https://bing.com", "https://whatsapp.com", "https://chatgpt.com", "https://amazon.com", "https://duckduckgo.com", "https://tiktok.com", "https://msn.com", "https://netflix.com", "https://weather.com", "https://live.com", "https://naver.com", "https://linkedin.com", "https://microsoft.com", "https://twitch.tv", "https://office.com", "https://vk.com", "https://openai.com", "https://pinterest.com", "https://quora.com", "https://discord.com", "https://canva.com", "https://aliexpress.com", "https://github.com", "https://apple.com", "https://globo.com", "https://spotify.com", "https://roblox.com", "https://mail.ru", "https://imdb.com", "https://cnn.com", "https://nytimes.com", "https://xkcd.com", "https://gmail.com"]) {
  test(url, async ({ page }) => {
    await page.context().route('**/*', async route => {
      const response = await route.fetch();
      const headers = response.headers();
      delete headers['cross-origin-opener-policy'];
      await route.fulfill({
        response,
        headers: headers
      });
    })
    await doTest(url, page);
    await page.context().unrouteAll({ behavior: 'ignoreErrors' })
  });
}

Minimal reproducible:

test('with cross-origin-opener-policy', async ({ page }) => {
  await page.route('**/*', async route => {
    await route.fulfill({
      headers: {
        'cross-origin-opener-policy': 'same-origin',
        'content-type': 'text/html'
      },
      body: '<html><body><a href="https://example.com">link</a></body></html>'
    });
  });
  expect(await page.evaluate(() => window.matchMedia("(pointer: fine)").matches)).toBeTruthy();
  await page.goto('https://example.com');
  expect(await page.evaluate(() => window.matchMedia("(pointer: fine)").matches)).toBeTruthy();
});

mxschmitt avatar Nov 26 '24 15:11 mxschmitt

'--blink-settings=primaryHoverType=2,availableHoverTypes=2,primaryPointerType=4,availablePointerTypes=4' arg is causing it from here:

https://github.com/microsoft/playwright/blob/a84488edaaa32702f23eb6d5374598e6d2ed7712/packages/playwright-core/src/server/chromium/chromium.ts#L315

Unknown why it has a different behaviour between COOP pages and without. When we remove it, we have consistent behaviour in websites with and without COOP. It was added in https://github.com/microsoft/playwright/commit/75edc61531b44fa657157b8e8481fcc8bc440abf.

Minimal repro:

import http from 'http';
const server = http.createServer((req, res) => {
  const withCOOP = req.url === '/coop';
  res.writeHead(200, {
    ...(withCOOP ? {
      'Cross-Origin-Opener-Policy': 'same-origin'
    } : {}),
    'Content-Type': 'text/html'
  });
  res.end(`
    <html>
      <div id="result"></div>
      <script>
        document.getElementById('result').textContent = 'pointer: fine: ' + window.matchMedia("(pointer: fine)").matches;
      </script>
    </html>
  `);
});
const kPort = 3000;
await new Promise((resolve, reject) => server.listen(kPort, resolve));
console.log(`Server running at http://localhost:${kPort}/`);

// Repro details
// Host OS: Ubuntu 24.04-amd64
// 1. Run the server.mjs script with the following command:
//    node server.mjs
// 2. Create a screenshot of the page with the following command: 
//    xvfb-run /root/.cache/ms-playwright/chromium_headless_shell-1150/chrome-linux/headless_shell --headless --no-sandbox --screenshot=example.png --blink-settings=primaryHoverType=2,availableHoverTypes=2,primaryPointerType=4,availablePointerTypes=4 http://localhost:3000/
//    xvfb-run /root/.cache/ms-playwright/chromium_headless_shell-1150/chrome-linux/headless_shell --headless --no-sandbox --screenshot=examplecoop.png --blink-settings=primaryHoverType=2,availableHoverTypes=2,primaryPointerType=4,availablePointerTypes=4 http://localhost:3000/coop
// Expected: Same screenshot for both URLs
// Actual: Different screenshots for both URLs

mxschmitt avatar Nov 28 '24 11:11 mxschmitt

Investigation notes:

  • blink settings are needed, so that the browser consistently reports mouse-like pointer/hover types - covered by should emulate the hover media feature test;
  • most likely, coop forces a new renderer process to be created, thus the difference;
  • most likely, there is a race between the original settings applied from --blink-settings through WebSettingsImpl::SetFromStrings and then another settings update caused by SlowWebPreferenceCache::OnInputDeviceConfigurationChanged;
  • perhaps media query values are not updated in some MediaValuesCached instance when ChangeType::kMediaQuery is invalidated.

dgozman avatar Jan 07 '25 14:01 dgozman

We got hit by this issue as well, with a developer reporting inconsistencies with whether an Android date picker or a Desktop date picker was rendered. The result was different depending on the order in which they navigated to the date picker. Are there any suggested workarounds here? Perhaps some Emulation CDP calls at the start of the session?

jeff-an avatar Mar 13 '25 20:03 jeff-an

sorry for the direct tag @dgozman but this is affecting a lot of our user flows ATM, any assistance would be greatly appreciated!

jeff-an avatar Mar 17 '25 15:03 jeff-an

@dgozman Hi! This is affecting us as well when working with MUI's date-picker that behaves differently in mobile and desktop view. Is there any plan on fixing this or workarounds?

KellyC17 avatar Apr 29 '25 17:04 KellyC17

Why was this issue closed?

Thank you for your contribution to our project. This issue has been closed due to its limited upvotes and recent activity, and insufficient feedback for us to effectively act upon. Our priority is to focus on bugs that reflect higher user engagement and have actionable feedback, to ensure our bug database stays manageable.

Should you feel this closure was in error, please create a new issue and reference this one. We're open to revisiting it given increased support or additional clarity. Your understanding and cooperation are greatly appreciated.

pavelfeldman avatar Sep 04 '25 01:09 pavelfeldman