Ecommerce Testing

Product Page Testing: Verify Product Data, Variants, Price, and Stock

Verify ecommerce product pages by testing product data, selected variants, SKU resolution, current price, availability, quantity rules, media, accessibility and add-to-cart evidence.

WrightTest TeamApproximately 18 min read
Product page testing flow from visible product data through variant selection, SKU resolution, pricing, availability and add-to-cart verification.
Product page testing connects what the customer sees with the SKU, price, availability and cart line the system accepts.

A customer opens a product page for running shoes, selects Blue / Size 42, and clicks Add to cart.

The page shows:

Colour: Blue
Size: 42
Price: $80.00
Availability: In stock

The cart receives:

SKU: SHOES-BLACK-40
Colour: Black
Size: 40
Price: $75.00

Nothing crashed. The Add-to-cart request returned successfully. The cart even contains a product.

The transaction is still wrong.

Product page testing must prove that the item presented to the customer is the same sellable item accepted by the cart:

Visible product
→ selected options
→ resolved SKU
→ current price
→ current availability
→ cart request
→ stored cart line

This is the boundary covered by this article. Checkout, payment, order creation, and post-purchase processing belong to later stages of the ecommerce journey.

For the wider testing strategy, see Ecommerce Testing.

For release-level coverage across the complete purchase flow, use the Ecommerce Website Testing Checklist.

For the broader test library, see Ecommerce Test Cases.

What Product Page Testing Must Prove

A catalogue page usually identifies a product family. The product page resolves the exact item the customer intends to buy.

For a simple product, this may mean one SKU and one price.

For a configurable product, the final item may depend on:

  • colour;
  • size;
  • material;
  • capacity;
  • subscription plan;
  • licence type;
  • seller;
  • customer group;
  • region;
  • bundle composition.

A useful product-page test connects five states:

StateExample
Product familyRunning Shoes
Selected optionsBlue, size 42
Resolved identitySHOES-BLUE-42
Commercial state$80.00, available
Accepted cart lineSHOES-BLUE-42, quantity 1, $80.00

The core invariant is:

The product identity, selected options, price, availability, and quantity accepted by the customer must match the item submitted to and stored in the cart.

In practice, four checks provide most of the value:

  1. Selected options resolve to the correct SKU.
  2. Visible price matches the authoritative cart price.
  3. Stale or unavailable stock is handled truthfully.
  4. The stored cart line matches the customer’s final selection.

A broken review carousel is worth fixing. It is not equivalent to adding the wrong SKU.

Define the Product Contract and Test Data

Before writing automated tests, document which systems own product identity, price, and inventory.

A controlled product contract might look like this:

{
  "productId": "PROD-20418",
  "slug": "running-shoes",
  "name": "Running Shoes",
  "selectedOptions": {
    "colour": "Blue",
    "size": "42"
  },
  "sku": "SHOES-BLUE-42",
  "currency": "USD",
  "unitPrice": 8000,
  "availableQuantity": 3,
  "minimumQuantity": 1,
  "maximumQuantity": 3,
  "customerGroup": "retail",
  "region": "US",
  "purchasable": true
}

Representing money in minor units can make comparisons explicit and avoid accidental floating-point values such as 79.999999.

The contract should answer:

  • Which service owns the product and variant identifiers?
  • Which service calculates the current price?
  • Which service owns available inventory?
  • At what stage is stock reserved?
  • Can price or stock change after the page loads?
  • Does Add to cart revalidate the product state?
  • Can region or customer group change the offer?
  • Are unavailable combinations hidden, disabled, or shown as unavailable?
  • How are bundles and customisations represented in the cart?

Without these rules, a test can detect a mismatch without knowing which state is authoritative.

Controlled product fixtures

Avoid using random products from a shared catalogue for the core regression suite.

A product can change because of imports, merchandising, another test, or an administrator. Controlled fixtures make failures reproducible.

Prepare at least:

