E-Commerce Testing Guide

How to Test BigCommerce Checkout with Playwright: Complete 2026 Guide

A scenario-by-scenario walkthrough of testing BigCommerce checkout flows with Playwright. Optimized One-Page Checkout, embedded checkout via the Checkout JS SDK, Stencil theme variations, payment gateway iframes, coupon and discount logic, shipping calculator edge cases, and the pitfalls that silently break checkout test suites.

$30B+

BigCommerce powers over 60,000 online stores and processed more than $30 billion in merchant sales through its platform, according to its own 2024 annual report.

BigCommerce 2024 Annual Report

0Checkout scenarios covered
0+Cross-origin iframes per flow
0%Fewer lines with Assrt
0sAvg checkout flow duration

BigCommerce Optimized One-Page Checkout Flow

BrowserStorefrontBigCommerce APICheckout PagePayment GatewayAdd item to cartPOST /cartsCart ID + redirect URLNavigate to /checkoutRender checkout sectionsFill shipping + billingLoad payment iframeEnter card details (iframe)Tokenize + submit paymentOrder confirmation page

1. Why Testing BigCommerce Checkout Is Harder Than It Looks

BigCommerce checkout is not a simple form submission. The platform offers two checkout experiences: the Optimized One-Page Checkout (the default for most stores) and the legacy multi-step checkout. The Optimized One-Page Checkout collapses customer information, shipping, billing, and payment into accordion sections on a single page. Each section makes asynchronous API calls to the BigCommerce backend, recalculating totals, validating addresses, and fetching available shipping methods before the next section becomes interactive. Your Playwright test cannot simply fill fields and click submit; it must wait for each section to finish its async work before proceeding.

The complexity compounds when you consider the embedded checkout model. BigCommerce allows headless storefronts to embed the checkout experience using the Checkout JS SDK, which loads the entire checkout as an iframe from checkout.bigcommerce.com. Your Playwright test must switch into that iframe context to interact with any checkout field. Inside that checkout iframe, payment providers like Stripe, Braintree, PayPal, and Square each inject their own nested iframes for PCI-compliant card entry. That means your test needs to navigate into an iframe inside an iframe, a pattern that requires careful use of Playwright's frameLocator API.

Stencil themes add another layer. BigCommerce stores built on the Stencil framework can customize checkout selectors, add custom form fields, inject promotional banners, and modify the checkout flow with custom JavaScript. A test written against the default Cornerstone theme may fail silently on a merchant's customized theme because the button label changed from “Place Order” to “Complete Purchase” or a custom shipping calculator replaced the default one. Finally, BigCommerce enforces rate limits on its Storefront and Management APIs, and sandbox environments have tighter limits than production, meaning your test suite can trigger 429 responses if it creates too many carts or orders in parallel.

BigCommerce Checkout Architecture Layers

🌐

Storefront

Stencil or headless

⚙️

Cart API

POST /carts

🌐

Checkout Page

One-Page Checkout

📦

Checkout Iframe

Embedded checkout SDK

🔒

Payment Iframe

Stripe/Braintree/PayPal

⚙️

Order API

POST /orders

Confirmation

Order complete

Payment Gateway Iframe Nesting

🌐

Storefront DOM

Top-level page

📦

Checkout Iframe

BigCommerce hosted

🔒

Payment Iframe

Gateway hosted (PCI)

💳

Card Fields

Number, expiry, CVV

A robust BigCommerce checkout test suite must handle all of these layers: async section rendering, embedded checkout iframes, nested payment iframes, Stencil theme selector variations, and API rate limits. The sections below walk through each scenario with runnable Playwright TypeScript you can paste directly into your project.

2. Setting Up a Reliable Test Environment

Before writing scenarios, establish a deterministic test environment. BigCommerce provides sandbox stores for development and testing. Create a dedicated sandbox store through the BigCommerce Partner Portal or Developer account. Never run end-to-end checkout tests against a production store, because every completed order creates real records, triggers real webhooks, and can affect inventory counts.

