keepcalculator

06 Numbers and Powers

How to Test Hover States with Playwright Screenshots

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

This guide shows you how to capture hover-state screenshots with Playwright, so you can visually verify that buttons, links, and menus respond correctly to mouse hover. You’ll learn to trigger a hover, take a screenshot, and compare it against a baseline to catch unintended CSS or layout changes. You’ll need a basic Playwright setup with a test file and the ability to run Node.js scripts.

What You’ll Need

  • Node.js (v16 or later) installed
  • A Playwright test project (or install it via npm init playwright@latest)
  • A web page with hoverable elements (e.g., a button with a hover style)
  • Basic familiarity with writing and running Playwright tests

Step-by-Step

  1. Set up a test file. Create a file like hover.spec.js in your tests directory. Import Playwright’s test and expect modules at the top: const { test, expect } = require('@playwright/test');
  2. Write a test that navigates to your page. Use test('hover screenshot', async ({ page }) => { await page.goto('https://example.com'); }); Replace the URL with the page you’re testing.
  3. Locate the element you want to hover over. Use Playwright’s locator API, e.g., const button = page.locator('button.submit'); Ensure the selector is specific enough to target the right element.
  4. Trigger a hover. Call await button.hover(); This moves the mouse pointer over the element, simulating a real user’s hover. Playwright waits for the hover action to complete before continuing.
  5. Wait for any hover effects to settle. If the hover triggers animations (e.g., a color transition), wait for them to finish. Use await page.waitForTimeout(500); or better, wait for a specific state like await expect(button).toHaveCSS('background-color', 'rgb(0, 0, 255)'); to ensure the effect is applied.
  6. Take the screenshot. Use await page.screenshot({ path: 'hover-state.png' }); This captures the entire viewport. To capture just the element, use await button.screenshot({ path: 'button-hover.png' }); The latter is useful for focused comparison.
  7. Save the screenshot as a baseline. On your first run, the screenshot is your baseline. Commit it to your repository so you can compare future runs against it.
  8. Compare against the baseline. To detect changes, use Playwright’s built-in visual comparison. In your test, after taking the screenshot, add expect(await page.screenshot()).toMatchSnapshot('hover-state.png'); This compares the current screenshot to the stored baseline. If they differ, the test fails and Playwright generates a diff image.
  9. Run the test. Execute npx playwright test in your terminal. Playwright will run the test and report pass/fail status. If it fails, it will show a diff in the test report.
  10. Review the diff. Open the test report (run npx playwright show-report) to see the baseline, actual, and diff images. This helps you identify exactly what changed in the hover state.

Common Mistakes

  • Not waiting for hover effects. Taking a screenshot immediately after hover() may capture the element mid-transition. Always wait for the effect to complete.
  • Using a non-stable selector. If your locator is too broad or changes between runs, the hover may target the wrong element, producing inconsistent screenshots.
  • Ignoring viewport size. Screenshots are viewport-dependent. If you change the viewport size between runs, the layout will shift, causing false failures. Set a fixed viewport in your test or config.
  • Forgetting to update the baseline. When you intentionally change the hover style, you must update the baseline snapshot. Use npx playwright test --update-snapshots to regenerate it.
  • Testing hover on a non-hoverable element. Some elements (like a plain <div>) don’t have hover styles. Hovering them will still work, but the screenshot will look identical to the non-hover state, giving a false sense of coverage.

Tips

  • Use element screenshots for focused checks. Capturing just the element (e.g., a button) reduces noise from surrounding content and makes diffs easier to interpret.
  • Set a consistent viewport. In your Playwright config, set viewport: { width: 1280, height: 720 } to ensure consistent screenshots across runs.
  • Use CSS assertions before screenshots. Instead of waiting a fixed time, assert that the hover effect is applied (e.g., await expect(button).toHaveCSS('color', 'rgb(255, 0, 0)')). This is more reliable and faster.
  • Group hover tests logically. If you have many elements, write a loop that iterates over locators, but be careful to keep each test independent to avoid state leakage.
  • Store baselines in version control. Commit your baseline screenshots so your team can review changes. Use a separate directory for snapshots to keep things tidy.

Troubleshooting

Test fails even though nothing changed. This often happens due to environment differences (e.g., font rendering, OS). Try running the test in a Docker container or on the same OS as your CI. Also, ensure you’re using the same browser version.

Hover doesn’t trigger the effect. The element might be covered by another element, or the hover is intercepted by a tooltip. Use page.mouse.move() to move the mouse to specific coordinates if hover() isn’t working. Alternatively, check if the element is actually visible and enabled.

Screenshots are blurry or low-resolution. Set deviceScaleFactor: 2 in your viewport to capture high-DPI screenshots. This is especially important for testing on retina displays.

Snapshot comparison is too strict. Playwright’s default threshold is 0.2 (20% pixel difference). If you have minor anti-aliasing differences, increase the threshold in the toMatchSnapshot call: toMatchSnapshot('hover.png', { maxDiffPixelRatio: 0.1 }).

Cannot find the baseline snapshot. Ensure your snapshot files are stored in the default __snapshots__ directory. If you use a custom path, specify it in the config.

Frequently Asked Questions

Can I test hover states on mobile devices? Hover doesn’t exist on touch screens. Playwright can simulate hover via page.mouse.move(), but it won’t reflect real mobile behavior. For mobile, test tap states instead.

How do I update the baseline screenshot after a deliberate change? Run npx playwright test --update-snapshots. This regenerates all snapshots that fail. Be sure to review the changes before committing.

What if my hover state involves a dropdown menu? Hover over the trigger element, then wait for the menu to appear (e.g., await expect(page.locator('.menu')).toBeVisible()), then take the screenshot of the menu or the whole page.

Can I take a screenshot of a hover state without writing a full test? Yes, you can use Playwright’s codegen or a simple script using chromium.launch(), but using the test runner gives you built-in snapshot comparison and reporting.

Why does my hover screenshot show the cursor? Playwright hides the cursor by default. If you want to show it, use page.screenshot({ path: 'hover.png', animations: 'disabled' }) – but actually the cursor is always hidden. To include a cursor, you’d need to use a custom script with page.mouse.move() and then capture the screen, but that’s not standard.

How do I handle hover states that only appear after a delay? Use await page.waitForSelector('.tooltip', { state: 'visible' }) or await expect(page.locator('.tooltip')).toBeVisible() to wait for the element to appear before taking the screenshot.

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 →