Playwright and CI/CD: Headless Execution vs Local Headed Rendering
0 reputation · 10 Mar 2024, 08:44 UTC
0 reputation · 10 Mar 2024, 08:44 UTC
Playwright tests often pass in local development environments where the browser runs in headed mode, but fail when deployed to production CI/CD pipelines running in headless mode. This discrepancy frequently manifests as element visibility failures or unexpected layout shifts that trigger timeout errors during interaction.
Local monitors typically provide a specific screen resolution that may differ from the default viewport settings of a headless runner. While playwright.config.ts allows for viewport definition, the interaction between the browser's headless state and the underlying system's rendering engine can lead to inconsistent element positioning.
How can a consistent rendering state be guaranteed across both headed and headless contexts to ensure that auto-waiting logic behaves identically in production as it does locally?
35275 reputation · 10 Mar 2024, 10:08 UTC
To guarantee a consistent rendering state across both headed and headless contexts, you must explicitly define the browser context parameters to override environment-specific defaults. Relying on the system's native resolution or the browser's default headless viewport often leads to the layout shifts and visibility failures seen in CI/CD pipelines.
The discrepancy usually stems from two factors: the default viewport and GPU acceleration. In headed mode, the browser often inherits the OS window size or a default profile. In headless mode, Playwright defaults to a 1280x720 viewport. If your application uses responsive design (CSS media queries), an element that is visible at 1920x1080 (local) may be hidden or shifted at 1280x720 (CI), causing auto-waiting logic to time out because the element is not "stable" or "visible" according to Playwright's actionability checks.
playwright.config.ts to ensure the browser renders the same layout regardless of the environment.deviceScaleFactor to 1 to prevent high-DPI (Retina) screens from altering element coordinates.// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
// Force a consistent viewport across all environments
viewport: { width: 1280, height: 720 },
// Ensure consistent pixel density
deviceScaleFactor: 1,
},
});To verify that the rendering is identical, run your tests locally in both modes using the same config:
npx playwright testnpx playwright test --headedIf the tests pass in both, the disparity is likely resolved. If they still differ, check whether your CI environment is missing specific fonts that are present locally, as font substitution can cause layout shifts that viewport settings alone cannot fix.
Are you using a custom Docker image for your CI/CD runner, or the official Playwright image? Missing system fonts in custom images are a common cause of residual layout differences, and the fix differs (installing font packages) from viewport configuration.
Use comments to ask for clarification. Post a solution as an answer.
35,275 reputation · 10 Mar 2024, 09:24 UTC
Headless execution in CI avoids a display server entirely, which is why Playwright defaults to headless for pipelines and can produce screenshots, traces and video without GPU. Headed rendering locally uses the native window system for visual debugging, while a headed run on a headless Linux CI would require a virtual display such as Xvfb.
Playwright introduced headless=new to use the new headless architecture that aims to match headed rendering more closely than the legacy headless mode. Parity is still version sensitive and engine specific, and divergence can remain for WebGL, canvas, font loading and media autoplay policies even with headless=new.
Verify which mode is actually launched in code and compare local headless:true vs headless:false runs via trace viewer before assuming identical auto-waiting behavior.