End-to-End Test
Method
A test that opens a real browser and clicks through a flow in the order a user would, checking that the path holds together end to end.
Why it exists
Testing started at the level of parts. Feed a value into the function that calculates a price and check the result; pull one screen out on its own and check that a button responds. That style is fast and cheap — two thousand of these run in under a minute. And yet there were days when all two thousand came back green and customers still could not use the product.
Working parts do not add up to a working product if the seams between them break. Login works, saving a document works, but the address the app redirects to after login is off by one character, so nobody ever reaches the save screen. A test that isolates one function will never see that gap, because each function did exactly what it was asked to do.
Pagedeck hit this. Theo confirmed every test was green on a Friday and shipped. Monday morning Sofia reported that customers who had just signed up could not create their first document. Permissions were attaching a beat late right after signup, and that delay blocked the first attempt. No component was broken. Nobody had clicked through in the order a real user does.
An end-to-end test hands that sequence to a machine. The check a person used to do by hand — open a browser, sign up, log in, create a document — gets written down as code and replayed on every deploy. The two ends the name refers to are the user's finger and the result that comes back on screen, and the test does not ask what sits in between.
How to run it
Pick one flow, write the interactions in the order a user performs them, and pin down what has to appear at the end. Six steps.
- Choose the flow — take one path with a clear start and finish, like signup through saving a first document. The unit is a goal, not a screen. A user flow diagram, which maps the screens and branches someone passes through to get something done, makes this selection much faster.
- Set up the starting state — decide which accounts and which data exist before the test runs. That prepared state is called a fixture: you write it down once and load it instead of building it by hand each time. When fixtures drift, a test that passed yesterday fails today for no visible reason.
- Write the interactions — script the steps into a tool that drives the browser for you. Open this address, type into the email field, click sign up, wait until the screen changes.
- Assert the outcome — state what counts as success. "The page navigated" is too weak. Pick something the user would verify with their own eyes, like the title of the document they just created showing up in the list.
- Put it on a schedule — tests that run when someone remembers do not run. Attach them to continuous integration and continuous delivery (CI/CD), the system that automatically verifies code changes and carries them through to deployment, so every push triggers a run.
- Capture evidence on failure — save a screenshot, a video, and the server logs from the moment things broke. Without that evidence, tracking down the cause takes longer than the run itself.
When it fits and when it doesn't
It fits flows where being wrong is expensive. Signup, checkout, granting permissions — paths where one blockage sends a user away or puts money in the wrong place. If a single payment passes through the front end, your server, a card processor, and an email send, there is effectively no other way to verify the whole chain at once. It also makes a good outer shell for regression testing, which checks that what used to work still works after a change.
There are three limits. First, it's slow. Launching a browser and waiting for pages to paint costs about ten seconds per case, so five hundred cases run for more than two hours. A check nobody waits for eventually gets turned off.
Second, it breaks easily. Rename a button from "Save" to "Save changes" and the test fails; let the server answer half a second late and it fails. End-to-end is where flaky tests — tests that pass some days and fail others without a line of code changing — show up most.
Third, it doesn't point at the cause. A failing unit test names one function. A failing end-to-end test means something among the dozens of pieces in that flow went wrong, and a person has to dig to find which.
So teams keep the count deliberately low. Thousands of unit tests, a few dozen end-to-end tests covering the most expensive flows. Invert that ratio and a full pass takes half a day.
How it sounds at work
"Can we get one E2E on this? It goes all the way to checkout, so a break would be obvious."
A request to spend a slot on this flow because it matters enough to cover.
"E2E is red but it works on my machine."
The problem may be the test environment or a timing issue rather than the feature — usually this is someone suspecting flakiness.
"Let's run E2E overnight only and keep unit and integration on every push."
A decision to split the fast checks from the slow ones because the full run got too long.
Pagedeck keeps about forty end-to-end tests. Signup, checkout, document sharing, and permission changes account for most of them. Unit and integration run first on every push, and end-to-end runs again right before a merge. When Theo decides whether a new feature gets one, the criterion isn't how big the feature is but whether Sofia gets a phone call when it breaks.
Mia watches a different number. If end-to-end failed twenty times over the last two weeks and only three of those were real bugs, she reads that as a signal to fix the unstable tests rather than add more.
What people get wrong
The most common mistake is assuming more end-to-end tests mean more safety. They sit closest to the user, so more of them looks strictly better. But as the count rises, so does the run time and the rate of breakage, and once most failures are not real bugs for a couple of months, people start hitting the rerun button on a red build without reading it. From that point the tests exist but do nothing.
Reading a green end-to-end suite as confirmation of quality is the same error. These tests only see the handful of paths someone wrote down. Measure test coverage, the share of code the tests actually execute, and the ground a few dozen end-to-end tests cover turns out to be narrower than it feels. A passing suite means the flows you recorded still work today; it says nothing about the code you changed yesterday.
Easily confused with
| Term | What it wires together | How it differs |
|---|---|---|
| Integration test | Several components connected inside the code | Never opens a screen and only checks the joins between parts. It wires the server to the database but doesn't ask what the user clicks, which makes it faster and far less brittle |
Where to go next
Last updated 2026-09-16