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_numberTest 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 discountTest 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 emailPerformance 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/ -vTest 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 releasesPre-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