E-commerce Regression Testing: What to Test Before Every Release

E-commerce Regression Testing: What to Test Before Every Release

E-commerce regression testing is the systematic process of verifying that existing functionality still works after every code change. Every release is an opportunity to silently break checkout, inventory management, or payment processing. This guide defines what to test, in what order, and at what frequency.


Why E-commerce Regression Testing Is Critical

A broken checkout doesn't just lose a sale — it loses trust. Users who encounter a payment failure rarely retry. They go to a competitor.

The stakes:

  • Average cart abandonment rate: 70%+ (many due to UX and payment issues)
  • Cost of downtime: An hour of checkout downtime can cost thousands in lost revenue
  • Silent regressions: Plugin updates, theme changes, or server config changes can break checkout with no error in your logs

Regression testing catches these before users do.


The Three Regression Risk Categories

High Risk (Test Every Release)

Changes to these areas break checkout:

  • Payment gateway code or configuration
  • Cart/checkout templates or JavaScript
  • Tax calculation or shipping rate logic
  • WooCommerce/Magento/Shopify core updates
  • Theme updates affecting checkout pages
  • SSL certificate changes
  • CDN configuration changes

Medium Risk (Test Most Releases)

  • New product types or custom fields
  • Customer account functionality
  • Email notification templates
  • Currency or localization changes
  • Inventory management changes

Low Risk (Test Periodically)

  • Admin-side functionality (order management, product editing)
  • Reporting and analytics
  • Static content pages

Core Checkout Regression Tests

These tests run before every production deployment.

Test 1: Guest Checkout — Standard Card

# tests/regression/test_guest_checkout.py
import pytest
from playwright.sync_api import Page, expect

def test_guest_checkout_standard_card(page: Page, store_url: str):
    """Complete purchase as guest with standard Visa card."""
    
    # Step 1: Browse to product
    page.goto(f"{store_url}/products/test-widget")
    expect(page.locator("h1")).to_contain_text("Test Widget")
    
    # Step 2: Add to cart
    page.click("text=Add to Cart")
    expect(page.locator(".cart-count")).to_have_text("1")
    
    # Step 3: Proceed to checkout
    page.goto(f"{store_url}/checkout")
    expect(page).to_have_url(f"{store_url}/checkout")
    
    # Step 4: Fill customer info
    fill_checkout_form(page, {
        "email": "regression-test@test.com",
        "first_name": "Reg",
        "last_name": "Test",
        "address": "123 Test St",
        "city": "Portland",
        "state": "OR",
        "zip": "97201"
    })
    
    # Step 5: Payment
    fill_test_card(page, "4242424242424242")
    
    # Step 6: Place order
    page.click("button:has-text('Place Order')")
    
    # Step 7: Verify confirmation
    expect(page.locator("text=Order confirmed")).to_be_visible(timeout=30000)
    
    # Capture order number for validation
    order_number = page.locator(".order-number").text_content()
    assert order_number, "Order number should be present on confirmation page"
    
    return order_number

Test 2: Registered Customer Checkout

def test_registered_customer_checkout(page: Page, store_url: str):
    """Complete purchase as logged-in customer with saved address."""
    
    # Login
    page.goto(f"{store_url}/account/login")
    page.fill("[name='email']", "test-customer@test.com")
    page.fill("[name='password']", "TestPassword123!")
    page.click("button:has-text('Sign In')")
    expect(page.locator("text=My Account")).to_be_visible()
    
    # Add to cart
    page.goto(f"{store_url}/products/test-widget")
    page.click("text=Add to Cart")
    
    # Checkout — address should be pre-filled
    page.goto(f"{store_url}/checkout")
    
    # Verify saved address is populated
    email_value = page.locator("[name='email']").input_value()
    assert email_value == "test-customer@test.com"
    
    # Payment and place order
    fill_test_card(page, "4242424242424242")
    page.click("button:has-text('Place Order')")
    expect(page.locator("text=Order confirmed")).to_be_visible(timeout=30000)

Test 3: Declined Payment Handling

