A discount app has exactly one job that cannot be wrong: the price. Everything else is a feature. The price is the promise.
We have crossed 400 edge cases in our discount test suite, and we thought it was worth explaining what those cases are and why a small pricing app spends this much effort on them. The short version: a discount that is 12 cents off is worse than no discount at all, because it turns a moment of savings into a moment of doubt. A customer who spots a total that does not add up does not think "rounding," they think "is this store real."
So here is how we keep the price right.
Why discount math is deceptively hard
Discounting one item by 10% is trivial. The difficulty is that real carts do not contain one item and one discount. They contain several products, sometimes several discounts, in one of many currencies, each of which rounds to a different number of decimal places. Every one of those variables multiplies the others.
A single volume tier that can also combine with a free shipping discount, evaluated across three currencies, already has dozens of distinct paths through the math. Each path has to land on the correct cent, and it has to land there the same way every time. That is the surface we test.
The three families of edge cases
Most of the 400 fall into three groups.
Currency and rounding. Rounding order changes the answer. Apply a percentage and round each line, and you can get a different cart total than if you round once at the end. Add multi-currency conversion, which introduces its own rounding step, and the two can disagree by a cent or two. A cent or two is enough to make line items not sum to the total shown, which is the single most alarming thing a checkout can do. We test zero-decimal currencies, high-denomination currencies, and the conversion boundaries where floating point likes to misbehave.
Combination matrices. This is the biggest family. We take every discount type in the app, volume, Buy X Get Y-style rewards, shipping, and order-level, and pair it against every combination rule: combine, exclude, prioritize. Then we check that when two discounts touch, the engine resolves them deterministically. The same cart must never produce two different totals depending on the order the discounts were evaluated in.
Line versus cart interactions. A discount can apply to a line item or to the whole cart, and the two interact. A cart-level percentage sitting on top of a line-level volume price has to compose in the right order, and quantity changes have to reprice cleanly. We test carts that cross a tier boundary mid-edit, mixed-eligibility carts where only some products qualify, and the awkward case where a return drops a cart back below a threshold it previously cleared.
A concrete example
Take a cart with two units at $19.99 and a "10% off order" discount, priced in a currency that rounds to two decimals.
Round per line: each unit becomes $17.991, rounds to $17.99, cart total $35.98. Round at the end: $39.98 less 10% is $35.982, rounds to $35.98.
Those agree here, which is the point. But nudge the price to $19.95 with a three-unit cart and the two methods can split by a cent. The test suite pins which method the engine uses and asserts the line items always sum to the displayed total, in every currency, so the customer never sees arithmetic that does not close.
How the suite grows
We do not sit down and imagine 400 cases. The suite grows two ways.
New features arrive with their own matrix. When we shipped a new discount type, we did not just test it in isolation, we added its row and column to the combination matrix against everything already there. That is why each feature costs more to test than the last, and it is the right kind of expensive.
The other source is production. Every bug that reaches a real store becomes a permanent regression test before the fix ships. The failing cart gets written into the suite so it fails the build if the behavior ever comes back. This is why the count only goes up. We are not chasing a number, we are refusing to ship the same mistake twice. Our second BFCM postmortem has the story of a few of the bugs that earned their place in that suite.
Why this connects to margin, not just correctness
Testing is usually framed as a reliability story, but for a discount app it is also a margin story. A combination that resolves the wrong way does not just show a strange total, it can discount deeper than you intended and quietly erode the margin on every affected order. Correct combination logic is what makes your volume discounts behave the way you configured them, and it is what makes the numbers in your profit analytics trustworthy enough to act on.
It is also why we built dry-run simulation: the same determinism that lets us test 400 cases in a build lets you replay a proposed discount against your real orders and trust the result. If the engine were not predictable, the simulation would be a guess.
Four hundred is not a finish line. It is where we are this month, and it will be a larger number next month, because every store that trusts us with its checkout is trusting the one thing that cannot be wrong. We would rather over-test the price than ever have to apologize for it.




