The bug
A pet shop on Shopify sets up weight-based shipping in three tiers: 0–5 kg, 5–10 kg and 10–20 kg. Nobody adds a tier above 20 kg, and Shopify also adds the default package weight to every cart. When a cart falls in a gap between tiers, Shopify moves it up to the next rate. A cart above the top tier gets no rate at all.
How it shows up
For Black Friday the shop builds a bundle: two 12 kg bags of dog food. The cart weighs 24 kg plus the box, no rate matches, and checkout says “Shipping not available. Your order cannot be shipped to the selected address.” Orders with one bag still go through. So the owner tests checkout with one bag, sees it work and finds nothing wrong. The customers who see the message are the ones with the biggest baskets, and the admin shows no error.
Shipping method
- Cart: 2 × dog food, 12 kg each
- Rate: 20 kg and up
Rate found
Shipping not available
- Cart: 2 × dog food, 12 kg each
- Weight: 24 kg plus the box
No rate above 20 kg
How a test finds it
A good checkout test doesn’t buy one item. It builds the heaviest cart a customer could realistically make: the maximum quantity of the heaviest product, plus the largest bundle. Then it asks for shipping to every zone the shop serves. With the tiers above, the 24 kg cart gets no rate and the test fails before the campaign starts.
The fix
Add an open-ended top tier, for example 20 kg and up, or switch to carrier-calculated rates with a flat backup rate. Set a weight on every product, so cart totals are real.
The test that catches it
A Playwright checkout test with the heaviest realistic cart, run against each shipping zone, asserting that at least one rate appears. A second check fails if any product has no weight set. Both run before every campaign and after every change to the shipping settings.
import { test, expect } from "@playwright/test";
import { addHeaviestCart, products, shippingZones } from "./fixtures";
// The biggest basket a customer could build: the heaviest product at its
// maximum quantity, plus the largest bundle.
for (const zone of shippingZones) {
test(`the heaviest cart gets a rate: ${zone.name}`, async ({ page }) => {
await addHeaviestCart(page);
await page.goto("/checkout");
await page.getByLabel("Country/region").selectOption(zone.country);
await page.getByRole("button", { name: "Continue to shipping" }).click();
await expect(page.getByText("Shipping not available")).toHaveCount(0);
await expect(page.getByRole("radio").first()).toBeVisible();
});
}
test("every product has a weight", async () => {
const missing = (await products()).filter((variant) => !variant.grams);
expect(missing).toEqual([]);
});
What it puts at risk
The largest orders of the campaign, in the week the shop paid for ads to bring them in. The customer hits a dead end, the shop sees nothing, and the order may go to a competitor.