def test_declined_card_shows_error_and_allows_retry(page: Page, store_url: str):
    """Declined card shows error message and allows user to retry."""
    
    navigate_to_checkout(page, store_url)
    fill_checkout_form(page, test_customer())
    fill_test_card(page, "4000000000000002")  # declined card
    page.click("button:has-text('Place Order')")
    
    # Error message appears
    expect(page.locator(".payment-error")).to_be_visible()
    expect(page.locator("text=declined")).to_be_visible()
    
    # User is still on checkout page, not redirected
    expect(page).to_have_url(f"{store_url}/checkout")
    
    # User can retry with a different card
    fill_test_card(page, "4242424242424242")  # success card
    page.click("button:has-text('Place Order')")
    expect(page.locator("text=Order confirmed")).to_be_visible(timeout=30000)

Test 4: Coupon Application

def test_coupon_applies_correctly(page: Page, store_url: str):
    """Coupon reduces total by expected amount."""
    
    navigate_to_cart(page, store_url, product="test-widget-50")  # $50 product
    
    # Apply 20% coupon
    page.fill("[name='coupon_code']", "SAVE20")
    page.click("button:has-text('Apply')")
    
    expect(page.locator(".discount-amount")).to_be_visible()
    discount_text = page.locator(".discount-amount").text_content()
    assert "10.00" in discount_text or "-10" in discount_text  # 20% of $50
    
    subtotal = page.locator(".cart-subtotal").text_content()
    assert "40.00" in subtotal  # $50 - $10 discount

Test 5: Tax Calculation

def test_tax_calculated_for_taxable_state(page: Page, store_url: str):
    """Tax is calculated for orders from taxable states."""
    
    navigate_to_checkout(page, store_url)
    fill_checkout_form(page, {
        **test_customer(),
        "state": "CA",   # California — 8.25% tax
        "zip": "90210"
    })
    
    # Tax line should appear
    expect(page.locator(".order-tax")).to_be_visible()
    tax_text = page.locator(".order-tax").text_content()
    assert "$" in tax_text
    assert tax_text != "$0.00"

Inventory Regression Tests

def test_out_of_stock_product_cannot_be_purchased(page: Page, store_url: str):
    """Out-of-stock products show appropriate messaging."""
    
    page.goto(f"{store_url}/products/test-out-of-stock")
    
    # Add to cart button should be disabled or replaced
    add_to_cart = page.locator("button:has-text('Add to Cart')")
    out_of_stock = page.locator("text=Out of Stock")
    
    # Either button is disabled, or "Out of Stock" text appears
    assert (
        not add_to_cart.is_enabled() or 
        out_of_stock.is_visible()
    ), "Out of stock product should not be purchasable"

def test_stock_decrements_on_purchase(api_client, test_product_id: int):
    """Purchasing an item decrements its inventory."""
    
    # Get initial stock
    initial_stock = api_client.get_product_stock(test_product_id)
    
    # Place an order for 2 units
    order_id = api_client.create_test_order(test_product_id, quantity=2)
    api_client.confirm_order(order_id)
    
    # Verify stock decreased
    final_stock = api_client.get_product_stock(test_product_id)
    assert final_stock == initial_stock - 2
    
    # Cleanup
    api_client.cancel_order(order_id)

Email Notification Tests

import imaplib
import email
import time

def test_order_confirmation_email_sent(page: Page, store_url: str, mail_client):
    """Order confirmation email is sent within 60 seconds of purchase."""
    
    test_email = f"regression+{int(time.time())}@test.com"
    
    # Complete purchase with unique email
    complete_checkout(page, store_url, email=test_email)
    
    # Poll for email (wait up to 60 seconds)
    received = mail_client.wait_for_email(
        to=test_email,
        subject_contains="Order Confirmation",
        timeout=60
    )
    
    assert received, "Order confirmation email should arrive within 60 seconds"
    assert "order" in received.body.lower()

def test_shipping_notification_email_sent(api_client, mail_client):
    """Shipping notification email is sent when order is marked shipped."""
    
    order_id = api_client.create_test_order(...)
    test_email = api_client.get_order_email(order_id)
    
    # Mark order as shipped
    api_client.ship_order(order_id, tracking_number="1Z999AA10123456784")
    
    # Check for shipping email
    received = mail_client.wait_for_email(
        to=test_email,
        subject_contains="Your order has shipped",
        timeout=120
    )
    
    assert received
    assert "1Z999AA10123456784" in received.body  # tracking number in email

