keepcalculator

06 Numbers and Powers

Playwright Screenshot Testing for Responsive Pages

Card No. 06·50760 · Updated · Standard formula, shown below

This guide shows you how to use Playwright’s screenshot capabilities to verify that your web pages render correctly across different screen sizes. You’ll learn to capture full-page and element-specific screenshots at various viewport widths, compare them against baseline images, and automate the entire process so layout regressions are caught before they reach production.

What You’ll Need

  • Node.js (version 16 or later) installed on your machine
  • A basic understanding of JavaScript and command line usage
  • A Playwright project set up (either via npm init playwright or manually installing @playwright/test)
  • Access to the web page you want to test (local or remote URL)

Step-by-Step

  1. Install Playwright Test – If you haven’t already, run npm init playwright@latest in your project directory. This sets up the test runner and installs browsers. For an existing project, run npm install -D @playwright/test and then npx playwright install to download the browser binaries.
  2. Create a test file – In your tests folder, create a new file, e.g., responsive.spec.js. This will contain all your screenshot tests.
  3. Import test and expect – At the top of the file, add: const { test, expect } = require('@playwright/test'); (or use ES modules if your project is configured that way).
  4. Define viewport sizes – Create an array of common screen sizes you want to test. For example: const viewports = [ { width: 375, height: 667 }, { width: 768, height: 1024 }, { width: 1920, height: 1080 } ]; These represent mobile, tablet, and desktop.
  5. Write a loop for each viewport – Use for (const viewport of viewports) { test(`Screenshot at ${viewport.width}px`, async ({ page }) => { ... }); } This generates a separate test for each screen size.
  6. Set the viewport size – Inside the test, call await page.setViewportSize(viewport); before navigating to the page. This ensures the browser window matches the desired dimensions.
  7. Navigate to your page – Use await page.goto('https://example.com'); (replace with your actual URL). Wait for the page to load fully, using await page.waitForLoadState('networkidle'); if necessary.
  8. Take a full-page screenshot – Use await page.screenshot({ path: `screenshots/${viewport.width}.png`, fullPage: true }); This captures the entire scrollable area of the page, not just the visible viewport.
  9. Take an element screenshot (optional) – To capture a specific component, first locate it: const header = await page.locator('header'); then await header.screenshot({ path: `screenshots/header-${viewport.width}.png` }); This is useful for checking a navigation bar or hero section in isolation.
  10. Run the tests – Execute npx playwright test from your terminal. Playwright will run each test and save the screenshots to the specified paths.
  11. Set up visual comparison (baseline) – To automatically detect changes, use Playwright’s built-in expect(page).toHaveScreenshot(). First run will create a baseline image. Subsequent runs compare against it and fail if the screenshot differs by more than a threshold.
  12. Update baselines when intended – When you intentionally change the UI, run npx playwright test --update-snapshots to overwrite the stored baseline images with the new ones.

Common Mistakes

  • Not waiting for fonts or images – Screenshots taken before web fonts load or images finish rendering will show unstyled text or blank areas. Always wait for network idle or use page.waitForSelector for critical elements.
  • Ignoring scroll behavior – A full-page screenshot captures the entire page, but if your page has sticky headers or lazy-loaded content, the screenshot may not reflect what a user actually sees at a given scroll position. Consider taking viewport-only screenshots for those cases.
  • Using fixed paths without cleanup – If you reuse the same screenshot path, old images are overwritten. That’s fine, but if you delete a test, the old screenshot remains. Clean up your screenshots folder regularly.
  • Comparing screenshots across different environments – Font rendering, OS-level anti-aliasing, and GPU differences can cause false positives. Run visual comparisons on the same operating system and browser version to keep results consistent.

Tips

  • Use a dedicated screenshot directory – Create a screenshots/ folder and add it to your .gitignore if you don’t want baseline images in version control. For baselines, keep them in a separate folder like screenshots/baselines/ and commit them.
  • Set a global viewport in config – You can define default viewport sizes in playwright.config.js under use: { viewport: { width: 1280, height: 720 } }, but for responsive tests you’ll override per test.
  • Use device emulation for mobile – Playwright has built-in device descriptors like devices['iPhone 12'] that set viewport, user agent, and touch support. Use test.use({ ...devices['iPhone 12'] }) for realistic mobile testing.
  • Mask dynamic content – If your page has timestamps, ads, or random elements, use page.screenshot({ mask: [locator] }) to cover them with a colored box before capturing, preventing false mismatches.

Troubleshooting

  • Screenshots are blank or incomplete – This usually means the page hasn’t finished loading. Increase wait times or use await page.waitForLoadState('networkidle'). If lazy-loaded images are below the fold, scroll to them first or use fullPage: true after scrolling.
  • Visual comparison fails even though nothing changed – Check for anti-aliasing differences, animations, or dynamic content. Try setting animations: 'disabled' in the test options or use page.emulateMedia({ reducedMotion: 'reduce' }). Also, set a maxDiffPixelRatio in toHaveScreenshot to allow tiny differences.
  • Tests fail on CI but pass locally – CI environments often have different font rendering. Install system fonts, use a headless browser with the same version, and ensure your CI machine has the same operating system as your local machine.
  • Cannot find the element for element screenshot – Use a more specific selector. If the element is inside a shadow DOM, use page.locator('selector', { has: page.locator('...') }) or pierce the shadow root with page.locator('css=...').

Frequently Asked Questions

How do I take a screenshot of only the visible viewport?

Simply omit the fullPage option or set it to false. The default is false, so page.screenshot({ path: 'viewport.png' }) captures only the current viewport.

Can I test multiple pages in one test?

Yes, you can navigate to multiple URLs within a single test and take screenshots of each. However, for better isolation and clearer failure messages, it’s recommended to use separate tests for each page.

How do I set a custom pixel ratio for high-DPI screens?

Use page.setViewportSize({ width, height }) and also set deviceScaleFactor via page.context().newPage() with options. For example: const context = await browser.newContext({ viewport: { width: 375, height: 667 }, deviceScaleFactor: 2 });

What is the best way to store baseline screenshots?

Keep them in a separate directory like __screenshots__ and commit them to your repository. This allows team members to see what the expected UI looks like and makes it easier to review changes.

Can I use Playwright screenshots for non-UI testing, like PDF generation?

Yes, you can use page.pdf() for headless Chromium to generate PDFs of the page, which is useful for reports or documentation. This is separate from screenshot functionality but works similarly.

How do I ignore a specific area when comparing screenshots?

Use the mask option in toHaveScreenshot or page.screenshot. Pass an array of locators that point to the areas you want to mask. Playwright will cover them with a solid color before capturing.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.

More cards in this drawer

The whole Numbers and Powers drawer →