FixturePurpose
Simple productBasic identity, price, and Add-to-cart flow
Multi-variant productOption selection and SKU resolution
Unavailable variantDisabled and server-rejected combinations
Last-unit variantStock boundary and concurrency
Out-of-stock productPurchase prevention
Promotion-eligible productDiscount presentation
Promotion-excluded productEligibility boundary
Customer-group productSegmented visibility or pricing
Region-restricted productLocation-based purchasing rules
Product with media galleryImage and variant-media behaviour

A multi-variant fixture should describe each supported combination:

{
  "product": "Running Shoes",
  "variants": [
    {
      "colour": "Blue",
      "size": "41",
      "sku": "SHOES-BLUE-41",
      "price": 8000,
      "stock": 4
    },
    {
      "colour": "Blue",
      "size": "42",
      "sku": "SHOES-BLUE-42",
      "price": 8000,
      "stock": 3
    },
    {
      "colour": "Black",
      "size": "42",
      "sku": "SHOES-BLACK-42",
      "price": 8500,
      "stock": 0
    }
  ]
}

This lets the test verify the actual option-to-SKU mapping instead of checking only whether a button appears selected.

Product Identity and Content

The product page should describe the same product returned by the authoritative catalogue source.

For commercially important fields, compare the product API, visible page, and cart request.

LayerExample
Product APISHOES-BLUE-42
Visible pageBlue, size 42
Cart requestSHOES-BLUE-42

Verify the fields relevant to the product:

  • product name;
  • product ID;
  • SKU or model number;
  • brand;
  • seller;
  • description;
  • specifications;
  • price and currency;
  • availability;
  • fulfilment type;
  • return or delivery information;
  • canonical URL.

Do not assert a visible SKU merely to create another UI check. When SKU is not customer-facing, compare the selected options with the cart request or cart API instead.

Incomplete content

Optional content should fail without disabling the purchase path.

Test products with:

  • no secondary image;
  • missing variant image;
  • empty optional specification;
  • unavailable reviews;
  • unavailable recommendations;
  • missing compare-at price;
  • delayed delivery estimate.

A recommendation outage should not prevent a customer from selecting and buying a valid product.

Required commercial data needs stricter handling. The page should not invent a price, stock state, or product identity when the authoritative value is unavailable.

Variant and SKU Resolution

Product variant and SKU testing flow showing option selection, resolved SKU, price, availability, image and cart request alignment.
Variant tests should prove that selected options resolve to the same SKU, price, availability and media used by the cart.

Variant selection is usually the highest-risk part of a configurable product page.

Changing an option may affect:

SKU
Price
Availability
Image
Shipping class
Promotion eligibility
Purchase limit
Seller
Delivery estimate

Treat the variant as a resolved business object, not merely a highlighted colour or size button.

Initial and partial selection

Determine whether the page:

  • starts with no selection;
  • preselects a documented default;
  • restores a selection from the URL;
  • restores a previous customer choice;
  • automatically selects the only available combination.

The behaviour must be visible and deliberate.

A hidden default is dangerous. When Blue appears selected but the request submits Black, the customer has little chance to notice the error.

For a product requiring both colour and size, selecting only colour should not silently resolve an unrelated default size unless this is an explicit product rule.

Check that:

  • incomplete selection is communicated;
  • Add to cart remains unavailable or shows a specific validation error;
  • no unintended SKU is submitted;
  • completing the selection updates all dependent fields.

Unavailable combinations

A product can handle an unavailable combination in several valid ways:

  • hide it;
  • disable it;
  • show it as unavailable;
  • offer a back-in-stock action;
  • keep it visible but unavailable in the current region.

The server must enforce the same restriction.

A disabled browser control does not prevent a modified request from submitting an unavailable SKU.

Race conditions during rapid selection

Variant responses can arrive in a different order from the customer’s clicks:

Customer selects Blue
→ Blue request starts

Customer selects Black
→ Black request starts

Black response returns
→ page shows Black

Blue response returns late
→ page incorrectly returns to Blue data

Delay variant responses and switch options rapidly.

The final SKU, price, stock, image, and cart request must belong to the customer’s latest accepted selection.