Performance Regression Tests

Checkout conversion rates correlate directly with page load time. Test performance as part of regression:

from playwright.sync_api import Page
import time

PERFORMANCE_THRESHOLDS = {
    "product_page_load": 2.0,    # seconds
    "add_to_cart_response": 1.0,
    "checkout_page_load": 2.5,
    "payment_submission": 5.0,
}

def test_product_page_load_performance(page: Page, store_url: str):
    start = time.time()
    page.goto(f"{store_url}/products/test-widget")
    page.wait_for_load_state("networkidle")
    load_time = time.time() - start
    
    assert load_time < PERFORMANCE_THRESHOLDS["product_page_load"], \
        f"Product page loaded in {load_time:.2f}s (threshold: {PERFORMANCE_THRESHOLDS['product_page_load']}s)"

def test_checkout_page_load_performance(page: Page, store_url: str):
    add_product_to_cart(page, store_url)
    
    start = time.time()
    page.goto(f"{store_url}/checkout")
    page.wait_for_load_state("networkidle")
    load_time = time.time() - start
    
    assert load_time < PERFORMANCE_THRESHOLDS["checkout_page_load"], \
        f"Checkout loaded in {load_time:.2f}s"

Regression Test Execution Strategy

Before Every Deploy to Production

# Run critical path tests only (fast, ~5 minutes)
pytest tests/regression/ -m <span class="hljs-string">"critical" -v

<span class="hljs-comment"># If all pass, deploy
<span class="hljs-comment"># Then run full suite post-deploy
pytest tests/regression/ -v

Test Priority Labels

# Mark tests with priority
@pytest.mark.critical    # Run every deploy
@pytest.mark.high        # Run most deploys
@pytest.mark.medium      # Run weekly
@pytest.mark.low         # Run before major releases

Pre-Release Checklist

  • Guest checkout — success card
  • Guest checkout — declined card shows error
  • Registered user checkout
  • 3D Secure card completes successfully
  • Coupon reduces total correctly
  • Tax calculated for applicable states/countries
  • Shipping rates calculated correctly
  • Out-of-stock product cannot be purchased
  • Stock decrements on purchase
  • Order confirmation email received
  • Refund processes successfully
  • Order status transitions work
  • Admin can view and manage orders
  • Product page loads under 2 seconds
  • Checkout page loads under 2.5 seconds
  • Mobile checkout works on iPhone and Android viewports

CI Integration

name: E-commerce Regression

on:
  push:
    branches: [main]
  schedule:
    - cron: "0 */4 * * *"  # every 4 hours in staging

jobs:
  critical-regression:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.11"
      - run: pip install pytest playwright
      - run: playwright install chromium
      
      - name: Run critical regression tests
        env:
          STORE_URL: ${{ secrets.STAGING_STORE_URL }}
          TEST_CARD_SUCCESS: "4242424242424242"
        run: pytest tests/regression/ -m "critical" --tb=short -v
      
      - name: Alert on failure
        if: failure()
        uses: slackapi/slack-github-action@v1
        with:
          payload: '{"text":"🚨 E-commerce regression failed on staging"}'
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}

Running Regression Tests Continuously

A test suite that runs only before deployments misses production issues caused by:

  • Third-party payment gateway outages
  • CDN edge node failures affecting specific regions
  • Database connection pool exhaustion under load
  • SSL certificate expiry
  • External service API changes

For 24/7 monitoring, schedule your critical regression tests to run continuously:

HelpMeTest runs your checkout regression tests every 5 minutes and alerts you immediately when they fail — so you know about checkout problems before your customers do.


Next Steps

  • Start with 5 critical tests — happy path checkout, declined card, coupon, stock check, confirmation email
  • Automate your pre-release checklist — convert every checkbox item to an automated test
  • Add continuous monitoring — tests running only in CI miss production outages between deployments
  • Explore checkout funnel testing to measure and improve conversion rate

Read more