[Bug]: Headless chromium media query (pointer: fine) changing on some web pages while running in docker image and native linux
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
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();
});
'--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
Investigation notes:
- blink settings are needed, so that the browser consistently reports mouse-like pointer/hover types - covered by
should emulate the hover media featuretest; - 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-settingsthroughWebSettingsImpl::SetFromStringsand then another settings update caused bySlowWebPreferenceCache::OnInputDeviceConfigurationChanged; - perhaps media query values are not updated in some
MediaValuesCachedinstance whenChangeType::kMediaQueryis invalidated.
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?
sorry for the direct tag @dgozman but this is affecting a lot of our user flows ATM, any assistance would be greatly appreciated!
@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?
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.