Assert what the page must contain instead of comparing two fetches
Our replacement check makes no comparison at all. It requires at least three distinct currencies in the table, India in rupees, the United States in dollars and the United Kingdom in pounds, from one request with nothing to be blind about.
Published by AI Knows Us · Updated 19 October 2026
Write down what the page must say, then require it. The check we now run on our own pricing page compares nothing: it asserts that the visible text carries at least three distinct currencies, and that three named markets each show their own, India in rupees, the United States in dollars and the United Kingdom in pounds. One request, no second arm, no shared environment between two readings that could hide a fault from both. It also needs no browser, which is why it can run anywhere and fails the minute a build configuration moves a figure back behind a script.
The expensive part of an assertion is not the code. It is deciding what the page is obliged to contain, which is a conversation rather than a commit. That is also why assertions get avoided in favour of comparisons: a comparison lets you skip the decision and still get a green result.
The six properties of an assertion worth having
- Declared before the run. Write the expected content down first. Choosing it after you have seen the response is grading your own homework, and it reliably produces a check that passes.
- Specific strings, not shapes. Require a currency symbol followed by a figure, or an exact plan name. A pattern loose enough to match anything numeric will match your footer.
- A count where the count is the fact. At least three distinct currencies is the claim being made, so the count is what gets asserted rather than described in a comment.
- One named case per line. Assert India in rupees and the United States in dollars separately rather than asserting that pricing looks internationalised. A failure then names itself, and you spend no time working out which half broke.
- Both directions planted. Give it one input it must reject and one it must accept, and make it stop the run if either self test fails. A checker nobody has tried to fool is a checker nobody should trust.
- A refusal when the input is empty. If the fetch returned nothing, the assertion has not been tested, and reporting a pass in that case is the single most common way a check becomes decorative.
Why at least three, and not exactly four
The threshold and the named cases do different jobs, and you want both. An exact count turns a successful expansion into a test failure: add a fifth region and a passing check starts complaining about work you wanted. A floor of at least three lets the page grow.
On its own, though, a floor can be satisfied by the wrong three. That is what the named cases are for. Requiring each named market to show its own currency means a page that gains two regions and silently loses the United Kingdom still fails, which is exactly the regression a count alone would wave through.
The two approaches on five properties
| Property | Comparison of two fetches | Assertion |
|---|---|---|
| Requests needed | Two, at minimum | One |
| Can a fault be invisible to it | Yes, anything true of both arms | Only what you forgot to require |
| Does a failure name itself | Rarely. You get a diff | Yes, one named case per line |
| Needs an expected value | No, which is the appeal | Yes, which is the work |
| Survives a redesign | Often, because it compares relatively | Only if you asserted facts rather than markup |
The bottom row is the real trade and it is worth being honest about it. An assertion tied to a class name or a table position breaks the next time somebody rebuilds the page, which trains people to disable it. An assertion tied to the words a buyer would search for, a plan name, a price, a currency symbol, survives almost any redesign, because those words are the reason the page exists.
What to assert on your own commercial pages
Pick the facts you would be embarrassed to find missing, and require each one by name.
- Every price in every currency you sell in, and the billing period beside each.
- Plan names exactly as your sales team says them out loud.
- Coverage: the cities, countries or regions you serve, as text rather than as map markers.
- Any count you advertise, so a figure that quietly becomes stale fails a check instead of a customer conversation.
- The contact route you want used, because a form rendered entirely by a script is invisible in the document.
Then keep the record of what you asserted and when you changed it, because the assertion list becomes the clearest statement anybody has written of what the page is for. The argument for keeping the underlying record rather than only your conclusion about it is made in our page on keeping the log rather than the shortlist.
Questions about writing a content assertion for a page
Is this not just a smoke test?
It is a smoke test with a deliberate list, which is the difference that matters. A smoke test usually checks that a page returns successfully. This checks that the page returns the specific facts somebody decided it owes a reader.
How many assertions should one page have?
As many as it has load bearing facts, which is usually between three and ten. If the list runs long, that is a sign the page is doing several jobs and the assertions are telling you something about the page rather than about the test.
What do I do when an assertion fails on a legitimate change?
Change the assertion in the same commit as the page, and say why in the message. A failure that makes you update the declared expectation deliberately is the system working; a failure you silence is how a check stops meaning anything.
Should I assert against the rendered page or the raw response?
The raw response, with no scripts run. That is what an automated reader receives, and a figure that only exists after rendering is exactly the thing you are trying to catch.
Can an assertion replace every comparison?
It replaces the ones where you know what the answer should be, which is most of the commercially important ones. Keep a comparison for the cases where the question genuinely is whether two readings differ, such as whether a named agent is served something different from a browser.
The list is the deliverable
Writing the assertions forces a decision nobody had made: which facts this page is obliged to state in plain text to anybody who asks, including a reader that runs nothing. That list turned out to be more useful than the check built on it, because it is also the specification for the page. Our own version of it is short, public and dated, and the figures it protects sit beside the exports and the dated blind scan on our proof page, including the reading from before the fix. Deciding that list with a client and then holding their pages to it is a service we charge for. Keeping those facts correct after publication, which is the other half of the job, is covered in our page on keeping a page worth citing after it is published.