Confidence Over Coverage: Testing Where Failure Is Expensive There is one number that has hurt frontend testing more than any bug: the coverage percentage. Teams chase it. Dashboards celebrate it. Pull requests get blocked over it. And after all that effort, the real question is still unanswered: do we actually trust this thing to ship? Coverage measures how many lines of code your tests ran . It says nothing about whether those tests would notice if the behavior broke. You can reach 100% coverage with tests that check almost nothing. You can sit at 60% coverage with tests that catch every failure that matters. The number and the goal are only loosely connected — and chasing the number pulls you away from the goal. An architect swaps the coverage question for a better one: where is a failure expensive, and are we testing there ? Why "100% coverage" is the wrong target Coverage fails as a measure of confidence in three ways. It rewards running code, not checking it. A test can render a component and check nothing, yet still count every line it touched as "covered." The dashboard turns green. The safety net has holes you cannot see through the number. It treats all code as equally risky. The line that formats a tooltip label and the line that decides which rows a user is allowed to see are worth very different amounts of testing. But coverage counts them the same. Chasing the last 10% usually means writing tests for trivial code — because the risky code was already tested, and the trivial code is all that is left. It creates tests that punish change. To lift coverage on stubborn code, people start checking internal details — private state, the exact order of function calls. Now every refactor (rewriting the inside of the code without changing what it does) breaks a pile of tests that were never protecting real behavior. The test suite starts to fight change instead of supporting it. None of this means coverage is useless. A floor on coverage — say, no new code below 80% — is a fair guard against plain neglect. The mistake is treating the ceiling as the goal. The better way: test by risk, not by line The alternative is to decide on purpose where testing effort goes, based on what a failure would cost. Some code is expensive to get wrong. Some is cheap. Test them differently. Expensive failures cluster in a few places: Logic that decides things — what is selected, what a key press means, what is enabled, who can see what. Wrong answers here are silent and serious. Public contracts — the props, events, and behavior other teams depend on. A break here spreads outward to code you do not own. Interaction correctness — can a keyboard-only user actually operate this? Does focus land where it should? Failures here lock real people out. Assembly — does the whole thing still work once it is built and dropped into a real app, not just in isolation? Cheap failures — a slightly wrong margin, a typo in a label — are real too. But they are better caught by other gates (visual checks, a reviewer's eye) than by piling unit tests on top of them. This is why the testing strategy in later chapters is a set of separate gates , each owning one expensive failure. Logic tests own correctness. Interaction tests own usability. Contract tests own compatibility. Each gate is clear about what it catches — so when one turns red, you know right away what broke. "Functional coverage" — the number worth keeping If you want a coverage number that actually means something, measure against the contract , not the lines. A component has a contract: the set of roles, states, and behaviors it promises. Functional coverage asks a simple question — does every one of those have at least one test? A dropdown that promises open, closed, keyboard navigation, disabled, and error states has 100% functional coverage when each of those five is tested. It does not matter how many lines that touches. The contract sets the target, so the number cannot be gamed by trivial code, and it cannot claim credit for behavior nobody actually checked. That is a number an architect can defend in a review: "every promise this component makes is tested." "We hit 94% of lines" is not the same sentence — and everyone in the room quietly knows it. The Trade-off: does risk-based testing mean testing less? It can look like permission to skip tests. It is not. It is a change in where the effort goes, and the difference matters. Side-by-side Coverage-driven Confidence-driven --- --- --- What you aim for Lines run Expensive failures caught The trivial getter Gets a test to lift the number Left alone — cheap to get wrong The permission logic One test among many Heavily tested — it is the whole point A refactor Often breaks tests that checked internals Tests hold — they check the contract The reported number "% of lines" — impressive, hollow "% of contract" — smaller, honest The sign you are chasing the wrong thing If your team writes tests to raise a number rather than to sleep better…