BigCommerce Test Environment Checklist

  • Create a dedicated BigCommerce sandbox store (separate from production)
  • Generate a Storefront API token with manage scope for carts and checkouts
  • Generate a Management API token (V2/V3) for order cleanup
  • Configure a test payment gateway (Stripe test mode or BigCommerce Test Gateway)
  • Create 2-3 test products with known SKUs, prices, and inventory
  • Set up at least two shipping zones with flat-rate methods
  • Create test coupon codes with known discount rules
  • Disable CAPTCHA and bot protection for the sandbox store

Environment Variables

.env.test

Cart Setup via Storefront API

Every checkout test starts with a cart. Use the BigCommerce Storefront Cart API to programmatically create a cart with known products before each test. This avoids the fragility of navigating the product page and clicking “Add to Cart” through the UI, which depends on Stencil theme selectors.

test/helpers/bigcommerce-cart.ts

Playwright Configuration for BigCommerce

BigCommerce checkout involves multiple cross-origin iframes and async section transitions. Configure generous timeouts and allow the service worker to register without interference.

playwright.config.ts
BigCommerce Sandbox Setup

3. Scenario: Complete Checkout Happy Path

The first scenario every BigCommerce integration needs is the complete end-to-end checkout that succeeds without complications. This is your smoke test: add a product to the cart, proceed to the Optimized One-Page Checkout, fill customer information, select a shipping method, enter payment details, and land on the order confirmation page. If this breaks, nobody can buy anything and you want to know immediately. The Optimized One-Page Checkout renders all steps as accordion sections. Each section triggers asynchronous validation and recalculation when completed, so your test must wait for each transition.

1

Complete Checkout Happy Path

Moderate

Goal

Starting from a programmatically created cart, navigate through every section of the Optimized One-Page Checkout and land on the order confirmation page with a valid order number.

Preconditions

  • Sandbox store running with test products configured
  • Cart created via Storefront API with at least one item
  • Test payment gateway enabled (Stripe test mode or BigCommerce Test Gateway)
  • At least one shipping method available for the test address

Playwright Implementation

bigcommerce-checkout.spec.ts

What to Assert Beyond the UI

Post-Checkout Verification

  • Order confirmation page displays correct order number
  • Order total matches cart total plus shipping and tax
  • BigCommerce Management API returns the order with status 'Pending'
  • Product inventory decremented by the ordered quantity
  • Order confirmation email triggered (verify via webhook or email service)

Complete Checkout: Playwright vs Assrt

import { test, expect } from '@playwright/test';
import { createTestCart } from '../helpers/bigcommerce-cart';

test('complete checkout: happy path', async ({ page }) => {
  const { checkoutUrl } = await createTestCart(
    process.env.APP_BASE_URL!,
    process.env.BIGCOMMERCE_STOREFRONT_TOKEN!
  );
  await page.goto(checkoutUrl);
  await page.waitForSelector('[data-test="checkout-page-container"]');

  await page.getByLabel('Email Address').fill('test@example.com');
  await page.getByLabel('First Name').fill('Test');
  await page.getByLabel('Last Name').fill('Buyer');
  await page.getByLabel('Address Line 1').fill('123 Test Street');
  await page.getByLabel('City').fill('Austin');
  await page.getByLabel('State/Province').selectOption('Texas');
  await page.getByLabel('Postal Code').fill('78701');

  await page.getByRole('button', { name: /continue/i }).first().click();
  await page.waitForSelector('[data-test="shipping-option"]');
  await page.locator('[data-test="shipping-option"]').first().click();
  await page.getByRole('button', { name: /continue/i }).first().click();

  await page.waitForSelector('[data-test="payment-form"]');
  const paymentFrame = page.frameLocator('iframe[title*="payment"]');
  await paymentFrame.getByLabel('Card Number').fill('4111111111111111');
  await paymentFrame.getByLabel('Expiry').fill('12/28');
  await paymentFrame.getByLabel('CVV').fill('123');

  await page.getByRole('button', { name: /place order/i }).click();
  await page.waitForURL(/\/order-confirmation/);
  await expect(page.getByText(/order confirmed/i)).toBeVisible();
});
48% fewer lines

4. Scenario: Guest Checkout with Embedded Checkout