This race condition is easy to miss in a normal happy-path test because every response usually returns quickly and in order.

Price, Availability, and Quantity

A product page may display:

  • regular price;
  • sale price;
  • customer-group price;
  • subscription price;
  • quantity-tier price;
  • tax-inclusive or tax-exclusive price;
  • marketplace seller price;
  • minimum bundle price.

A currency symbol alone proves very little.

Verify the amount together with:

  • selected variant;
  • currency;
  • customer group;
  • region;
  • seller;
  • tax presentation;
  • promotion eligibility;
  • quantity conditions.

Variant and promotion pricing

When selecting another variant:

  1. The displayed price should update.
  2. The resolved SKU should update where required.
  3. Add to cart should submit the selected item.
  4. The cart should apply the authoritative price.
  5. Returning to the original variant should restore its price.

The browser should not be trusted as the owner of the final price. Compare what the customer saw with what the cart accepted.

For promotions, check that:

  • expired discounts are removed;
  • excluded variants do not inherit the offer;
  • percentage labels match the real calculation;
  • customer-specific discounts are not exposed to ineligible users;
  • minimum quantity requirements are visible;
  • campaign text does not promise a price the cart rejects.

The product page may display an estimate. The cart still needs to reconcile the authoritative commercial result.

Availability changes

Availability is not always a single inStock flag.

Common states include:

In stock
Low stock
Backorder
Preorder
Out of stock
Region unavailable
Customer restricted
Temporarily unavailable

A page can load with one unit available, then lose that unit before the customer clicks Add to cart.

The expected result depends on the reservation policy:

  • reject the addition;
  • add the line but reject later;
  • create a temporary reservation;
  • offer a backorder;
  • choose another fulfilment source.

The important point is that the application returns a truthful state. It should not confirm availability that no longer exists.

Quantity boundaries

Test the values that can cross the business boundary:

  • zero;
  • negative quantity;
  • minimum minus one;
  • exact minimum;
  • exact maximum;
  • maximum plus one;
  • available stock;
  • available stock plus one;
  • decimal quantity;
  • pasted text;
  • non-numeric input;
  • repeated increment clicks.

The server should enforce the same rule as the browser.

Silently changing 11 to 10 is usually weaker than rejecting the value and explaining the limit.

Last-unit concurrency

Open the same last-unit variant in two independent customer sessions.

Allow both customers to see the item, then perform the action that triggers reservation according to the product’s actual policy.

Verify:

  • inventory does not become negative;
  • only the permitted transaction succeeds;
  • no duplicate reservation remains;
  • the losing customer receives a truthful result;
  • stale availability eventually updates;
  • the successful transaction can be identified in inventory records.

The browser can reproduce the two customer journeys. Inventory and order records provide the decisive evidence.

The Add-to-Cart Boundary

Product page add-to-cart testing boundary comparing visible product data, selected options, quantity, price and stored cart line.
The add-to-cart boundary is where the visible product selection becomes stored cart state.

The most important product-page assertion happens after the customer clicks Add to cart.

The accepted cart line should match:

Product ID
SKU
Selected options
Seller
Quantity
Unit price
Currency
Customisation
Subscription choice
Bundle components

A direct comparison makes the expected result clear:

Product pageCart
BlueBlue
Size 42Size 42
SHOES-BLUE-42SHOES-BLUE-42
Quantity 1Quantity 1
$80.00$80.00
Retail customerRetail price

A success toast is not enough. Verify the accepted request or resulting cart state.

Repeated clicks and delayed requests

Rapid clicks during a slow request can create:

  • duplicate lines;
  • unintended quantity;
  • conflicting messages;
  • multiple requests;
  • a button that never recovers.

The correct outcome depends on the cart policy. It may be one line with quantity 1, one merged line with a deliberate quantity, or one accepted request while duplicate submissions are ignored.

The outcome should not depend on how many times a frustrated customer clicked during a delayed response.

Failures and lost responses

