keepcalculator

06 Numbers and Powers

Data Driven Testing for Visual UI Checks

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

Data-driven testing for visual UI checks lets you verify that your interface renders correctly across many different input states, screen sizes, and themes—without writing a separate test for every case. You define your test data (e.g., user roles, locales, viewport sizes) in a table or file, then run the same visual test against each row, comparing screenshots against baselines. This catches layout regressions, overflow issues, and contrast problems early. Before you start, you’ll need a visual testing tool (like Percy, Applitools, or Playwright’s built-in screenshot comparison), a test runner (like Jest, Mocha, or Playwright Test), and a version control system to store baselines.

What You’ll Need

  • A visual regression testing tool (e.g., Percy, Applitools, or Playwright’s toHaveScreenshot)
  • A test framework (Jest, Mocha, Playwright Test, Cypress, etc.)
  • A data source: JSON, CSV, YAML, or a database with your test cases
  • A Git repository (or similar) to store baseline images and test code
  • A CI/CD pipeline (optional but recommended for automated runs)

Step-by-Step

  1. Define your test data schema. Decide what variables affect the UI: viewport size, theme (light/dark), user role, locale, or specific content states (e.g., empty, loading, error). Create a JSON array or CSV with columns for each variable. For example: [{"name":"admin-dark-desktop","role":"admin","theme":"dark","viewport":"1280x720"}, ...]
  2. Set up your visual testing tool. Install the SDK for your chosen tool. For Playwright, run npm install @playwright/test and configure the browser. For Percy, add @percy/cli and @percy/playwright. Follow the tool’s setup guide to connect to your CI or local environment.
  3. Create a baseline or “golden” screenshot. Before you start data-driven tests, you need a reference image. Run your test once with a known-good state (e.g., admin user, light theme, desktop viewport) and save that screenshot as the baseline. Most tools do this automatically on the first run.
  4. Write a test that iterates over your data. In your test file, import the data array and use a loop or test.describe to create a test per row. For each row, navigate to the page, set the viewport, apply the theme or role (via localStorage, cookies, or mocking), and take a screenshot. Example with Playwright Test:
    import { test } from '@playwright/test';
    import data from './visual-test-data.json';
    
    data.forEach(({ name, role, theme, viewport }) => {
      test(`visual check: ${name}`, async ({ page }) => {
        await page.setViewportSize({ width: parseInt(viewport.split('x')[0]), height: parseInt(viewport.split('x')[1]) });
        await page.goto('/dashboard');
        await page.evaluate(([theme]) => {
          localStorage.setItem('theme', theme);
        }, [theme]);
        await page.reload();
        await expect(page).toHaveScreenshot(`${name}.png`);
      });
    });
  5. Run the tests and review diffs. Execute your test command (e.g., npx playwright test). The tool will compare each new screenshot against the baseline. If there’s a difference, it will show a diff image—highlighting changed pixels. Review each diff to decide if it’s an intended change (update baseline) or a bug (fix the code).
  6. Update baselines when changes are intentional. When you deliberately change the UI (e.g., new design, added text), you need to accept new baselines. In Playwright, run with --update-snapshots. In Percy, use the “Approve” button in the UI. Never update baselines without reviewing the diff.
  7. Integrate into CI. Add the test to your pipeline so it runs on every pull request. Configure the tool to fail the build if there are unreviewed diffs. This ensures visual regressions are caught before merge.

Common Mistakes

  • Not isolating data rows. If tests share state (e.g., a logged-in user persists), one row can affect another. Always reset state—clear localStorage, cookies, or use a fresh browser context per test.
  • Hardcoding viewport sizes inside the test. That defeats the purpose of data-driven testing. Keep all variables in the data file.
  • Ignoring dynamic content. Dates, timestamps, or random IDs will cause false diffs. Mock or freeze time, or use fixed data in your test environment.
  • Updating baselines without reviewing. It’s tempting to click “accept all” when you see many diffs. You might miss a real regression. Always review each diff.
  • Running on local machine only. Visual results vary by OS and browser version. Run in CI with a consistent environment (e.g., same Docker image) to avoid flaky diffs.

Tips

  • Start small. Begin with 5–10 data rows covering the most critical states: different user roles, both themes, and 2–3 viewports (mobile, tablet, desktop).
  • Use descriptive names. Name your screenshots by the data row (e.g., admin-dark-mobile.png) so you can quickly identify what failed.
  • Combine with functional tests. Run visual checks after your functional assertions pass, so you’re not debugging a broken page.
  • Set a pixel threshold. Some tools allow a tolerance (e.g., 0.1% diff) to ignore anti-aliasing. Use it sparingly—too high a threshold hides real bugs.
  • Version your data file. Treat your test data like code. Review changes to the data file in PRs.

Troubleshooting

  • Too many diffs on first run. Likely because your baseline wasn’t captured in the same environment (browser, OS, screen resolution). Re-capture baselines in your CI environment.
  • Tests pass locally but fail in CI. This is usually an environment mismatch—fonts, rendering engines, or browser versions. Use Docker or a fixed browser version in CI.
  • “Cannot find baseline” error. The baseline image is missing. Run the test once with --update-snapshots to create it.
  • Flaky diffs due to animations. Disable CSS animations in your test (e.g., page.addStyleTag({ content: '* { animation: none !important; }' })) or wait for animations to finish before screenshot.
  • Data file not loading. Check the import path and that the JSON is valid. Use require() instead of import if you’re in a CommonJS environment.

Frequently Asked Questions

Do I need a paid tool for visual testing?

No. Playwright’s built-in toHaveScreenshot is free and works well for most projects. Paid tools like Percy or Applitools offer advanced features like cross-browser grids and AI-based diff analysis, but they’re not required to start.

How do I handle dynamic data like dates in screenshots?

Mock the date using your test framework (e.g., Playwright’s page.clock) or replace dynamic content with fixed test data in your app’s test mode.

Can I run data-driven visual tests on multiple browsers?

Yes. Most tools support Chromium, Firefox, and WebKit. Run the same data set in each browser project. Be aware that baselines are browser-specific.

What’s the best way to store test data?

JSON is easiest for most projects. For larger datasets, consider YAML for readability or a database if you need to generate data dynamically. Keep it in version control.

How often should I update baselines?

Only when the UI change is intentional and reviewed. Avoid updating baselines as a reflex to a failing test—investigate the diff first.

Can I use data-driven visual tests with component libraries?

Yes. You can test individual components by rendering them in a test harness (like Storybook) and running visual checks against each story with different props.

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 →