BigCommerce headless storefronts use the Checkout JS SDK to embed the entire checkout experience as an iframe on a custom domain. This is common for stores using Next.js, Gatsby, or a custom React frontend. The embedded checkout loads from checkout.bigcommerce.com as a cross-origin iframe, and your Playwright test must switch into that iframe context to interact with any element. Guest checkout adds complexity because the customer information section behaves differently when no account is associated: it shows additional fields for creating an account and handles email uniqueness checks asynchronously.

The embedded checkout iframe is injected by the @bigcommerce/checkout-sdk and takes several seconds to fully render. Your test must wait for the iframe to appear in the DOM, then wait for the checkout content inside the iframe to finish its initial data fetch before interacting with form fields. Attempting to fill fields before the async initialization completes will produce stale element errors or silently submit empty values.

2

Guest Checkout via Embedded Checkout

Complex

Playwright Implementation

embedded-checkout.spec.ts

Embedded Guest Checkout: Playwright vs Assrt

import { test, expect } from '@playwright/test';
import { createTestCart } from '../helpers/bigcommerce-cart';

test('guest checkout: embedded iframe', async ({ page }) => {
  const { cartId } = await createTestCart(/*...*/);
  await page.goto(`/checkout?cartId=${cartId}`);

  const checkoutFrame = page.frameLocator(
    'iframe[src*="bigcommerce.com/checkout"]'
  );
  await expect(
    checkoutFrame.locator('[data-test="checkout-page-container"]')
  ).toBeVisible({ timeout: 25_000 });

  await checkoutFrame.getByLabel('Email Address').fill(guestEmail);
  await checkoutFrame
    .locator('[data-test="customer-continue-as-guest-button"]')
    .click();

  // ... fill shipping, select method, fill payment iframe ...
  const paymentFrame = checkoutFrame.frameLocator('iframe[title*="payment"]');
  await paymentFrame.getByLabel('Card Number').fill('4111111111111111');

  await checkoutFrame
    .getByRole('button', { name: /place order/i }).click();
  await expect(page.getByText(/order confirmed/i)).toBeVisible();
});
50% fewer lines

Try Assrt for free

Open-source AI testing framework. No signup required.

Get Started

5. Scenario: Payment Gateway Iframe Interaction

Payment processing in BigCommerce checkout always happens inside a cross-origin iframe injected by the payment gateway provider. BigCommerce supports dozens of payment gateways, and each one renders its own PCI-compliant card entry form. Stripe uses Elements iframes with names like __privateStripeFrame. Braintree uses hosted fields with iframe names like braintree-hosted-field-number. PayPal renders its own button iframe that opens a popup window. Your test must know which gateway is active and use the correct iframe selectors.

The most common failure mode is timing. Payment gateway iframes load asynchronously after the payment section of the checkout becomes active. The iframe element may appear in the DOM before the internal form fields are ready. Your test must wait for the specific input element inside the iframe, not just the iframe element itself. Additionally, some gateways (Stripe in particular) use synthetic focus events that require your test to click the field before filling it, rather than calling fill() directly.

3

Payment Gateway Iframe: Stripe and Braintree

Complex

Playwright Implementation: Stripe

payment-stripe.spec.ts

Playwright Implementation: Braintree Hosted Fields

payment-braintree.spec.ts

Test Card Numbers by Gateway

GatewayTest CardExpected Result
Stripe4242424242424242Success
Stripe (decline)4000000000000002Card declined
Braintree4111111111111111Success
Braintree (decline)4000111111111115Processor declined
BigCommerce Test4111111111111111Success (any valid format)

6. Scenario: Coupon Codes and Discount Rules

BigCommerce supports multiple discount mechanisms: coupon codes, automatic discounts, customer group pricing, and promotion rules. Testing coupon application during checkout is critical because discount logic runs server-side and the checkout page must re-render the order summary with updated totals. A common bug is the coupon input accepting the code visually but the total not updating because the async recalculation failed silently.

