notes
Sep 28, 2024 · 2 min read

Writing My First Real Test Suite

The site had exactly one test for most of its life: a GitHub Action step that ran astro build and checked the exit code. If the build didn’t crash, I shipped. This caught typos in frontmatter and not much else — a broken layout, a missing alt attribute, a link that silently 404s, none of that fails a build.

Where I started

I picked Playwright mostly because it could drive a real browser without much setup, and because I’d used it once at a previous job and remembered liking the trace viewer. The first test I wrote was almost insultingly simple:

test('home page loads and has a heading', async ({ page }) => {
  await page.goto('/');
  await expect(page.getByRole('heading', { level: 1 })).toBeVisible();
});

That one test caught nothing on its first ten runs. Then I refactored the header component and it caught a missing <h1> within a minute of me breaking it, which is the exact moment a test suite goes from “thing I wrote because I should” to “thing I trust.”

What I added after that

Once the first test proved its worth, adding more felt less like a chore:

  • A smoke test that visits every route generated from content collections, not just the ones I remember exist.
  • A check that every internal link on the home page resolves to a 200, run against the built output.
  • An axe-core scan on the article template, which is where most real accessibility bugs on this site have actually lived.

The part that surprised me

The axe-core scan found a contrast failure in a badge component within the first run — a coral background with white text that looked fine to me on my monitor and failed WCAG AA by a hair. I’d looked at that badge probably fifty times while building it. The test looked at it once and caught what I couldn’t see, which is a good one-sentence argument for why this suite exists at all: not to catch the bugs I’d notice eventually, but the ones I structurally can’t, because I already know what the page is supposed to look like.