Simulate:

  • cart service unavailable;
  • stale product version;
  • changed price;
  • changed stock;
  • invalid variant;
  • expired session;
  • lost network response.

The message shown to the customer should match the actual cart state.

Do not display Added to cart before the cart has accepted and stored the line.

A difficult case occurs when the cart accepts the item but the browser loses the response. Retrying should reconcile the existing cart rather than creating an unexplained duplicate.

The recovery message should answer practical questions:

  • Was the item added?
  • Was the selected variant preserved?
  • Did the price change?
  • Is another attempt safe?
  • What should the customer do next?

Customer and Regional Restrictions

The same product may have different commercial states for different customers.

Relevant context can include:

  • authenticated or guest state;
  • customer group;
  • organisation or tenant;
  • subscription status;
  • country;
  • delivery region;
  • sales channel;
  • marketplace seller.

Test the controlled product under each supported context.

Compare:

  • visibility;
  • price;
  • currency;
  • stock source;
  • quantity limit;
  • promotion eligibility;
  • delivery eligibility;
  • purchase controls.

A restricted product should not become purchasable through a copied URL or modified Add-to-cart request.

Client-side visibility is not an authorisation boundary.

Product Page Experience

Images, responsive layout, accessibility, and performance matter because they affect whether customers can understand and configure the product.

They should not overshadow the commercial contract, but they should not be treated as decoration either.

Images and media

Test the primary image, thumbnails, gallery navigation, zoom, video, and variant-specific media where supported.

Focus on commercially meaningful behaviour:

  • the selected colour shows the intended product;
  • changing size does not unexpectedly reset colour media;
  • a late image response does not replace the current variant;
  • the cart thumbnail matches the selected item;
  • missing secondary media does not block purchase;
  • image loading does not create disruptive layout movement;
  • responsive images are sized for the rendered device.

A failed image should not remove the product title, price, options, or Add-to-cart control.

Accessibility and keyboard use

Product pages often contain custom controls such as colour swatches, size selectors, quantity steppers, galleries, accordions, and sticky purchase panels.

Check that:

  • each option has an accessible name;
  • option groups have descriptive labels;
  • selected state is exposed;
  • unavailable state is exposed;
  • colour is not the only identifier;
  • focus remains visible;
  • keyboard users can configure the product;
  • validation identifies the missing selection;
  • important price, stock, and cart updates are perceivable;
  • variant images retain meaningful alternative text.

A blue circle without an accessible name does not communicate the option to every customer.

Complete the main product flow using only the keyboard:

Open product
→ inspect options
→ select variant
→ change quantity
→ add to cart
→ inspect confirmation or mini-cart

Focus should not disappear or return to an unrelated element when a mini-cart or dialog closes.

Mobile behaviour

On mobile, images, product options, price, stock, and Add to cart may be separated by long content and sticky controls.

Check that:

  • variant selectors remain usable;
  • sticky controls do not cover options;
  • the sticky Add-to-cart button uses the current selection;
  • price and stock remain visible at the decision point;
  • validation messages are not hidden;
  • orientation changes preserve the product state;
  • image zoom can be closed normally;
  • the on-screen keyboard does not block customisation or quantity input.

A common mobile defect is a sticky button holding an older SKU or price than the main product form.

Performance and dependency failures

Product pages often combine large media, pricing, inventory, recommendations, reviews, personalisation, and analytics.

Measure the page as a purchasing surface, not only as a URL that eventually finishes loading.

Verify:

  • product identity and price appear without waiting for secondary widgets;
  • Add to cart is enabled only when the required state is ready;
  • variant selection remains responsive;
  • recommendations or reviews cannot block purchase;
  • slow inventory produces a controlled state;
  • delayed variant responses cannot overwrite the latest choice;
  • image loading does not cause disruptive movement;
  • repeated requests are cancelled or reconciled safely.

A fast initial render is not enough when selecting a size freezes the page or leaves the purchase button using stale data.

Product Structured Data

Where the page publishes Product structured data, compare it with the visible and authoritative product state.