The coupon code field in the Optimized One-Page Checkout appears as a collapsible section. Your test must first expand the coupon section (which may be collapsed by default), enter the code, click the apply button, and then wait for the order summary to update before asserting the discounted total. BigCommerce validates coupons against eligibility rules (minimum order, specific products, customer groups, usage limits), so your test data must satisfy all conditions.

4

Coupon Code Application During Checkout

Moderate

Playwright Implementation

coupon-checkout.spec.ts

Coupon Application: Playwright vs Assrt

test('coupon: valid code reduces total', async ({ page }) => {
  const { checkoutUrl } = await createTestCart(/*...*/);
  await page.goto(checkoutUrl);
  await page.waitForSelector('[data-test="checkout-page-container"]');

  const originalTotal = await page
    .locator('[data-test="cart-total"]').textContent();

  await page.getByRole('button', { name: /coupon code/i }).click();
  await page.getByLabel(/coupon code/i).fill('TESTDISCOUNT10');
  await page.getByRole('button', { name: /apply/i }).click();

  await expect(
    page.locator('[data-test="discount-total"]')
  ).toBeVisible({ timeout: 10_000 });

  const newTotal = await page
    .locator('[data-test="cart-total"]').textContent();
  const parse = (s: string | null) =>
    parseFloat(s?.replace(/[^0-9.]/g, '') || '0');
  expect(parse(newTotal)).toBeLessThan(parse(originalTotal));
});
47% fewer lines

7. Scenario: Shipping Method Selection and Rate Calculation

BigCommerce calculates shipping rates dynamically based on the customer's address, the products in the cart, and the configured shipping zones and methods. The Optimized One-Page Checkout fetches available shipping methods asynchronously after the customer completes the address section. This async fetch is the most common source of flaky checkout tests: your test clicks “Continue” after filling the address, but the shipping options have not loaded yet, causing the test to either fail or skip to payment without a shipping method selected.

BigCommerce supports flat-rate, weight-based, price-based, and real-time carrier-calculated shipping. Real-time rates from UPS, FedEx, or USPS add external API latency, making the shipping section slower. For test environments, configure flat-rate methods to avoid external dependencies. Your test should assert not just that a shipping option appears, but that the rate displayed matches the expected configuration and that the order total updates correctly when switching between methods.

5

Shipping Method Selection and Rate Verification

Moderate

Playwright Implementation

shipping-methods.spec.ts

8. Scenario: Stencil Theme Variations and Custom Checkout

BigCommerce stores use the Stencil framework for their storefront themes. The default Cornerstone theme provides the standard checkout selectors that most documentation references. However, merchants frequently customize their themes, and third-party themes from the BigCommerce marketplace can have significantly different checkout DOM structures. A custom Stencil theme might rename the “Place Order” button to “Complete Purchase”, add custom form fields for gift messages or PO numbers, inject promotional banners between checkout sections, or replace the default shipping calculator with a custom component.

The safest strategy for cross-theme compatibility is to prefer data-test attributes that BigCommerce includes in the Optimized One-Page Checkout over text-based selectors. The built-in data-test attributes are stable across theme customizations because they come from the BigCommerce checkout application itself, not from the Stencil theme layer. When you must use text selectors (for custom theme elements), use flexible patterns with regular expressions.

6

Stencil Theme Custom Checkout Fields

Moderate

Playwright Implementation

stencil-custom-checkout.spec.ts

Recommended Selectors: data-test vs. Text

ElementPreferred (data-test)Fallback (text/role)
Email input[data-test="customer-email-input"]getByLabel('Email')
First name[data-test="firstNameInput-text"]getByLabel('First Name')
Shipping option[data-test="shipping-option"]locator('.shippingOption')
Place order[data-test="place-order-button"]getByRole('button', /place order/i)
Order total[data-test="cart-total"]locator('.cart-priceItem--total')

9. Common Pitfalls That Break BigCommerce Checkout Tests

Async Section Transitions

The Optimized One-Page Checkout fetches data asynchronously between each section. Clicking “Continue” after the address section triggers a shipping rate calculation API call that can take anywhere from 500ms (flat-rate) to 5 seconds (real-time carrier rates). If your test does not explicitly wait for the shipping options to appear before interacting with them, you get flaky failures. Use waitForSelector on the specific checkout section element, not waitForTimeout with a hardcoded delay. Hardcoded waits are the number one cause of both slow and unreliable BigCommerce checkout tests, as reported across multiple BigCommerce community forum threads and GitHub issues in the checkout-sdk-js repository.

