ScreenshotNeo

BlogHow-to

How to Set Up Screenshot Tests for a React Website in an Indian CI Pipeline

Set up Playwright screenshot comparisons for a React app in CI, keep baselines reproducible, and debug visual failures. The workflow applies to teams in India without requiring an India-based runner.

By the ScreenshotNeo team4 October 20268 min read

Use Playwright Test’s toHaveScreenshot() assertion to capture a React page and compare it with a checked-in reference image. Run the same Playwright version, browser, operating system, fonts, and app data when creating and checking baselines. An Indian team can use the same portable Linux CI workflow as any other team; the country qualifier alone does not require an India-based runner.

This guide uses Playwright Test with a Vite-style preview server and GitHub Actions as a concrete example. Adjust the server command, port, Node version, action versions, and environment variables to match your repository. The same test can run in other CI systems that provide Node, the required browser dependencies, and artifact storage.

1. Add Playwright Test and a visual assertion

Install @playwright/test using your project’s package manager and commit the resulting lockfile. Follow the current Playwright installation documentation for your package manager and project structure. Add a test such as tests/homepage.spec.ts:

import { test, expect } from '@playwright/test';

test('home page matches its visual baseline', async ({ page }) => {
  await page.goto('/');
  await expect(page).toHaveScreenshot('home.png');
});

The first run creates a reference screenshot. Review it for correctness, then commit the generated snapshot alongside the test. Later runs compare the current screenshot with that reference. Give snapshots clear names and test stable, representative routes or states first, such as the home page, navigation, an important form, or a key user flow.

2. Configure the React server and test environment

Playwright’s configuration supports webServer and use.baseURL, so a test can start the app and navigate with relative paths. This example assumes a Vite preview server on port 4173; confirm the correct command and port for your app.

import { defineConfig } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  workers: process.env.CI ? 1 : undefined,
  reporter: process.env.CI ? [['html', { open: 'never' }]] : 'list',
  use: {
    baseURL: 'http://127.0.0.1:4173',
    trace: 'retain-on-failure',
  },
  webServer: {
    command: 'npm run preview -- --host 0.0.0.0',
    url: 'http://127.0.0.1:4173',
    reuseExistingServer: !process.env.CI,
  },
});

For a build-preview workflow, make sure CI builds the app before Playwright starts. One option is to make the preview script build first, or add an explicit build step before the test command. If tests need an API or another service, configure additional web servers or start dependencies in the CI job. Set test data and environment variables deliberately so the same route produces the same content.

3. Run the test locally and create reviewed baselines

  1. Start from the repository root and install the locked dependencies with your package manager.
  2. Install the Playwright browser required by the project, following its install documentation.
  3. Run npx playwright test. The configured server starts automatically if needed.
  4. Inspect any newly generated reference image at the configured snapshot path. Confirm it represents the intended page and viewport.
  5. Commit the test and approved reference images together.

To intentionally accept a design change, run npx playwright test --update-snapshots, inspect the changed images, and commit the reviewed updates. Avoid automatically updating baselines on every CI run: doing so would replace the reference instead of flagging unexpected changes.

4. Add a GitHub Actions job

Playwright’s CI guide documents installing Node dependencies, browser binaries, and Linux dependencies before running tests. This workflow follows that pattern and uploads the HTML report when the job is not cancelled:

