Screenshot Testing for E-commerce: Cart, Checkout, and Product Pages
Ensure your e-commerce site looks perfect across all customer touchpoints with automated visual testing.
E-commerce sites have unique visual testing challenges—product images, dynamic pricing, cart states, and checkout flows all need verification. This guide covers screenshot strategies for comprehensive e-commerce testing.
E-commerce Testing Challenges
Dynamic Content
- Product prices change
- Stock levels fluctuate
- Personalized recommendations
- Sale banners and promotions
- Cart quantities and totals
Critical Pages
| Page | Testing Priority |
|---|---|
| Product detail page | High |
| Category/listing page | High |
| Cart | Critical |
| Checkout | Critical |
| Order confirmation | Critical |
| Homepage | Medium |
| Account pages | Medium |
Product Page Testing
Capture Product Galleries
async function testProductPage(productUrl) {
// Main product image
const mainImage = await captureScreenshot(productUrl, {
viewport: { width: 1440, height: 900 },
waitFor: '.product-image',
});
// Test image gallery navigation
const galleryImages = await captureWithInteraction(productUrl, [
{ action: 'click', selector: '.gallery-thumbnail:nth-child(2)' },
{ action: 'wait', duration: 500 },
{ action: 'screenshot', name: 'gallery-image-2' },
{ action: 'click', selector: '.gallery-thumbnail:nth-child(3)' },
{ action: 'wait', duration: 500 },
{ action: 'screenshot', name: 'gallery-image-3' },
]);
return { mainImage, galleryImages };
}
Test Product Variants
async function testProductVariants(productUrl, variants) {
const screenshots = {};
for (const variant of variants) {
// Select variant (size, color, etc.)
const screenshot = await captureWithInteraction(productUrl, [
{ action: 'click', selector: `[data-variant="${variant}"]` },
{ action: 'wait', duration: 300 },
{ action: 'screenshot' },
]);
screenshots[variant] = screenshot;
}
return screenshots;
}
// Usage
const variants = ['red', 'blue', 'black'];
const variantScreenshots = await testProductVariants(
'https://store.com/product/t-shirt',
variants
);
Out of Stock States
const OUT_OF_STOCK_TEST_PRODUCTS = [
'https://store.com/product/out-of-stock-item',
'https://store.com/product/low-stock-item',
];
async function testStockStates() {
const results = [];
for (const url of OUT_OF_STOCK_TEST_PRODUCTS) {
const screenshot = await captureScreenshot(url);
// Verify out of stock styling is visible
const hasOutOfStockLabel = await checkElement(url, '.out-of-stock-label');
const buyButtonDisabled = await checkElement(url, 'button[disabled]');
results.push({
url,
screenshot,
hasLabel: hasOutOfStockLabel,
buttonDisabled: buyButtonDisabled,
});
}
return results;
}
Cart Testing
Empty Cart
async function testEmptyCart() {
// Clear any existing cart
await clearCart();
const screenshot = await captureScreenshot('https://store.com/cart', {
waitFor: '.empty-cart',
});
return screenshot;
}
Cart with Items
async function testCartWithItems() {
// Add items to cart
await addToCart([
{ product: 'SKU-001', quantity: 1 },
{ product: 'SKU-002', quantity: 2 },
]);
const screenshot = await captureScreenshot('https://store.com/cart', {
waitFor: '.cart-items',
});
// Verify quantities and totals are visible
return screenshot;
}
Cart Updates
async function testCartQuantityChange() {
await addToCart([{ product: 'SKU-001', quantity: 1 }]);
const screenshots = await captureWithInteraction('/cart', [
{ action: 'screenshot', name: 'initial' },
{ action: 'click', selector: '.quantity-increase' },
{ action: 'wait', duration: 500 },
{ action: 'screenshot', name: 'after-increase' },
{ action: 'type', selector: '.quantity-input', text: '5' },
{ action: 'wait', duration: 500 },
{ action: 'screenshot', name: 'quantity-5' },
]);
return screenshots;
}
Checkout Flow Testing
Multi-Step Checkout
async function testCheckoutFlow() {
// Set up cart
await addToCart([{ product: 'SKU-001', quantity: 1 }]);
const checkoutScreenshots = [];
// Step 1: Cart review
checkoutScreenshots.push(await captureScreenshot('/checkout', {
waitFor: '.checkout-step-1',
name: 'step-1-cart',
}));
// Step 2: Shipping info
await fillForm('.shipping-form', TEST_SHIPPING_INFO);
checkoutScreenshots.push(await captureScreenshot('/checkout/shipping', {
waitFor: '.checkout-step-2',
name: 'step-2-shipping',
}));
// Step 3: Payment
checkoutScreenshots.push(await captureScreenshot('/checkout/payment', {
waitFor: '.checkout-step-3',
name: 'step-3-payment',
}));
// Step 4: Review
checkoutScreenshots.push(await captureScreenshot('/checkout/review', {
waitFor: '.checkout-step-4',
name: 'step-4-review',
}));
return checkoutScreenshots;
}
Guest vs Logged-In Checkout
async function testCheckoutStates() {
const results = {};
// Guest checkout
await clearSession();
results.guest = await captureScreenshot('/checkout', {
waitFor: '.guest-checkout',
});
// Logged-in checkout
await login(TEST_USER);
results.loggedIn = await captureScreenshot('/checkout', {
waitFor: '.user-checkout',
});
// Saved address loaded
await selectSavedAddress();
results.savedAddress = await captureScreenshot('/checkout', {
waitFor: '.saved-address',
});
return results;
}
Error States
async function testCheckoutErrors() {
const errorScreenshots = [];
// Invalid card
await fillPaymentForm({
cardNumber: '4000000000000002', // Decline test card
});
await submitCheckout();
errorScreenshots.push(await captureScreenshot('/checkout/payment', {
waitFor: '.payment-error',
name: 'payment-declined',
}));
// Expired card
await fillPaymentForm({
expiry: '01/20',
});
await submitCheckout();
errorScreenshots.push(await captureScreenshot('/checkout/payment', {
waitFor: '.expiry-error',
name: 'card-expired',
}));
// Invalid shipping
await fillShippingForm({
zipCode: '00000',
});
errorScreenshots.push(await captureScreenshot('/checkout/shipping', {
waitFor: '.shipping-error',
name: 'invalid-shipping',
}));
return errorScreenshots;
}
Mobile Testing
Mobile Product Pages
const MOBILE_PRODUCTS = [
'/product/featured-item',
'/product/best-seller',
];
async function testMobileProductPages() {
const results = [];
for (const url of MOBILE_PRODUCTS) {
results.push({
url,
portrait: await captureScreenshot(url, {
viewport: { width: 375, height: 812 },
}),
landscape: await captureScreenshot(url, {
viewport: { width: 812, height: 375 },
}),
});
}
return results;
}
Mobile Checkout
async function testMobileCheckout() {
await addToCart([{ product: 'SKU-001', quantity: 1 }]);
const screenshots = [];
const steps = ['/cart', '/checkout', '/checkout/shipping', '/checkout/payment'];
for (const step of steps) {
screenshots.push(await captureScreenshot(step, {
viewport: { width: 375, height: 812 },
fullPage: true,
}));
}
return screenshots;
}
Price Verification
Capture Price Display
async function testPriceDisplay(productUrl) {
const screenshot = await captureScreenshot(productUrl, {
waitFor: '.product-price',
});
// Also verify specific price elements
const priceElement = await captureElement(productUrl, '.product-price');
const salePrice = await captureElement(productUrl, '.sale-price');
const regularPrice = await captureElement(productUrl, '.regular-price');
return { full: screenshot, priceElement, salePrice, regularPrice };
}
Sale/Promotion States
async function testPromotionalPricing() {
// Regular price
const regular = await captureScreenshot('/product/item', {
name: 'regular-price',
});
// With promo code
await applyPromoCode('SAVE20');
const withPromo = await captureScreenshot('/cart', {
name: 'with-promo',
});
// Flash sale styling
const flashSale = await captureScreenshot('/product/flash-sale-item', {
name: 'flash-sale',
});
return { regular, withPromo, flashSale };
}
Category/Listing Pages
Grid vs List View
async function testListingViews(categoryUrl) {
const screenshots = {};
// Grid view
screenshots.grid = await captureScreenshot(`${categoryUrl}?view=grid`, {
fullPage: true,
});
// List view
screenshots.list = await captureScreenshot(`${categoryUrl}?view=list`, {
fullPage: true,
});
return screenshots;
}
Filters and Sorting
async function testFiltersAndSort(categoryUrl) {
const screenshots = [];
// Apply price filter
screenshots.push(await captureScreenshot(`${categoryUrl}?price=0-50`, {
name: 'price-filter',
}));
// Apply size filter
screenshots.push(await captureScreenshot(`${categoryUrl}?size=large`, {
name: 'size-filter',
}));
// Sort by price low to high
screenshots.push(await captureScreenshot(`${categoryUrl}?sort=price-asc`, {
name: 'sort-price-asc',
}));
return screenshots;
}
Test Organization
Page Object Pattern
class ProductPageTest {
constructor(baseUrl) {
this.baseUrl = baseUrl;
}
async captureMain() {
return captureScreenshot(this.baseUrl);
}
async captureVariant(variant) {
return captureWithInteraction(this.baseUrl, [
{ action: 'click', selector: `[data-variant="${variant}"]` },
{ action: 'screenshot' },
]);
}
async captureZoom() {
return captureWithInteraction(this.baseUrl, [
{ action: 'hover', selector: '.product-image' },
{ action: 'screenshot' },
]);
}
}
class CheckoutFlowTest {
async runFullFlow() {
const screenshots = {};
screenshots.cart = await captureScreenshot('/cart');
screenshots.checkout = await captureScreenshot('/checkout');
// ... more steps
return screenshots;
}
}
Best Practices
1. Use Test Data
const TEST_PRODUCTS = {
simple: '/product/basic-tshirt',
variants: '/product/multicolor-jacket',
outOfStock: '/product/sold-out-item',
onSale: '/product/clearance-item',
};
2. Handle Dynamic Content
async function captureWithMasking(url) {
const screenshot = await captureScreenshot(url, {
maskElements: [
'.recommended-products',
'.recently-viewed',
'.shipping-eta',
],
});
return screenshot;
}
3. Test Critical Paths Daily
// Priority testing schedule
const DAILY_TESTS = ['cart', 'checkout', 'product-detail'];
const WEEKLY_TESTS = ['category', 'search', 'account'];
Conclusion
E-commerce screenshot testing requires:
- Product pages - Variants, galleries, pricing
- Cart - Empty, populated, quantity changes
- Checkout - All steps, error states, guest/logged-in
- Mobile - Critical flow on mobile devices
- Dynamic content - Mask or exclude changing elements
Automated visual testing catches layout issues before customers encounter them, protecting conversion rates and brand perception.
Ready to test your e-commerce site?
Get your free API key → - 100 free screenshots to get started.
See also:
About the Author

Asad Ali
Full-Stack Developer and Founder of ZTabs with 8+ years of experience building scalable web applications and APIs. Specializes in performance optimization, SaaS development, and modern web technologies.
Credentials: Founder & CEO at ZTabs, Full-Stack Developer, Expert in Next.js, React, Node.js, and API optimization
Frequently Asked Questions
How do I capture the cart page without real inventory mutations?
Seed a dedicated test account with a fixed cart state via an API call before capture, or use a feature flag that pins the cart to a known fixture. Either pattern keeps visual tests deterministic across runs. Avoid capturing a real user's cart — timing and inventory changes produce false regressions.
Should I test checkout at multiple pricing/tax locales?
If you ship to multiple regions, yes. Geo-pin the capture via the user-agent locale or an explicit Accept-Language header, and verify each region's price display, currency symbol, and tax row. Missing a region in visual tests is how pricing bugs reach production in that region.
Dynamic promotional banners keep breaking my visual diffs. Fix?
Strip them via a CSS selector in the element-removal list, or capture against a staging URL where promos are disabled. Banners are designed to rotate — they will always trigger diffs on product pages. Isolate them from the capture so only real layout regressions fire the alert.
Ready to capture your first screenshot?
Get started with 100 free screenshots. No credit card required.