Payment Iframe Not Ready

Payment gateway iframes load asynchronously after the payment section becomes active. The iframe element may be present in the DOM while the internal form fields are still initializing. A common failure pattern is the test finding the iframe but timing out on the card number input inside it. Wait for the specific input element inside the iframe, not the iframe element itself. If using Stripe, you may need to add a brief pause after the iframe appears because Stripe Elements fires a “ready” event internally before the input actually accepts keystrokes.

Stale Cart State

BigCommerce carts persist in the browser session. If your test creates a cart but does not clean it up after a failed run, the next test may inherit items from the previous cart. This causes unexpected order totals, shipping rate mismatches, and coupon eligibility failures. Always delete existing carts via the Storefront API in your test setup phase and create a fresh cart for each test.

Sandbox API Rate Limits

BigCommerce sandbox stores enforce API rate limits that are stricter than production. The Storefront API allows roughly 10 requests per second per client. If your test suite creates multiple carts in parallel, you can exhaust this limit and receive 429 responses that cause cascading test failures. Run checkout tests sequentially (one worker) or add retry logic with exponential backoff to your cart creation helper.

Checkout URL Expiration

BigCommerce checkout URLs include a cart token that expires after a short period (typically 30 minutes). If your test takes too long or if you reuse a checkout URL from a previous test run, the checkout page will display a “cart not found” or “session expired” error. Always generate a fresh cart and checkout URL immediately before each test, and keep your test execution time under five minutes per scenario.

Checkout Test Anti-Patterns

  • Using hardcoded waitForTimeout instead of waitForSelector between sections
  • Targeting the iframe element instead of the input inside the iframe
  • Reusing carts across test runs without cleanup
  • Running parallel workers against sandbox API rate limits
  • Using text selectors that break across Stencil theme variations
  • Not waiting for async coupon recalculation before asserting totals
BigCommerce Checkout Test Suite Run
Common Error: Payment Iframe Timeout

10. Writing These Scenarios in Plain English with Assrt

Every scenario above involves navigating into cross-origin iframes, waiting for async section transitions, and handling payment gateway differences. The Stripe payment test alone requires knowing the exact iframe name pattern, the internal input names, and the click-before-fill workaround. Multiply that across six scenarios and two payment gateways and you have a test suite that is brittle, hard to maintain, and silently breaks when BigCommerce updates the checkout page or a payment gateway changes its iframe structure.

Assrt lets you describe the checkout scenario in plain English. It resolves the iframe nesting, identifies the correct payment gateway, waits for async transitions, and generates the Playwright TypeScript automatically. When BigCommerce renames a data-test attribute or Stripe changes its iframe naming convention, Assrt detects the failure, analyzes the new DOM, and opens a pull request with updated selectors. Your scenario files stay untouched.

Here is the complete checkout happy path from Section 3, rewritten as an Assrt scenario file. Notice that the iframe handling, async waits, and gateway-specific selectors are all described as intent rather than implementation.

scenarios/bigcommerce-full-checkout-suite.assrt

Assrt compiles each scenario block into the same Playwright TypeScript you saw in the preceding sections. The generated code is committed to your repository as real, readable, runnable test files. When BigCommerce updates its checkout page layout, changes a data-test attribute, or your payment gateway changes its iframe structure, Assrt detects the failure, re-analyzes the live DOM, and opens a pull request with the corrected selectors. Your plain-English scenario files remain stable.

Start with the happy path checkout. Once it is green in your CI pipeline, add the guest checkout scenario, then the coupon flow, then the shipping method test, then the Stencil theme variation check. In a single afternoon you can have comprehensive BigCommerce checkout coverage that most merchant stores never achieve by hand.

Related Guides

Ready to automate your testing?

Assrt discovers test scenarios, writes Playwright tests from plain English, and self-heals when your UI changes.

$npm install @assrt/sdk