Integration Testing vs End-to-End Testing
Integration testing vs end-to-end testing: what each one covers, how they differ in scope, speed and failure causes, and when to write which.

Integration testing checks that a few connected parts of your app work together. End-to-end testing checks a whole user journey through the real system, from the first request to the last response. An integration test touches fewer parts, so it has fewer ways to fail. An end-to-end test covers more ground, so it catches more kinds of bug and takes longer to diagnose. You need both, in different amounts. The guide to unit tests vs integration tests covers the lower layers. This one covers where integration stops and end-to-end begins.
Integration vs end-to-end tests at a glance
An integration test asks “do these parts work together?” An end-to-end test asks “does this journey work for a user?”
| Integration test | End-to-end test | |
|---|---|---|
| Scope | A few connected parts | A full user journey |
| Runs against | Real neighbors, or a stand-in for one of them | The running app and every service the journey touches |
| Entry point | A function, a service call or an HTTP request | The interface, or the API below it |
| Typical count | Fewer than unit tests | The fewest |
| Fails because | A connection between two parts broke | Anything along the journey broke |
Google’s testing blog suggests a 70/20/10 split, 70% unit, 20% integration and 10% end-to-end, as a good first guess. The exact numbers matter less than the shape: many small tests at the bottom, few large ones at the top.
What an integration test covers
An integration test covers the seam between parts: a route and its database, a service and the service it calls, a client and the JSON it reads back.
The word is used two ways. A narrow integration test covers just the code that talks to one neighbor, usually with a test double on the other end. A broad one needs live versions of all the services it touches, as Martin Fowler’s note on integration tests puts it.
Because the scope is small, a failure points to a short list of suspects. For the definition and a worked example, read what integration testing is.
What an end-to-end test covers
An end-to-end test runs a journey the way a user would, and it passes only if every part along the way works together. Sign up and log in, add an item and pay, create a project and invite a teammate: each is one test that crosses the interface, the services, the database and the network.
A journey can enter your app in two places. A browser test enters through the UI. An API flow test enters at the HTTP layer and sends the requests the UI would send. Playwright can do the second job too: it can send requests straight to your REST API with no browser.
Speed and failure causes, measured on one journey
We ran one shop journey two ways: as a browser test and as an API flow. The setup was a 2-vCPU, 7 GB Linux container sized like a CI runner, with the app and the tests in the same container. These numbers come from that one app and journey. They are not a general benchmark, and they compare a browser test with an API flow, not integration with end-to-end in general.
Speed. 10 runs of the browser test took 11.2 s in total. 10 runs of the flow took 2.2 s.
A UI-only change. We renamed the Edit button’s CSS class, two lines of front-end code, with the API untouched. The browser test failed after the 30 s test timeout, and the flow passed all 8 steps.
A real change. After a real API change broke both tests, the median time to green was 21 s for the flow and 61 s for the browser test.
The pattern is the one the table predicts. The more parts a test crosses, the more it depends on, and the less its failure message says about the cause.
What end-to-end tests catch that integration tests cannot
End-to-end tests catch bugs that only appear when the whole journey runs, and bugs that live in the screen. Integration tests catch neither by design.
A browser test is the only test that sees your layout, your client-side logic and your accessibility. A button that never appears, a form that validates wrongly in the browser, a route the client calls with the wrong path: an API-level integration test will not notice, because it never loads the page.
The reverse holds too. Across 8 bugs, the unit tests caught 5 and one API flow test caught 6. Each side found bugs the other missed, which is the case for layers. For the browser side in depth, including why these suites get slow and flaky, see the end-to-end testing guide.
Which to write, and how many
Write integration tests for the connections and the edge cases, and a few end-to-end tests for the journeys that would hurt most if they broke.
The line blurs at the API. An API flow that logs in, creates a record and updates it is an integration test of your app, and it is also an end-to-end test of that journey, minus the screen. That makes it the cheapest way to cover a journey. Keep a small set of browser tests on top for what users see. The testing pyramid with an API layer shows where each sits.
You can write API flows by hand, or record them. Stresseur records how an API is really used during development, turns those flows into YAML tests, and runs them in CI on every pull request. The flows live in your repo under api-tests/. See API integration tests from real traffic for how it works, or run npx stresseur init --demo to try it on a built-in sample shop.
Integration tests prove the parts connect. End-to-end tests prove the journey works. Start with the one journey your users cannot live without, test it through the API, and add a browser test only where the screen is what could break.
Frequently asked questions
Is an API test integration or end-to-end?
It can be both. An API flow that logs in, creates a record and updates it is an integration test of your app, and it is also an end-to-end test of that journey, minus the screen.
How many end-to-end tests should I write?
Fewer than the other kinds. Google's testing blog suggests a 70/20/10 split, 70% unit, 20% integration and 10% end-to-end, as a good first guess. Adjust it to what your own bugs look like.
Can Playwright test an API directly?
Yes. Playwright can send requests straight to your REST API, with no browser.
What is a flaky end-to-end test?
A flaky test passes or fails on different runs without any change to the code.
How do I run these tests on every pull request?
Put them in CI. Stresseur turns recorded flows into YAML tests and runs them in CI on every pull request. The flows live in your repo under `api-tests/`.