Ship/Now

Guides · 3 min

Testing

One command that drives a real browser against a real database, because the failures worth catching are between the parts.

The bugs that reach customers in an app like this are almost never inside a function. They are between two of them: the cookie that did not survive a redirect, the policy that lets the wrong row through, the panel that overflows at 360 pixels. Unit tests do not see any of those.

So the suite is one file that signs in for real, pays for real, and reads the page the way a customer would.

BASE=http://localhost:3000 node qa/buyer-flow.js

What it does

Creates a user through the admin API

Then deletes it first if it is left over from the last run, so the suite is re-runnable rather than passing once.

Signs in with a genuine magic link

Generated the same way the email template builds it, a token hash aimed at your own callback. If the templates are wrong, this fails, which is the point.

Grants an entitlement the way the webhook does

Then asserts the dashboard shows it: the key, the plan, the price formatted in the right currency.

Attacks its own policies

Reads every table with the publishable key alone and asserts it gets nothing. Posts an unsigned webhook and asserts a 400.

Measures the phone

Resizes to 360 wide and asserts scrollWidth never exceeds clientWidth, on every page, naming the offending element when it does.

The overflow check

This one earns its keep more than any other:

const over = await page.evaluate(() => {
  const doc = document.documentElement;
  return {
    scrollW: doc.scrollWidth,
    clientW: doc.clientWidth,
    wide: [...document.querySelectorAll("body *")]
      .filter((el) => el.getBoundingClientRect().right > doc.clientWidth + 1)
      .slice(0, 3)
      .map((el) => `${el.tagName}.${el.className}`),
  };
});

It does not just say the page is too wide. It names the three elements sticking out, which turns a twenty minute hunt into a one line fix.

Trust the test before you trust the fix

When a check fails, prove the check is right before changing the code. A failing assertion is a claim, not a verdict, and half an hour spent fixing a bug that was really a bad selector is half an hour you do not get back.

What is not here

There are no unit tests, and that is a choice rather than an omission. Add them where you have real logic: pricing arithmetic, entitlement rules, anything with branches worth enumerating. Do not add them to assert that a component renders.

Something wrong or missing on this page? Tell us.