What genuinely needs UI testing

  • The flow works end to end. A user can get from intent to outcome. Nothing below the interface can answer this.

  • State across steps. Something set on one screen is respected on the next. This is where real defects cluster.

  • The thing the user is told matches what happened. A success message with no saved record is the most common lie an app tells.

What does not belong in a UI test

Validation rules

  • Every combination of bad input through the browser is slow and fragile.

  • Check one in the UI, the rest at the API.

Calculations

  • A unit test answers this in milliseconds with a better failure message.

Data setup

  • Clicking through five screens to create a fixture is slow and breaks for reasons unrelated to what you are testing.

Sizing the suite

Two useful rules. Cover flows by how quietly they would fail rather than by importance, because important flows are watched and quiet ones are not. And stop adding when the maintenance cost starts eating the time you were saving, which happens earlier than most teams expect.

The three habits

  • Stable anchors, not CSS paths. Removes most redesign breakage.

  • Wait for state, not for time. Removes most flakiness.

  • Assert what a reload would confirm. Removes the false confidence of a success message.

Pushing a test down a layer, in practice

The advice to move checks below the interface is easy to agree with and vague to act on, so here is what it looks like on a real example.

You have a browser test that fills in a signup form with fourteen different invalid inputs and checks the error message each time. It takes four minutes, breaks whenever the form layout changes, and tells you almost nothing about the browser.

Replace it with one browser test that submits one invalid input and confirms an error is shown to the user, plus thirteen API tests that check the validation rules directly. The browser test now answers a browser question, the rules are covered faster and more precisely, and a validation change no longer requires touching anything that renders.

The part discipline cannot fix

Selectors

  • A redesign that changes nothing functional turns the suite red.

  • Where most maintenance time actually goes.

Waiting

  • Fixed delays are slow and still flaky. Correct waits need to know what to wait for.

  • Most flakiness traces back here.

Authored coverage

  • You cover what someone wrote, which is the interesting flows rather than the ones that break.

The third one is structural. Coverage bounded by author time will fall behind a product whose code increasingly arrives from an agent. Intention-based steps and generated coverage address that part.

Terminal

npm install -g @testsprite/testsprite-cli
testsprite setup

The dashboard covers the same ground for anyone who does not want a local install, and the full command surface lives in the CLI repository.

Connect the repository from the dashboard and runs start from the deployment you already produce, or add a step to your own workflow instead.

What TestSprite covers at each layer

Flows in the browser, where only a browser can answer, and the API layer underneath in the same project. That is what makes the push-it-down advice practical rather than aspirational: the validation rules move to API cases that run in seconds, and one browser case checks that the form is wired to them.

Both are generated from your product and refined in plain language, and browser steps are intentions rather than selectors, so the suite survives redesigns that change nothing functional.

What you end up with is a browser suite small enough that people trust it, covering the journeys that matter, with the rules and edge cases covered faster one layer down.

How many UI tests is right?

Enough to cover the journeys you would be embarrassed to break, chosen by how quietly they would fail. Push everything else down a layer.

Should we test every screen?

No. Test flows, not screens. A screen with no flow through it rarely justifies a browser test.

What about accessibility?

Worth automating for the mechanical checks and it needs human review for the rest. A separate concern with its own tooling.

Is cross-browser coverage necessary?

Depends on your analytics. Many teams run a full suite on one browser and a smoke suite on the others, which is usually the right trade.

When should UI tests run?

On every pull request. Anything less frequent means a failure points at a batch of changes rather than one.

The short version

Test flows in the UI, everything else below it.

UI testing should cover end-to-end flows, state across steps, and whether what the user is told matches what happened. Validation, calculations and data setup belong a layer down, where they are faster and easier to diagnose.