name: Visual tests
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-node@v6
        with:
          node-version: lts/*
      - run: npm ci
      - run: npx playwright install --with-deps
      - run: npx playwright test
      - uses: actions/upload-artifact@v5
        if: ${{ !cancelled() }}
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 30

The action versions above are those shown in the current Playwright CI documentation; use versions permitted by your repository policy and review updates periodically. If your workflow builds the React app separately, add that build step before running Playwright. Make sure the report path matches your Playwright reporter configuration.

5. Keep screenshot comparisons reproducible

Playwright documents that screenshot rendering can vary with operating system, browser version and settings, hardware, power source, and headless mode. For reliable comparisons:

  • Generate baselines in the same operating system and browser environment used by CI. A documented Playwright container workflow can help standardize the environment.
  • Keep Playwright versions controlled by the package lockfile and install the browser version that matches that Playwright release.
  • Use deterministic fixtures, stable test accounts, and predictable API responses. Avoid dates, rotating banners, random content, and live data in screenshot routes where possible.
  • Set the intended viewport and browser projects explicitly when your tests cover multiple sizes or browsers. Treat each rendering environment as potentially needing its own baseline.
  • Use one CI worker initially. Increase workers or shard jobs only when runtime justifies the added resource use and you can collect results consistently.
  • Do not cache browser binaries by default without measuring the benefit. Playwright’s CI guide notes that restoring a cache can take as long as downloading browsers, while Linux system dependencies are not cacheable.

6. Control dynamic regions and comparison sensitivity

First eliminate avoidable variability in the app and test data. When a small region is genuinely volatile and not part of what the test should validate, Playwright supports stylePath to apply a screenshot stylesheet. Use masking narrowly: hiding a large or meaningful part of the page can conceal a real regression.

Screenshot assertions also accept comparison options such as maxDiffPixels. Set a threshold only after inspecting actual diffs and deciding which rendering variation is acceptable for the project. A permissive threshold can make the test miss meaningful changes; a very strict threshold can flag small rendering noise. Keep the chosen value explicit and reviewed.

7. Debug failures and protect artifacts

When a comparison fails, inspect the expected image, actual image, and generated diff. Then review the test output and HTML report. With trace: 'retain-on-failure', use the Playwright trace viewer to inspect the page and actions leading up to the capture. Confirm the app loaded the intended route and data before changing a baseline or threshold.

Reports, traces, and logs can contain credentials, tokens, source code, or application information. Store them only in trusted artifact storage, set appropriate retention, and limit access. Avoid placing secrets directly into test output or captured page content.

Common problems and fixes

Symptom Likely cause Fix
Browser executable is missing The job installed npm packages but not the matching Playwright browser. Run npx playwright install --with-deps in Linux CI, or install the required browser according to the Playwright docs.
Server readiness times out The command or readiness URL is wrong, the app failed to build, or the server binds to another interface. Check server logs, app scripts, port, host binding, and webServer.url. Ensure build output exists before preview starts.
Every run shows visual diffs Local and CI environments differ in OS, browser, fonts, settings, viewport, or headless mode. Create and verify baselines in the same environment as CI; pin dependencies and browser versions through the project setup.
Only text or timestamps differ Data, locale, timezone, animation, or time-dependent content is unstable. Use fixed fixtures and deterministic locale/time settings where appropriate; disable or narrowly mask genuinely irrelevant volatile content.
Snapshot update changes too many files The command regenerated references across projects or routes. Review the diff carefully, run only the intended test or project where possible, and revert unintended changes before committing.
Test passes locally but fails in CI Different dependencies, missing service, environment variable, font, or resource constraint. Compare lockfile install, browser version, server command, test data, and CI logs. Start with one worker to reduce contention.
Artifact contains sensitive data Trace, report, or screenshot captured credentials or private app content. Restrict artifact access and retention, use non-sensitive fixtures, and avoid logging secrets.

What changes for an Indian team?

The test commands do not change because the team is in India. Choose a runner based on your source hosting, Linux or container support, access to required test services, artifact controls, and your organization’s cost or region requirements. The Playwright documentation cited here does not establish India-specific runner pricing, regional availability, data residency, or performance comparisons, so verify those requirements with the CI provider if they matter.

If the React product serves users in India, include representative Indian language, content, currency, and viewport states in the test suite where they affect rendering. That is a test coverage decision; it does not by itself mean the CI runner must be located in India.

Or skip the browser setup

For captures of deployed pages, ScreenshotNeo offers a one-call website screenshot API and an MCP server for AI agents. This is a separate option from Playwright’s in-repository visual regression tests: it returns a screenshot or PDF, while Playwright’s assertion compares your page against committed baselines.

See the ScreenshotNeo API documentation for request options. Example cURL call:

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://stripe.com \
  -o shot.webp

Python:

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://stripe.com',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));

ScreenshotNeo accepts cookie and consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and responses indicate the page verdict and billing status in headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.

Sign up free for 1,000 screenshots a month, no card required.

FAQ

Do I need to run CI in India?

No location requirement follows from screenshot testing itself. Select a region based on your organization’s data, access, and policy requirements.

Should I commit screenshot baselines?

Yes. Treat reviewed references as test inputs in version control so changes are visible in code review and comparisons remain repeatable.

Can screenshot tests replace functional tests?

No. Visual comparisons detect rendered appearance changes; keep assertions for behavior, accessibility, and application logic as separate checks.

Can ScreenshotNeo compare a pull request with a baseline?

The product facts here describe screenshot capture and PDF output, not committed-baseline comparison. Use Playwright’s screenshot assertion for the baseline comparison workflow shown above.