Skip to content

A pre-launch QA pass for Shopify that finds real bugs

Most pre-launch QA is a browser matrix and a click through the happy path. The bugs that reach customers live at quantity eleven, in discount combinations, and in the empty state.

From the workMay 27, 20268 min read

There are two kinds of pre-launch QA. One produces a document that makes everybody feel prepared. The other finds the thing that would have cost money on Tuesday. They look similar from a distance, and the difference is almost entirely about which inputs you choose.

The checks below are the ones that have earned their place: each one has a specific failure it exists to catch, and each one is written so that somebody who is not the developer can run it. What follows is a working checklist with the reasoning attached, because a checklist without reasoning gets skipped the first time a deadline moves.

The checks that only look thorough

Worth naming first, because they consume the QA budget.

The browser matrix. Opening the homepage in five desktop browsers mostly finds the same page five times. It does not find logic bugs, and logic bugs are what break orders. One real device on the checkout is worth more than four desktop browsers on the homepage.

Clicking every link. A crawler does this in ninety seconds and does it better. Human attention should go where a crawler cannot: state, combination, and sequence.

The performance score screenshot. A number captured once, on an empty cart, on a fast connection, from a nearby region. It is not wrong, it is just not evidence of anything a customer will experience. Real performance work is a separate discipline with its own method, not a line in a QA pass.

The happy path. One product, quantity one, no discount, full-price, in stock, domestic address, credit card. This path is the only one anyone tests and the only one that never breaks, because it is the one everybody built against.

The cart, and everything that happens at quantity

Quantity is where the most expensive bugs live, because per-unit and per-line arithmetic look identical when the quantity is one. Every one of these has a real failure mode behind it.

  • Add the same product twice in two visits. Does it merge into one line at quantity two or create a second line? Both behaviours are defensible; only one is what the pricing logic assumes.
  • Take a line to eleven. Any fee, surcharge, bundle rule or Cart Transform written against a single unit will be wrong here, and it will be wrong by a factor rather than by a rounding error. If a Function is involved, this is the case its unit tests should already cover, and this is you confirming they do.
  • Set a quantity above available inventory. Check what the cart says, what the checkout says, and whether they say the same thing. Disagreement between those two surfaces is a very common and very quiet defect.
  • Set a quantity to zero. The line should leave. Check whether anything downstream — a free-gift rule, a shipping threshold, a progress bar — still believes it is there.
  • Mix product types in one cart. A gift card, a subscription item, a digital product and a physical product together. Fees and discounts that were written for physical goods usually have opinions about gift cards that nobody stated out loud.
  • Cross a shipping threshold and then cross back. Add to reach free shipping, then remove. Thresholds that only run in one direction are a classic.
  • Reload the cart, then open it in a second tab. Cart state that lives in JavaScript rather than in the cart object diverges here.

Scroll the figure sideways to see all of it

Discounts, and the combinations nobody wrote down

Discount bugs are the ones that get discovered by customers on a forum. The rule is simple: every discount mechanism you have must be tested against every other one you have, and the expected result must be written down before the test, not decided by looking at the output.

  • Automatic plus code. Do they stack? Should they? Shopify's combination model is explicit, so this is a configuration you either set on purpose or inherited.
  • Product discount plus order discount plus shipping discount. All three at once, on a cart that also crosses a free-shipping threshold.
  • A discount on a cart containing an excluded item. The exclusion should apply to that line and to nothing else. Check the total, not just the badge.
  • A discount at quantity, again. "Twenty percent off" on a line of seven is where per-line logic reveals itself.
  • An expired code and a code for a different market. The failure message matters as much as the failure.
  • A gift card plus a discount. Order of application changes the total, and it is worth knowing which order you are getting.

If the store has checkout UI extensions in play, each of these should be re-run with the extension rendering, because what a shopper sees at checkout and what the pricing logic did are two separate systems that can disagree.

The redirect map, verified as a list

On a replatform or a rebuild, this is the check with the clearest cash value, and it is the one most often replaced by a feeling.

Take the actual URL list from the old store — not the new sitemap — and put it in a column. Every product, collection, page, blog article, and any filtered collection URL that got indexed. Add discontinued products; they still receive traffic and still receive ad clicks. Then request each one against the new store and record the status code and final destination in the next columns.

What you are looking for is not just 404s. A 301 to the homepage is technically a redirect and practically a lost sale: it tells the visitor their product does not exist without saying so. Chains of two and three redirects are the other finding, usually the residue of a previous migration nobody cleaned up. This work belongs with the SEO implementation, and it needs to be finished before launch day rather than after it.

Structured data, checked per template and not per page

Structured data errors are almost always template errors, so check one page of each type rather than many pages of one type: a simple product, a product with variants, a sold-out product, a collection, an article, and the search page.

The specific things that break: price and currency drifting from what the page displays, availability still saying in stock on a sold-out product, review markup left in the theme with no reviews behind it, and duplicate markup because both the theme and an installed app are emitting it. That last one is common enough after an app audit that it is worth checking on purpose.

Checkout, on a real device, on a real network

This is the check most likely to be skipped and most likely to find something. Not a device emulator — an actual phone, on cellular data, with the store's real payment configuration.

  • Complete a purchase end to end, including the wallet buttons, not just the card form.
  • Enter an address the address validation dislikes, and see whether the shopper can still proceed.
  • Choose each shipping rate, including any that a rate customisation is meant to hide or rename.
  • Abandon at the payment step, come back through the recovery email, and confirm the cart is intact.
  • Check the order confirmation page, the confirmation email, and the customer account view. Custom line item properties and Cart Transform output frequently look right in one of the three and wrong in the others.
  • Place an order that triggers each notification the store actually uses, and read them. Merge fields that render as blank are a launch-week classic.

Scroll the figure sideways to see all of it

Empty, error, and the states nobody designs

Every one of these will be seen by a real person in the first week, and none of them is in the design file.

  • Empty cart. Does it offer a way out, or is it a dead end with a heading?
  • Empty search. A search for a term with no results, and a search for a misspelling of a product you sell.
  • A collection filtered to nothing. Filter combinations that return zero products should say so and offer to undo the last filter.
  • A sold-out product page, and a product with one sold-out variant. The second is where the variant picker either helps or lies.
  • 404. It will be hit constantly during the redirect tail, so it should carry search and navigation rather than an apology.
  • A failed payment. Use a test card that declines and read what the shopper is told.
  • Long content. A product with a forty-word title, a customer with a very long address, a cart with fifteen lines. Layouts break at the extremes and the extremes exist in every catalogue.

The order to run it in

Data first, then logic, then presentation. Redirects and structured data are list-shaped work that can start before the theme is finished. Cart, quantity and discounts come next, because a finding there can change code. Device checkout and the empty states come last, when what you are testing is what will actually ship.

The rule that makes any of this stick: every failure found gets written down with the input that caused it, not with a description of what it looked like. "Quantity eleven, one gift card in cart, automatic discount active" is a bug report someone can reproduce in thirty seconds. "The cart total looked wrong" is a conversation.

Blog