ScreenshotNeo

BlogHow-to

How to Create Playwright Screenshot Tests for an Indian Ecommerce Site in Rupees

Build stable Playwright visual tests for an Indian ecommerce site: control locale and data, assert INR prices, and review screenshot baselines.

By the ScreenshotNeo team4 October 20269 min read

Use Playwright Test’s toHaveScreenshot() to compare an Indian ecommerce page or component against a reviewed reference image. Make the test deterministic: set the browser locale and timezone explicitly, use fixed product and promotion data, assert the displayed INR price as text, then capture the relevant region. Generate and review the baseline in the same browser and operating system environment used for later runs.

A screenshot checks visual presentation such as alignment, clipping, and typography. A separate locator assertion checks the exact price string, so a visual diff does not have to explain whether the amount or currency formatting is wrong. This guide uses a product page as an example; adapt its route, test IDs, fixture setup, and expected string to your application.

1. Set up a deterministic Playwright test

If the project does not already use Playwright Test, install it and initialize the test runner using the official Playwright installation guide. The example below assumes @playwright/test is installed, the application is running, and the test runner has a baseURL configured for local tests.

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

export default defineConfig({
  use: {
    baseURL: 'http://127.0.0.1:3000',
    browserName: 'chromium',
    locale: 'en-IN',
    timezoneId: 'Asia/Kolkata',
    viewport: { width: 1280, height: 800 },
  },
});

Use en-IN and Asia/Kolkata when those match the storefront’s requirements. Locale and timezone are configurable emulation settings in Playwright; they can be set at project scope or for an individual test. If the storefront intentionally uses another locale or timezone policy, configure that explicitly instead. See Playwright’s emulation documentation.

Provide a stable route or fixture with known values for the product name, price, image, stock status, promotion, cart quantity, and signed-in state. Avoid relying on a live catalog or rotating promotion: changes in data can make a screenshot fail even when the page rendering code is unchanged.

2. Assert the INR price and capture the page

Give important elements stable selectors such as data-testid. The example checks a specific display contract, then captures the product page:

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

test('product page displays the expected INR price', async ({ page }) => {
  await page.goto('/products/test-product');

  const price = page.getByTestId('product-price');
  await expect(price).toHaveText('₹1,23,456.00');
  await expect(page).toHaveScreenshot('product-page-inr.png');
});

The expected text is illustrative. Confirm the exact symbol, spacing, decimal places, and grouping that your design system promises. A valid localized currency string can differ in symbol placement or spacing depending on formatting choices, so encode the application’s intended contract rather than assuming a universal representation.

For a focused check, capture the price panel or product card instead of the whole page:

const price = page.getByTestId('product-price');
const card = page.getByTestId('product-card');

await expect(price).toHaveText('₹1,23,456.00');
await expect(card).toHaveScreenshot('product-card-inr.png');

A component screenshot is usually easier to diagnose and less exposed to unrelated page changes. Use a full-page screenshot when content outside the component, such as the cart summary or page-level layout, is part of the behavior being protected. Playwright’s screenshot assertion waits for two consecutive screenshots to match before comparing, which helps with transient rendering but does not replace deterministic test data or stable network responses. See Playwright visual comparisons.

3. Format and test rupee values deliberately

INR currency and Indian digit grouping are related but separate requirements. Specify both the locale and the ISO 4217 currency code in application code. For example:

const formatter = new Intl.NumberFormat('en-IN', {
  style: 'currency',
  currency: 'INR',
});

formatter.format(123456.78);

Intl.NumberFormat with en-IN supports Indian grouping, such as grouping digits into lakh and crore positions. The precise currency string depends on the formatter’s options and runtime. The application should define whether decimals are shown, whether the symbol or currency code is used, and where whitespace appears. See MDN’s NumberFormat constructor reference and MDN’s Intl.NumberFormat guide.

Choose fixture prices that exercise formatting boundaries and the actual storefront behavior: a value that needs Indian grouping, a decimal amount if applicable, a sale price, and a discount. For checkout, assert subtotal, shipping, tax, and final total independently with known fixture data. Keep the arithmetic and text checks separate from the screenshot assertion; that makes failures specific and actionable.

4. Create, review, and maintain screenshot baselines

  1. Run the test to create its first reference. Playwright creates a baseline on the first run of a screenshot assertion. Give the snapshot an explicit, descriptive name.
  2. Inspect the generated image. Confirm that the product data, price, fonts, images, and layout represent the intended state.
  3. Commit the baseline with the test. Keep it under version control so future comparisons have a reviewed reference.
  4. Run comparisons in a consistent environment. Use the same operating system or container, browser version, viewport, and rendering settings used to generate the reference. Playwright documents that rendering can vary by operating system, browser version, settings, hardware, power state, and headless mode. Its guidance is: “For consistent screenshots, run the test in the same environment where the baseline was generated.”
  5. Review diffs before updating. When a visual change is intentional, update the snapshots with the test runner’s --update-snapshots flag and inspect the resulting image diff before committing it. Do not accept a new baseline just because a test failed; a changed price display may be a regression.