Relevant fields can include:

  • name;
  • image;
  • SKU;
  • brand;
  • price;
  • currency;
  • availability;
  • rating;
  • shipping information;
  • return information.

Check that:

  • structured product identity matches the page;
  • price and currency describe the intended offer;
  • availability is not stale;
  • review values use the correct source;
  • canonical and structured URLs agree;
  • restricted or unpublished products do not expose misleading offers;
  • variant representation follows the site’s chosen search strategy.

Structured data is another representation of the product. It should not contradict what the application is actually selling.

Core Product Page Test Cases

The following 20 cases provide focused product-page coverage without repeating the complete ecommerce test library.

Identity and Variants

IDPri.ScenarioExpected resultEvidence
PDP-001P1Open a controlled product from its catalogue cardProduct identity, price, and availability match the linked catalogue itemCatalogue and product responses
PDP-002P1Open a direct product URLThe intended product loads without bypassing visibility rulesHTTP and product state
PDP-003P1Select a non-default variantOptions resolve the correct SKU, price, stock, and mediaVariant response and page state
PDP-004P1Leave one required option unselectedNo unintended default SKU is submittedValidation and cart request
PDP-005P1Select an unavailable combinationUI and server both prevent purchaseUI state and server response
PDP-006P1Change variants rapidly under delayed responsesFinal state belongs to the latest selectionNetwork order and page state
PDP-007P1Restore a variant from a URLURL, selected controls, SKU, and price agreeURL and resolved product state

Price, Stock, and Quantity

IDPri.ScenarioExpected resultEvidence
PDP-008P1Select a higher-priced variantPage and cart use the selected variant priceProduct and cart comparison
PDP-009P1Open an expired promotionExpired pricing is removed or rejected truthfullyPricing response
PDP-010P1Change currency or customer contextPage and cart stay in the same commercial contextPrice, identity, and cart line
PDP-011P1Enter quantity boundariesValid values pass; invalid values are rejected without silent corruptionValidation and cart state
PDP-012P0Attempt to purchase the final unit from two sessionsThe reservation policy allows only the documented valid outcomeInventory and order records
PDP-013P1Change stock after the page loadsAdd to cart revalidates and returns a truthful resultInventory and cart response

Add to Cart and Restrictions

IDPri.ScenarioExpected resultEvidence
PDP-014P0Add the selected variantCart line matches SKU, options, quantity, price, and currencyAdd-to-cart response and cart
PDP-015P1Click Add to cart repeatedly during a delayed responseOne deliberate cart result is produced according to policyRequests and final cart state
PDP-016P1Lose the response after the cart accepts the itemReopening or retrying reconciles the existing cart stateCart ID and line state
PDP-017P1Submit a restricted product through a modified requestServer rejects the purchase under the same eligibility rulesAuthorisation and cart response

Experience

IDPri.ScenarioExpected resultEvidence
PDP-018P1Configure and add the product using keyboard onlyControls remain labelled, operable, and correctly focusedKeyboard run
PDP-019P1Complete the flow on the main mobile viewportMedia, options, price, quantity, and Add to cart remain usableMobile trace and screenshots
PDP-020P2Load the page with slow images and failed recommendationsCore product data and purchase controls remain stableNetwork and performance trace

Automating Product Page Tests with Playwright

Product pages are strong candidates for browser automation because their critical state is visible and interactive.

The browser test should still inspect the resulting cart state.

A useful automated flow is:

Prepare controlled product
→ open product page
→ select options
→ verify resolved state
→ submit Add to cart
→ inspect the accepted response
→ compare the stored cart line

Example:

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

