Why your end-to-end tests keep breaking
Most end-to-end suites don't fail because the product broke. They fail because a selector moved. Here's what actually causes the churn.
Your CI went red overnight. You open the failure, and the checkout button is right there on the screenshot, exactly where it has always been. Nothing is broken. Someone wrapped the form in a div.
This is the normal condition of end-to-end testing, and it is why most suites quietly stop being trusted. Not because they catch nothing, but because they cry wolf until nobody reads them.
Selectors are a promise the UI never made
A selector-based test does not look for the button. It looks for a path to the button: a class, a test id, a position in the tree. That path is an implementation detail. Nobody on the team agreed to keep it stable, and no review ever asks "does this rename break a selector?"
So the path drifts. Every redesign, every component extraction, every CSS refactor moves something. The test fails, an engineer spends twenty minutes confirming the product is fine, and updates the selector. Multiply by a hundred tests.
The cost is not the twenty minutes. It is that after a few rounds of this, a red build stops meaning anything.
What changes, versus what matters
| A test should fail when | A test should not fail when |
|---|---|
| The pay button never enables | The pay button moved to a new parent |
| Checkout charges the wrong total | The class went from .primary to .btn |
| Sign-up silently drops the password | A designer changed the padding |
| The confirmation screen never loads | The DOM gained a wrapper div |
Everything in the right column is churn. A suite that cannot tell the two columns apart is a suite that will eventually be ignored.
Describe the intent, not the path
The alternative is to anchor the test to what a person would do, because that is the thing you actually promised your users:
Sign up, add an item to the cart, and check out.
That sentence is the whole test. A vision agent reads the rendered screen and decides what to tap, the same way a person scanning the page would. When the button moves, it is still the button that says "Place order", so the test still passes. When the button never enables, the test fails, which is the point.
The same sentence drives a real Android or iOS device and a real browser, so one description covers your app and your dashboard. A web check needs no build artifact at all, just a URL, which means it can run on a pull request before anything is compiled.
Start with three
If you are rebuilding a suite that nobody trusts, do not port all hundred tests. Three flows are worth more than thirty:
- Sign-up, all the way to a usable account
- Checkout, all the way to a confirmed order
- Whatever your support inbox complained about most last month
Every run gives you a video, a screenshot of each step, and a stated reason for what the agent did, so when one does go red a reviewer can watch the failure instead of guessing at it.
Start free and have the first one running in about five minutes.