See Playwright’s baseline and comparison guidance for snapshot storage and updating references.

5. Keep dynamic content from making the test noisy

Wait for the state you intend to capture. Ensure the product image and web fonts have loaded if they affect layout. Prefer test fixtures and controlled responses for application data over timing delays. A fixed delay can help only when a known animation or delayed transition is part of the test; it is not a reliable substitute for waiting on a visible state or response.

For content that is genuinely volatile and outside the test’s scope—such as a rotating banner or timestamp—hide it with a screenshot stylesheet or mask a specific region. Playwright supports screenshot styling through stylePath; consult the screenshot assertion options. Do not hide or mask the rupee price when price formatting is the behavior under test. Keep comparison tolerances narrow and deliberate: an overly permissive threshold can let meaningful layout changes pass.

6. Choose a useful screenshot scope and viewport

Test scope Use it when Trade-off
Price element or price panel Currency display, price alignment, or sale-price styling is the focus. It says little about the surrounding product page.
Product card Price, title, image, and card layout should be reviewed together. More unrelated card changes can cause diffs.
Full page The whole page layout or multiple related regions are in scope. More dynamic areas can make failures harder to diagnose.

Start with one stable viewport. Add mobile or tablet projects when responsive INR presentation is a requirement, and keep their baselines separate. Avoid adding operating systems or browser combinations without a reason: each rendering environment can produce its own reference images and comparison results.

7. Troubleshooting common failures

Symptom Likely cause Fix
The price text assertion fails although the amount looks correct. The app and test disagree on spacing, decimal digits, currency symbol, or locale formatting. Inspect the actual rendered text and set an explicit formatting contract in the application. Assert that contract, including whitespace and decimals where they matter.
The screenshot changes on every run. Dynamic data, animation, timestamps, third-party content, images, or fonts are still changing. Use fixed fixtures and controlled responses, wait for the intended state and required assets, and hide only volatile content outside the test’s scope.
A baseline looks different in CI than on a developer machine. The operating system, browser version, fonts, headless mode, or rendering environment differs. Generate and compare references in the same pinned browser and host environment, such as the same CI container.
A screenshot passes while the wrong currency is shown. The visual comparison is not a precise semantic check, or the baseline was updated without review. Add a locator text assertion for the exact expected amount and currency. Review all baseline changes before accepting them.
The full-page capture is slow or noisy. The page contains long or lazy-loaded content that is outside the behavior under test. Capture a stable component or region when appropriate. Use full-page capture only when the whole page is in scope.
Small antialiasing differences create a diff. Rendering settings or environment differ, or the comparison threshold is too strict for the stable environment. First align the environment. Adjust pixel-difference options only narrowly and review that the tolerance does not hide meaningful changes.

8. Performance, reliability, and cost

Visual tests require browser rendering and image comparison, so keep the suite focused on valuable states rather than capturing every page at every viewport by default. Component captures, fixed fixtures, and a small set of intentional viewport projects reduce unrelated work and make failures easier to review. No single runtime estimate applies across projects because page weight, browser environment, and test setup vary.

Reliability depends on repeatable inputs and a consistent rendering environment. Screenshot stability cannot guarantee correct commerce logic: assert amounts and totals semantically, and use the image to catch presentation regressions. Store reviewed baselines alongside tests so changes remain traceable.

Playwright is an open-source test framework; this workflow’s direct costs depend on the infrastructure used to run browser tests and retain artifacts. If maintaining browser installation, fixtures, and screenshot infrastructure is not the right fit for a particular capture workflow, a screenshot API is another option.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. Make a GET request with a URL to receive a PNG, JPEG, WebP, or PDF. Its clean-shot options accept cookie and consent banners like a visitor and remove more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses identify the page verdict and billing status in headers.

This is a URL-based capture service, so it does not replace Playwright’s assertions against seeded application state or its reviewed visual baselines. Use it when you need a clean screenshot without setting up a browser capture flow. The ScreenshotNeo API documentation lists the available parameters.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
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 Bun.write('shot.webp', res);

Replace the example URL with the page you are authorized to capture. ScreenshotNeo also offers an MCP server for AI agents, with take_screenshot, get_page_info, and capture_pdf. Plans include 1,000 screenshots per month free with no card; paid plans start at $5 for 3,000 screenshots. Sign up for 1,000 free screenshots a month, with no card required.

FAQ

Should I assert the rupee price with a screenshot alone?

No. Assert the exact rendered price as text, then use the screenshot to check its visual presentation.

Does en-IN guarantee one exact INR string?

No. The locale influences grouping and formatting, but the application’s options and runtime affect the final string. Define and assert the format your storefront intends to show.

When should I update a reference screenshot?

After confirming the UI change is intended and inspecting the new baseline diff. A test failure by itself is not a reason to approve a changed reference.

Should every product page have a full-page baseline?

Only when full-page appearance is part of the requirement. For price formatting, a price panel or product-card screenshot is often a more focused check.