test('selected product variant reaches the cart unchanged', async ({
  page,
  request,
}) => {
  const fixtureResponse = await request.post('/test-support/products', {
    data: {
      fixture: 'multi-variant-product',
      variants: [
        {
          colour: 'Blue',
          size: '42',
          sku: 'SHOES-BLUE-42',
          price: 8000,
          stock: 3,
        },
      ],
    },
  });

  expect(fixtureResponse.ok()).toBeTruthy();

  const product = await fixtureResponse.json();

  await page.goto(`/products/${product.slug}`);

  await expect(
    page.getByRole('heading', { name: product.name }),
  ).toBeVisible();

  await page
    .getByRole('group', { name: 'Colour' })
    .getByRole('radio', { name: 'Blue' })
    .check();

  await page
    .getByRole('group', { name: 'Size' })
    .getByRole('radio', { name: '42' })
    .check();

  await expect(page.getByTestId('product-sku'))
    .toHaveText('SHOES-BLUE-42');

  await expect(page.getByTestId('product-price'))
    .toHaveText('$80.00');

  const [cartResponse] = await Promise.all([
    page.waitForResponse((response) =>
      response.url().includes('/api/cart') &&
      response.request().method() === 'POST',
    ),
    page
      .getByRole('button', { name: 'Add to cart' })
      .click(),
  ]);

  expect(cartResponse.ok()).toBeTruthy();

  const acceptedLine = await cartResponse.json();

  expect(acceptedLine).toEqual(
    expect.objectContaining({
      sku: 'SHOES-BLUE-42',
      quantity: 1,
      unitPrice: 8000,
      currency: 'USD',
    }),
  );

  await page
    .getByRole('link', { name: 'Cart' })
    .click();

  const cartLine = page
    .getByRole('listitem')
    .filter({ hasText: product.name });

  await expect(cartLine.getByText('Blue')).toBeVisible();
  await expect(cartLine.getByText('Size 42')).toBeVisible();
  await expect(cartLine.getByText('$80.00')).toBeVisible();
});

The endpoint, controls, and response structure are application-specific.

The evidence pattern is not:

Select option
→ highlighted control
→ test passed

It is:

Visible selection
→ resolved product state
→ accepted cart request
→ stored cart line

Avoid fixed sleeps for variant and price updates. Wait for the relevant response or observable state.

Data-driven variant coverage

Keep one stable journey and vary the product data:

const cases = [
  {
    colour: 'Blue',
    size: '41',
    expectedSku: 'SHOES-BLUE-41',
    expectedPrice: '$80.00',
    expectedAvailability: 'In stock',
  },
  {
    colour: 'Blue',
    size: '42',
    expectedSku: 'SHOES-BLUE-42',
    expectedPrice: '$80.00',
    expectedAvailability: 'In stock',
  },
  {
    colour: 'Black',
    size: '42',
    expectedSku: 'SHOES-BLACK-42',
    expectedPrice: '$85.00',
    expectedAvailability: 'Out of stock',
  },
];

Useful variables include:

  • product;
  • colour;
  • size;
  • expected SKU;
  • expected price;
  • quantity;
  • customer group;
  • region;
  • expected stock state;
  • expected cart result.

Duplicating the complete browser journey for each variant increases maintenance without improving the evidence.

Where WrightTest Fits

WrightTest provides a visual interface around Playwright for recording, editing, running, scheduling, and debugging browser checks.

A team can record one product-page journey:

Open product
→ select variant
→ validate product state
→ add to cart
→ inspect cart line

Fixed values can then be replaced with variables:

Product
Colour
Size
Expected SKU
Expected price
Expected availability
Quantity
Customer group
Region
Expected cart result

The same journey can cover valid variants, unavailable combinations, customer-specific prices, last-unit products, quantity limits, slow responses, failed additions, and mobile layouts.

Each run can retain its inputs, failed step, screenshots, and Playwright trace.

WrightTest covers the repeatable browser journey. Authoritative price rules, inventory concurrency, eligibility enforcement, and cart persistence still require the appropriate API, integration, service, or database evidence.

Final Acceptance Rule

A product page should not pass because:

The page looked correct and the Add-to-cart button worked.

A stronger acceptance result is:

The page presented the intended product, resolved the customer’s selected options to the correct sellable item, displayed the current price and availability, enforced quantity and eligibility rules, submitted the same item to the cart, and stored a matching cart line.

That is the boundary product page testing must verify.

Technical References