In our Shopify Architecture Guide, we cover the fundamentals. Today: The last 10% of the project that often causes 90% of the problems.
At smplx., we've learned: An "almost finished" shop is not the same as a "launch-ready" shop. Testing and QA are not extras — they are architecture.
Why QA Is Critical
The numbers:
- 0.1% of visitors make a purchase
- Every error in checkout = direct revenue loss
- Mobile is fragile (browser tests don't catch that)
- Payment errors are existentially threatening
Reality: You can't test everything manually. You need a strategy.
What You Need to Test
1. Checkout Flow (Highest Priority)
Critical Paths:
- Add product -> Cart
- Change quantities
- Enter coupon (valid, invalid, expired)
- Start checkout
- Select shipping method
- Enter payment
- Show order confirmation
- Receive email
Scenarios:
- Normal credit card checkout
- Guest checkout
- Logged-in customer
- Express payment (Google Pay, Apple Pay)
- Multi-currency (if relevant)
- From different countries
Test Payments:
Stripe Test Cards:
- 4242 4242 4242 4242 (Success)
- 4000 0000 0000 0002 (Decline)
- 4000 0025 0000 3155 (Requires 3D Secure)
Klarna Test:
- 4111 1111 1111 1111 (Success - Invoice)
2. Responsive & Browser Testing
Test devices:
- Desktop (1920x1080, 1440x900, 1024x768)
- Tablet (iPad, Samsung Tab)
- Mobile (iPhone 12, iPhone SE, Samsung Galaxy)
- Old Mobile (iPhone 8)
Test browsers:
- Chrome (latest version)
- Safari (Mac + iOS)
- Firefox (latest)
- Edge
- Mobile Safari (iOS)
- Chrome Mobile (Android)
Tools:
BrowserStack: https://www.browserstack.com
- Real devices in the cloud
- Automated screenshot tests
3. Performance Testing (Web Vitals)
Test with Lighthouse:
# Terminal
lighthouse https://shop.example.com --view
Targets:
- LCP < 2.5s
- INP < 100ms
- CLS < 0.1
- Overall Score > 85
Measure with Web Vitals:
// In theme or headless app
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';
function sendMetrics(metric) {
// Send to analytics
fetch('/api/metrics', {
method: 'POST',
body: JSON.stringify(metric)
});
}
getCLS(sendMetrics);
getFID(sendMetrics);
getFCP(sendMetrics);
getLCP(sendMetrics);
getTTFB(sendMetrics);
4. SEO Testing
With axe DevTools (free):
# Chrome browser extension
# Checks: Accessibility + Basic SEO
Manual checks:
- H1 on every page (exactly one)
- Meta descriptions (all pages)
- Open Graph tags (social sharing)
- Structured data (JSON-LD for products)
- Sitemap.xml exists
- robots.txt not too restrictive
Example: Product Structured Data
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Product",
"name": "{{ product.title }}",
"description": "{{ product.description }}",
"image": "{{ product.featured_image | image_url: width: 800 }}",
"brand": {
"@type": "Brand",
"name": "{{ shop.name }}"
},
"offers": {
"@type": "Offer",
"price": "{{ product.selected_or_first_available_variant.price | divided_by: 100 }}",
"priceCurrency": "{{ shop.currency }}",
"availability": "https://schema.org/{% if product.selected_or_first_available_variant.available %}InStock{% else %}OutOfStock{% endif %}"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "{{ product.metafields.reviews.rating.value | default: 5 }}",
"reviewCount": "{{ product.metafields.reviews.count.value | default: 0 }}"
}
}
</script>
5. Accessibility Testing
Tools:
- axe DevTools (Chrome Extension)
- WAVE (WebAIM)
- Lighthouse Accessibility Audit
Critical Checks:
- All images have alt text
- Color contrast is sufficient
- Keyboard navigation works (tab through links)
- Form labels are correct (not just placeholders)
- ARIA labels where needed
Example: Accessible Form
<!-- WRONG -->
<input type="email" placeholder="Email">
<!-- RIGHT -->
<label for="email">Email</label>
<input type="email" id="email" name="email" required>
6. Payment & Tax Compliance
Test:
- Shipping calculations (correct by country)
- Tax calculations (sales tax, VAT)
- Currency conversions (if multi-currency)
- Payment methods available (by country)
- Address validation works
Example: Shipping Calculation
// Shopify GraphQL
query CalculateShipping {
cart(cartId: "...") {
estimatedCost {
shippingEstimate {
amount
}
totalTaxEstimate {
amount
}
subtotalAmount {
amount
}
totalAmount {
amount
}
}
}
}
7. Mobile Payment Testing
Important: Apple Pay and Google Pay only work on real devices!
Setup:
- Apple Pay on test device
- Google Pay on Android
Test with real devices:
Stripe Test Card for Apple Pay:
- Card Number: 4242 4242 4242 4242
- Exp: 12/26
- CVC: 123
Testing Tools and Setups
Automated Testing: End-to-End
With Playwright (recommended):
// test.spec.js
import { test, expect } from '@playwright/test';
test('Complete Checkout Flow', async ({ page }) => {
// 1. Go to shop
await page.goto('https://shop.example.com');
// 2. Click product
await page.click('[data-test="product-card"]');
expect(page).toHaveURL(/\/products\//);
// 3. Add to cart
await page.click('button:has-text("Add to cart")');
await page.waitForURL('**/cart');
// 4. Start checkout
await page.click('button:has-text("Checkout")');
await page.waitForURL('**/checkout');
// 5. Enter email
await page.fill('input[type="email"]', 'test@example.com');
// 6. Shipping address
await page.fill('input[placeholder="First name"]', 'Test');
await page.fill('input[placeholder="Last name"]', 'User');
await page.fill('input[placeholder="Address"]', '123 Main St');
// 7. Select shipping method
await page.click('text=Standard Shipping');
// 8. Payment
// Stripe iFrame handling is complex
// But Shopify managed checkout makes it easier
// 9. Order confirmation
expect(page).toContain('Order #');
});
test('Coupon is applied', async ({ page }) => {
await page.goto('https://shop.example.com/cart');
await page.fill('input[placeholder="Discount code"]', 'SAVE10');
await page.click('button:has-text("Apply")');
// Price should be updated
await page.waitForSelector('text=Subtotal');
const originalPrice = await page.locator('text=Subtotal').evaluate(el => el.textContent);
expect(originalPrice).toContain('$');
});
Run:
npx playwright test
# Or with UI
npx playwright test --ui
Performance Testing: Lighthouse CI
// lighthouserc.json
{
"ci": {
"collect": {
"url": [
"https://shop.example.com",
"https://shop.example.com/products",
"https://shop.example.com/collections"
],
"numberOfRuns": 3
},
"assert": {
"preset": "lighthouse:recommended",
"assertions": {
"largest-contentful-paint": ["error", { "maxNumericValue": 2500 }],
"cumulative-layout-shift": ["error", { "maxNumericValue": 0.1 }],
"first-input-delay": ["error", { "maxNumericValue": 100 }]
}
}
}
}
lhci autorun
Pre-Launch Checklist
72 Hours Before Launch
Functionality:
- All products visible + images load
- Variants work (all options)
- Inventory correct (overselling not possible)
- All payment methods active
- All shipping methods tested
- All coupons/discounts tested
- Email confirmations work
Performance:
- Lighthouse Score > 85
- LCP < 2.5s (mobile)
- No broken images
- No 404s
SEO:
- Sitemap.xml submitted to Google
- Meta descriptions all pages
- Robots.txt not too restrictive
- Structured data ok (rich snippets)
Security:
- HTTPS everywhere
- CSP headers set
- XSS protection
- CSRF protection (Shopify default)
Legal:
- Privacy policy current
- Terms & conditions ok
- Return policy clear
- Legal notice (GDPR)
24 Hours Before Launch
- Database backup
- Monitoring setup (analytics, error tracking)
- Incident response plan (who does what if there's a problem)
- Support system online (email, chat)
- Marketing campaign ready (don't start on launch day)
After Launch (24-48h Monitoring)
- Error rates monitored
- Payment success rate > 95%
- Page load times ok
- Customer support tickets scanned (reveals patterns)
- Conversion rate normal (no anomalies)
Post-Launch Monitoring
Real User Monitoring (RUM)
// In theme or app
// Send metrics to monitoring service
window.addEventListener('error', (event) => {
fetch('/api/errors', {
method: 'POST',
body: JSON.stringify({
message: event.message,
stack: event.error?.stack,
url: window.location.href,
timestamp: new Date()
})
});
});
// Unhandled Promise Rejections
window.addEventListener('unhandledrejection', (event) => {
fetch('/api/errors', {
method: 'POST',
body: JSON.stringify({
message: 'Unhandled Promise Rejection',
error: event.reason,
timestamp: new Date()
})
});
});
Key Metrics to Watch
Dashboard with:
- Conversion Rate (Visits -> Purchases)
- Cart Abandonment Rate
- Average Order Value
- Payment Success Rate
- Page Load Time (Real Users)
- Error Rate (Frontend + Backend)
- Customer Support Tickets
Tools:
- Google Analytics 4 (free)
- Shopify Admin Reports
- Sentry (Error Tracking)
- Databox (KPI Dashboard)
Incident Response
When a problem occurs:
1. Detect (Monitoring alert)
└─ Severity: Critical/High/Medium/Low
2. Acknowledge (Team is notified)
└─ On-call person: [Name]
3. Assess
└─ Impact: Revenue loss? UX broken? API down?
4. Mitigate (Fast!)
└─ Theme rollback?
└─ Disable app?
└─ Maintenance mode?
5. Fix (Root Cause)
└─ Code debug
└─ Deploy fix
6. Monitor (24h after fix)
└─ Error rate still ok?
└─ Performance normal?
7. Postmortem (next day)
└─ Why did it happen?
└─ How do we prevent it in the future?
Testing for Different Shopify Architectures
Theme-Based Shop (Liquid)
Focus:
- Theme performance
- Liquid template errors
- CSS/JS conflicts
- Browser compatibility
Tools:
- Lighthouse
- BrowserStack
- Chrome DevTools
Headless Shop (Next.js/Remix)
Focus:
- API error handling
- Storefront API rate limits
- SSR/SSG performance
- Data freshness
Tools:
- Jest (unit tests)
- Playwright (E2E tests)
- K6 (load testing)
// Jest Example
describe('Product Page', () => {
it('should fetch product data from Storefront API', async () => {
const response = await fetchProduct('123');
expect(response).toHaveProperty('id');
expect(response).toHaveProperty('title');
});
it('should handle API errors gracefully', async () => {
const response = await fetchProduct('invalid');
expect(response).toBeNull();
});
});
Multi-App Ecosystem
Focus:
- App communication (when apps interact)
- Webhook handling
- API rate limits
- Data consistency
Tools:
- API Monitoring (Postman, Insomnia)
- Webhook Testing (webhook.cool)
- Load Testing (Apache JMeter)
QA Checklist (Copyable)
# Pre-Launch QA Checklist
## Functional Testing
- [ ] Homepage loads
- [ ] Product pages load with images
- [ ] Variants work (all options)
- [ ] Add to cart works
- [ ] Cart shows correct totals
- [ ] Checkout flow complete
- [ ] Payment processes successfully
- [ ] Order confirmation email sent
- [ ] Customer account created (if applicable)
## Responsive Design
- [ ] Mobile (320px) looks ok
- [ ] Tablet (768px) looks ok
- [ ] Desktop (1920px) looks ok
- [ ] Touch targets are at least 44x44px
- [ ] No horizontal scroll
- [ ] Images scale properly
## Performance
- [ ] Lighthouse Score > 85
- [ ] LCP < 2.5s
- [ ] FID < 100ms
- [ ] CLS < 0.1
- [ ] Page size < 5MB
## SEO
- [ ] Meta descriptions set
- [ ] H1 tags correct
- [ ] Open Graph tags
- [ ] Structured data valid
- [ ] Sitemap submitted
## Security
- [ ] HTTPS everywhere
- [ ] No console errors
- [ ] Payment data secure
- [ ] PII protected
## Browsers
- [ ] Chrome (latest)
- [ ] Safari (Mac + iOS)
- [ ] Firefox (latest)
- [ ] Edge (latest)
## Payment
- [ ] Test card works
- [ ] Invalid card rejected
- [ ] Tax calculated
- [ ] Shipping calculated
- [ ] Coupons work
About the Author
Claudio Gerlich is Technical Architect at smplx. and has specialized in Shopify since 2020. With dozens of launches, we've learned: 90% of launch problems are preventable with a good QA strategy.
QA is not "boring testing." It's risk avoidance. It's revenue protection.
smplx. is a Shopify Technical Partner (since 2020) based in Muensterland, NRW.