#performance#a11y#typescript

How We Test UI Without Snapshot Tests

· 3 min read

A colleague asked me last week why our team cares so much about design tokens. I gave a rambling answer, so here is the longer, more organized version.

Most of the complexity was accidental. Over the years we'd layered three different approaches to design tokens on top of each other, and each one made sense at the time.

How we got here

The first symptom was subtle. Nothing failed outright, but design tokens kept drifting in the wrong direction, and every fix seemed to make the next one harder.

We had good intentions. We even had a document describing how design tokens should work. The trouble was that the document and the code had quietly gone their separate ways.

Trying something different

We started by writing down the one rule we actually cared about, then deleted every bit of code that didn't serve it. It's not glamorous, but it works.

Here's a trimmed-down version of what we ended up with:

export function debounce<T extends (...args: any[]) => void>(fn: T, wait = 200) {
  let timer: ReturnType<typeof setTimeout> | undefined;
  return (...args: Parameters<T>) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), wait);
  };
}

This alone let us delete a surprising amount of code elsewhere in the project.

A few things that helped along the way:

  • Make the default the safe choice, not just the documented one.
  • Keep the old path around until the new one has survived a real incident.
  • Agree on what "done" means before the first pull request.

Caveats

None of this is free. The new approach is a bit more verbose, and newcomers occasionally ask why we don't just use Svelte for everything. That's a fair question with a boring answer: we tried, and it made design tokens harder to reason about.

The biggest cost was social, not technical. Changing how people think about design tokens takes much longer than changing the code.

Closing thoughts

If you take one thing away from this, let it be this: design tokens is a design decision, not a cleanup task. Make it early and make it on purpose.

HR
Hazel Rossi
Frontend engineer in San Diego. Writing about frontend engineering.