When a pixel-perfect screen is still broken
Visual testing proves the UI looks right; functional testing proves it works. A checkout that passed every screenshot and lost a fraction of a percent of conversions, and how the two layers fit.
Visual testing proves the UI looks right; functional testing proves it works. They sound like two ways of saying the same thing and they are not. Each one is blind to what the other catches, and the clearest case I have heard for keeping both came from someone arguing against my product.
The fraction of a percent that was millions
He used to lead the web team at a large consumer marketplace, well over a hundred engineers touching the web, and his objection is the sharpest version I know: "screenshot testing detects visual differences, but it still doesn't check that something works. I've always found it partial." Then the story. Checkout conversion dropped by a fraction of a percent, the kind of number nobody would normally chase, except that at that scale it was millions. No errors were logged. Nothing had changed massively. The UI looked good. The screenshots looked good. On a subset of mobile devices, the submit button could not be tapped.
Their automated tests did not catch it either, because they clicked the DOM element programmatically, and the element worked. The real cause was a device-specific hit-target problem: something invisible over the button, or a handler that never bound on that browser. Screenshot testing would not have found it, and he was right to say so. It ran for a while before anyone connected the leak to a release. When they fixed it, conversion went back up.
The mirror image is just as real
An end-to-end test can click through a flow entirely green, finding every element by test id and asserting the right final state, while a human looking at the page sees overlapping text, a control pushed off screen, a modal rendered behind its backdrop. The behaviour is correct and the appearance is not, and the functional test has no way to know because it never looks at the pixels. My own version of this: at a talk this summer I described the six-agent problem, six PRs with green checks all waiting on a human, and when you run them you find the component and the endpoint were both built and do not talk to each other. Tests are how you stop being the thing that checks. But only if they check different things.
| Visual test | Functional or interaction test | |
|---|---|---|
| Proves | The UI looks the way you accepted | The UI does what a user needs |
| Catches | Layout shifts, missing elements, colour and spacing drift | Broken handlers, dead controls, wrong state after an action |
| Misses | A control that renders perfectly but does nothing | A flow that clicks through green while the layout is broken |
How do visual and functional testing fit together?
What I told him on the call is how I think about it now. Visual tests are closer to unit tests than people assume: cheap, isolated, one component in one state, and they go red on the class of bug nothing else sees. Interaction tests, where you render the page, click the button, and assert the modal opened, are the real integration tests. You need a thin layer of those on the critical flows so a dead control cannot pass silently, and you need visual coverage so a broken layout cannot pass silently either. Unit tests own the logic underneath both. You do not need a heavy end-to-end suite; you need enough of each layer that its blind spot is covered by the other.
The result, when the layers are in place, is a different bug profile. At a previous company we were two frontend engineers making UI changes all the time, with about a thousand visual tests covering every page and state. The number of UI bugs that reached our issue tracker was minimal. That is what changed my mind about visual testing being a nice-to-have.
The cost side is worth stating the same way he stated the conversion side. A UI bug that slips through is not only the revenue it leaks. It is the ticket someone files, the reproduction, the fix, the review, and the release, for a defect an agent could have caught in a minute before the merge. At a hundred-plus engineers, a small pixel change with a large impact is a seven-figure risk. At two engineers, it is a week of someone's attention. Both are worth a screenshot.
Can you run visual and functional tests from one build?
On the Storybook path, UI Verify executes each story's play function and waits for it to pass before capturing, so the image you diff is the settled state after the interaction, not the component at first paint. A play that throws is a failed interaction test, kept distinct from a render error, and that frame is never diffed and never promoted to a baseline. A broken interaction cannot quietly become the reference image.

That is the shape of the checkout bug, one layer down: a screen that renders correctly and fails the moment something tries to use it. For an agent shipping UI changes, getting both signals from one run is the difference between "it renders" and "it renders and it works". How the hook works is in interaction tests; it runs on the Storybook path, because Playwright and Vitest tests have already performed their interactions before the archive is recorded.
If you are setting this up from scratch, wire visual coverage first with the setup skill, then add interaction tests on the flows where a silent behavioural failure would cost you. A pixel-perfect screenshot is not proof the screen works, and a green click-through is not proof it looks right. Run both, and let each cover the other's blind spot.
Get both signals from one run
UI Verify captures your components and runs your interaction tests before it does, so your agent sees the visual diff and the behaviour together. Wire it up free.
Start for freeNo credit card required.
Set up visual testing
From no visual tests to a green check on every pull request.