
What Is End-to-End (E2E) Testing?
Liviu Lupei
Founder & Solutions Architect, Endtest · May 26, 2026
What is end-to-end testing?
End-to-end testing, often shortened to E2E testing, is a software testing method that verifies whether an application works correctly from the perspective of a real user.
Instead of testing one function, one API, one database query, or one UI component in isolation, an end-to-end test validates a complete user journey from beginning to end.
For example, an end-to-end test for a SaaS application might verify that a user can:
- Open the sign-up page.
- Create an account.
- Receive the confirmation email.
- Click the validation link from the email.
- Log in with the newly created account.
- Add billing information.
- Invite another team member.
- See the correct dashboard state.
That is very different from checking whether the createUser() function returns the right value or whether a React component renders the correct button label.
Those smaller tests are useful, but they do not answer the most important question:
Can a real user complete the flow successfully?
That is the core purpose of end-to-end testing.
Why end-to-end testing matters
Most production bugs do not happen because one isolated function fails in a clean, predictable way.
They happen at the boundaries between systems.
A web application might have a working frontend, a working backend, a working email provider, a working SMS provider, and a working database. But the full user flow can still fail because those systems do not work together correctly.
For example:
| Layer | What can go wrong |
|---|---|
| Frontend | The button is hidden, disabled, overlapping, or broken in one browser. |
| Backend | The API accepts the request but returns the wrong response. |
| Database | The user record is created with the wrong status. |
| Email service | The confirmation email is not sent or contains a broken link. |
| SMS provider | The OTP code is delayed, missing, expired, or sent to the wrong number format. |
| Authentication | The user is created but cannot log in after validation. |
| Browser | The flow works in Chrome but fails in Safari or Firefox. |
A unit test might tell you that the email generation function produced a string.
An integration test might tell you that the API created a user.
But only an end-to-end test can tell you that the user could actually sign up, receive the email, click the link, verify the account, receive the SMS code, enter the OTP, and reach the correct page.
That is why E2E testing is so important for critical flows.
A real sign-up flow is more than a form submit
Sign-up is one of the best examples of why end-to-end testing matters.
Many teams say they test sign-up, but what they really test is only the first part of the flow. They fill in the sign-up form, click the submit button, and check that a success message appears.
That is not enough.
A proper end-to-end sign-up test should verify the entire journey:
- The user can open the sign-up page.
- The form accepts valid input.
- The form rejects invalid input.
- The account is created.
- The validation email is actually sent.
- The validation email is actually received.
- The confirmation link inside the email works.
- The account status changes after the email is confirmed.
- The user can continue to the next step.
- If phone verification is required, the SMS is actually sent.
- The OTP code can be extracted from the real SMS message.
- The OTP can be entered successfully.
- The user reaches the correct authenticated state.
This is the difference between testing a screen and testing a business-critical flow.
If your product depends on email validation, then the email validation must be part of the E2E test.
If your product depends on SMS verification, then SMS verification must be part of the E2E test.
Endtest supports this type of flow by allowing teams to automate browser interactions together with email testing and SMS testing, so the test can validate what actually happens outside the browser as well.
You can learn more about Endtest features on the product page or review the available plans on the pricing page.
Why extracting the OTP from the database is not enough
A common shortcut in automated testing is to extract the OTP code directly from the database.
That can be useful for some backend-level tests, but it is not a real end-to-end test.
If the test gets the OTP from the database, it proves only that the OTP was generated and stored. It does not prove that the SMS was sent. It does not prove that the SMS provider accepted the message. It does not prove that the phone number format was valid. It does not prove that the user received the message.
That difference matters.
Imagine this situation:
- The application generates the correct OTP.
- The OTP is saved correctly in the database.
- The test reads the OTP from the database.
- The test enters the OTP in the browser.
- The test passes.
But in production, users are not receiving the SMS.
Maybe the SMS provider rejected the request. Maybe a country prefix was formatted incorrectly. Maybe the sender ID was blocked. Maybe the provider API changed. Maybe the SMS was delayed beyond the expiration window.
The database shortcut would miss all of those problems.
A true end-to-end test should use a real SMS number controlled by the test automation system, wait for the actual SMS message, extract the OTP from that message, and then continue the flow in the browser.
That is the only way to verify the real user experience.
The same principle applies to email validation. Reading a token directly from the database is not the same as receiving the email and clicking the validation link.
E2E testing vs unit testing
Unit tests verify small pieces of logic in isolation.
For example, a unit test might check that a password validation function rejects passwords that are too short. Another unit test might check that a price calculation function returns the expected result.
Unit tests are useful because they are fast, cheap, and precise. They help developers catch logic errors early.
But functional end-to-end testing can never be replaced by unit tests.
Unit tests do not open a browser, interact with the real UI, validate that the frontend and backend communicate correctly, confirm that emails are delivered, check whether SMS verification works, or prove that a user can complete a real journey.
A healthy test strategy usually includes multiple layers:
| Test type | What it validates |
|---|---|
| Unit tests | Small pieces of logic in isolation. |
| Component tests | Individual UI components or frontend behavior. |
| Integration tests | Communication between modules, services, or APIs. |
| API tests | Backend endpoints and data contracts. |
| End-to-end tests | Complete user flows across the full system. |
The mistake is assuming that unit tests are enough.
E2E testing vs component testing and Storybook
Modern frontend teams often use component-driven development. Tools like Storybook make it easier to build, document, and test UI components in isolation.
That is useful.
A Storybook test can verify that a button renders correctly. A component test can check that a modal opens when a user clicks a trigger. A visual test can catch a layout regression in a specific component.
But a real user does not use your product one component at a time.
A real user goes through flows.
They click a sign-up button, fill out a form, receive an email, confirm the account, log in, configure settings, invite teammates, upload files, and complete work inside the product.
Component tests cannot verify the full chain.
They do not validate routing across the real application, verify production-like authentication behavior, confirm that third-party integrations work, or detect that a confirmation email was never received.
Component tests and Storybook tests are useful, but they are not a replacement for end-to-end tests.
They answer a different question.
Component tests ask:
Does this piece of the interface behave correctly?
End-to-end tests ask:
Can the user complete the journey?
You need both.
The real value of E2E testing is confidence
The goal of end-to-end testing is confidence, not the largest possible test suite.
Before a release goes live, the team should know that the most important user journeys still work.
For a SaaS product, those journeys might include:
- Sign up
- Email validation
- SMS verification
- Login
- Password reset
- Creating a project
- Inviting a teammate
- Changing billing details
- Running a core workflow
- Exporting a report
- Canceling a subscription
For an eCommerce application, they might include:
- Searching for a product
- Adding an item to the cart
- Applying a discount code
- Creating an account
- Entering shipping details
- Completing checkout
- Receiving an order confirmation email
For a banking or fintech application, they might include:
- Creating an account
- Verifying identity
- Logging in with two-factor authentication
- Adding a beneficiary
- Making a transfer
- Receiving transaction notifications
These are business workflows as much as technical ones.
If they fail, the business loses sign-ups, sales, trust, or revenue.
That is why end-to-end testing should focus first on the flows that matter most.
Cross-browser testing is part of real E2E testing
A web application does not run in one browser.
Real users may access it from Chrome, Safari, Firefox, Edge, and mobile browsers. They may use Windows, macOS, iOS, Android, or different screen resolutions.
That matters because browsers do not behave exactly the same.
A flow that works in Chrome can fail in Safari. A CSS layout that looks correct in Firefox can break in Edge. A JavaScript feature can behave differently depending on the browser version. A file upload, date picker, permission dialog, video element, drag-and-drop interaction, or clipboard action can work in one environment and fail in another.
Cross-browser testing is the practice of verifying that your application works correctly across the browsers and operating systems your users actually use.
At minimum, teams should test the major browsers represented in their analytics data. If 25% of your users are on Safari, then Safari cannot be treated as an afterthought. If many users are on Edge because your customers are enterprise companies, then Edge needs to be part of your test coverage.
Endtest allows teams to run automated tests across major browsers, including real Safari, so teams can validate flows in environments that better match real users.
Real browsers matter
A headless browser running inside a Linux container can be useful for some types of automation.
It is fast, easy to run in CI, and cheap to scale.
But it does not fully mimic the environment of a real user. Real users use real browsers on real operating systems, not headless browsers inside Linux containers.
Certain issues only appear in a real browser environment:
- Browser-specific rendering differences
- Safari-specific behavior
- Native permission prompts
- File upload behavior
- Download behavior
- Clipboard restrictions
- Video and media playback behavior
- Font rendering differences
- OS-level dialogs
- Browser extension interactions
- Real viewport and device behavior
If your E2E tests only run in headless Linux containers, you may be testing a convenient approximation of the user environment, not the real environment.
For meaningful functional end-to-end testing, critical flows should be validated in real browsers running on Windows and macOS machines.
This is especially important for teams that serve enterprise users, consumer users, or global users across many browser and operating system combinations.
React does not eliminate browser bugs
Modern frontend frameworks like React, Vue, Angular, Svelte, and Next.js have made web development more productive.
But they do not eliminate cross-browser issues.
React can help structure the UI, manage state, make component reuse easier, and reduce some categories of mistakes.
But React does not control every browser behavior.
Your application still depends on:
- Browser APIs
- CSS support
- JavaScript runtime behavior
- Event handling differences
- Network behavior
- Storage behavior
- File input behavior
- Media behavior
- Permission prompts
- Third-party scripts
- Real user devices and operating systems
A React application can still have a Safari-only bug, a date picker issue in one browser, or a failure caused by a browser that blocks a permission, handles an event differently, or renders a layout differently.
The fact that an application uses a modern frontend library does not remove the need for end-to-end testing or cross-browser testing.
It often makes the need stronger, because modern applications are more dynamic, more interactive, and more dependent on client-side behavior.
E2E testing belongs in the CI/CD pipeline
End-to-end tests are most useful when they run automatically.
If E2E tests are run only before major releases, they become a late-stage safety net. That is better than nothing, but it still means bugs may be discovered after the team has already moved on.
The better approach is to run critical E2E tests in the CI/CD pipeline.
When a developer opens a pull request, merges to the main branch, or deploys to staging, the pipeline should automatically run the most important end-to-end tests.
That gives the team fast feedback.
If the sign-up flow breaks, the team should know before the release reaches users. If login stops working in Safari, the password reset email contains a broken link, or SMS verification fails because of a provider issue or a formatting change, the team should know before customers report it, before support tickets arrive, and before new users get blocked.
Running E2E tests in CI/CD is one of the most practical ways to protect the user experience.
It is also one of the clearest signals that a team treats quality as part of delivery, not as a separate phase that happens after development.
Endtest supports CI/CD integrations so teams can trigger automated end-to-end tests as part of their release process.
What should be tested end-to-end?
Not every test should be an end-to-end test.
E2E tests are more expensive than unit tests. They involve more systems, more moving parts, and more execution time.
That is why teams should be selective.
The best candidates for end-to-end testing are flows that are:
- Critical to revenue
- Critical to onboarding
- Critical to trust
- Frequently used
- Historically fragile
- Connected to external systems
- Hard to verify with lower-level tests
- Expensive if broken in production
Examples include:
| Product type | High-value E2E flows |
|---|---|
| SaaS | Sign-up, login, invitations, billing, core product workflow |
| eCommerce | Search, cart, checkout, payment, order confirmation |
| Fintech | Login, 2FA, transfers, account verification |
| Healthcare | Patient registration, appointment booking, document upload |
| Marketplaces | Seller onboarding, listing creation, buyer checkout |
| Developer tools | Account creation, API key generation, first successful run |
The rule of thumb is that if the business would be seriously affected by the flow breaking, it should probably have an end-to-end test.
What should not be tested only through E2E?
End-to-end testing is powerful, but it should not be used for everything.
If you try to validate every tiny rule only through E2E tests, the suite can become slow, fragile, and difficult to maintain.
Some checks belong at lower levels.
For example:
- Password strength rules can be covered with unit tests.
- API validation rules can be covered with API tests.
- Complex calculations can be covered with unit tests.
- Individual UI states can be covered with component tests.
- Accessibility rules can be checked with accessibility testing tools.
- Visual regressions can be covered with visual testing.
Then E2E tests can focus on complete user outcomes.
For example, instead of writing 40 E2E tests for every possible sign-up form validation message, you might write lower-level tests for all validation rules and a smaller number of E2E tests for the most important successful and unsuccessful sign-up paths.
That balance keeps the test suite useful.
What makes a good E2E test?
A good end-to-end test should be realistic, reliable, and easy to understand.
It should describe a real user goal rather than a technical interaction.
Bad E2E test name:
test_143_form_submit
Better E2E test name:
New user can sign up, confirm email, verify phone number, and access dashboard
A good E2E test should also have clear assertions.
Do not stop after clicking a button. Verify that the correct result happened.
For example:
| Action | Weak assertion | Better assertion |
|---|---|---|
| Submit sign-up form | Success message appears | User receives validation email and account remains inactive until confirmed |
| Click email link | Page loads | Account becomes active and user can log in |
| Enter OTP | Field accepts code | Phone number becomes verified and user reaches dashboard |
| Complete checkout | Button clicked | Order confirmation appears and email is received |
The best E2E tests are written around user outcomes.
Common E2E testing mistakes
Many teams struggle with E2E testing because they approach it incorrectly.
Here are some common mistakes.
Testing too much through the UI
The UI is important, but not every logic rule needs a browser test.
Use API, integration, component, and unit tests where they make sense. Reserve E2E tests for full workflows.
Ignoring email and SMS
If a flow depends on email or SMS, the test should verify email or SMS.
Otherwise, the test is skipping one of the most important parts of the user journey.
Running tests only in Chrome
Chrome is important, but it is not the entire web.
If your users are on Safari, Firefox, or Edge, your tests should reflect that.
Using only headless Linux containers
Headless testing can be useful, but critical flows should also be tested in real browsers on real operating systems.
Not running tests in CI/CD
Manual or occasional E2E testing leaves too much room for regressions.
Critical tests should run automatically as part of the delivery process.
Creating tests that nobody maintains
E2E tests must evolve with the product.
If a test suite becomes outdated, noisy, or flaky, teams stop trusting it.
Tools like Endtest help reduce the maintenance burden by making tests easier to create, edit, run, and maintain without forcing every team member to write browser automation code.
Where Endtest fits
Endtest is built for teams that want reliable end-to-end test automation without building and maintaining their own Selenium or Playwright infrastructure.
With Endtest, teams can create and run automated tests for real user flows, including flows that involve:
- Browser interactions
- Email testing
- SMS testing
- API testing
- Cross-browser testing
- Real Safari testing
- Visual testing
- Scheduled test runs
- CI/CD integrations
- AI-assisted test creation and maintenance
That matters because modern E2E testing involves more than clicking buttons in a browser.
Real applications depend on email providers, SMS providers, authentication systems, APIs, browser behavior, operating systems, and third-party services.
A test automation platform should make it possible to validate those complete flows in one place.
Endtest helps teams test the full user journey instead of isolated technical fragments.
Final thoughts
End-to-end testing answers the question that matters most before a release:
Will the application work for real users?
Unit tests, component tests, Storybook tests, and API tests are all useful. They should remain part of a healthy testing strategy.
But they cannot replace functional end-to-end testing.
They cannot prove that a user received the validation email, that an SMS OTP was actually delivered, that a sign-up flow works in Safari on macOS, or that the full system works together after a deployment.
That is why end-to-end testing remains essential.
The best teams do not treat E2E testing as a final manual check before release. They automate it, run it in CI/CD, test real flows, include email and SMS when those are part of the user journey, and run tests across the browsers their users actually use.
And they use platforms like Endtest to make that process faster, more reliable, and easier to maintain.