End-to-End Testing: What to Automate First
End-to-end (E2E) testing checks that a real user journey works across the connected parts of an application, from the interface through services and data stores. Automate a small set of high-value, repeatable journeys first: sign-in, a core task that creates or changes data, and the confirmation or recovery path customers depend on.
What end-to-end testing covers
An E2E test exercises a system through interfaces and dependencies in a way that resembles user behavior. For an online shop, a test might sign in, add an available item to a cart, enter a shipping address, complete a test payment, and verify the resulting order. It can reveal integration failures that isolated unit tests cannot, such as a front end sending the wrong field to an API.
“End to end” does not mean every test must run against every production dependency or cover every possible input. A test may use a controlled test environment, seeded data, and a payment simulator. The important distinction is that it verifies an important workflow across multiple layers rather than testing a single function in isolation.
What to automate first
Choose journeys by customer impact and likelihood of failure, not by how many screens they contain. A practical first group usually includes:
- Access: sign-in and sign-out, plus a critical account recovery flow if customers rely on it.
- The main customer outcome: the shortest successful path to the product’s core task, such as submitting a booking or saving a document.
- Important changes: editing, cancelling, or deleting a record when mistakes could cause customer harm or support work.
- Payment or other high-consequence steps: verify the application’s handoff and recorded outcome using a test provider or safe test mode, not a real charge.
- Failure and recovery: a meaningful validation error, retry, or interrupted request, where the user needs to know what happened and how to continue.
- Common access conditions: a representative supported browser or device, and any essential permission or accessibility path.
Prioritize workflows that are used often, block a key task when broken, cross several system boundaries, or have a history of regressions. A simple sign-in test that catches a release-blocking defect can be more valuable than a long test covering an obscure configuration.
How to build a reliable E2E test
- Define the customer outcome. State what must be true at the end, such as “the submitted booking appears in the account with the chosen date.” Avoid defining success only as “the button was clicked.”
- Make the environment predictable. Use dedicated test accounts and controlled data. Create the needed state through an API, fixture, or setup step when possible instead of relying on another fragile UI journey.
- Interact as a user would. Locate controls by accessible role, label, or stable test identifier. Prefer observable behavior over implementation details such as CSS classes or private storage values.
- Assert meaningful results. Check the visible confirmation and, where appropriate, verify the persisted result through a supported test interface. A click completing without an error is not proof that the task succeeded.
- Clean up safely. Remove test-created records or use uniquely identifiable data that can be discarded. Ensure tests cannot contact real customers, send genuine notifications, or trigger real transactions.
- Run it at the right points. Run a focused, fast critical-path set on changes and a broader suite on a schedule or before release. Keep failures visible with logs, screenshots, or traces that help diagnose the cause.
What belongs in other test layers
E2E tests are powerful but comparatively slow and sensitive to environment conditions. They are not a substitute for unit, component, or API tests. Put detailed rules—such as whether a discount is valid for a particular combination—in unit or service-level tests. Use component tests for interface states and API tests for request validation and service contracts. Reserve E2E automation for checking that the most consequential pieces work together.
This layered approach also helps locate defects. If a calculation has dozens of edge cases, testing each through a browser makes the suite slow and hard to diagnose. A handful of E2E cases can confirm that the calculation’s result reaches the customer-facing workflow, while lower-level tests cover the rules thoroughly.
Common problems and how to reduce them
- Flaky timing: fixed delays fail when the application is faster or slower than expected. Wait for a specific visible state or response instead of sleeping for an arbitrary duration.
- Shared or stale data: tests interfere when they modify the same account or assume records remain unchanged. Give each run isolated data and make setup repeatable.
- Overly broad tests: a single test that traverses many unrelated features is difficult to debug. Keep each test focused on one customer outcome, while avoiding needless repetition of the same setup.
- Unstable selectors: selectors tied to layout or styling break during harmless redesigns. Use accessible names and roles, or stable test IDs when necessary.
- External service failures: a third-party outage can make an application test look broken. Simulate external services for predictable workflow checks, and separately monitor real integrations with appropriate contract or health checks.
- False confidence: a green suite only shows that its scenarios passed in that run. It does not establish complete coverage, prove security, or guarantee that all production conditions are represented.
When a test fails, first determine whether the product behavior is wrong or the test environment, data, or dependency is unreliable. Do not routinely rerun and ignore failures: repeated flakiness obscures real regressions and erodes trust in the suite.
How to decide what comes next
After the initial critical journeys, review support incidents, product analytics, defect history, and upcoming changes. Add automation where the likely customer impact justifies the cost of writing and maintaining it. A useful test has a clear owner, a stable setup, an understandable assertion, and a failure response that someone will act on.
Coverage percentages alone are a poor ordering rule: a high number of automated screens does not prove that the most important customer outcomes are protected. Measure whether the suite catches meaningful regressions, provides quick feedback, and can be repaired without excessive investigation. Remove or redesign tests that no longer represent supported behavior.
Frequently Asked Questions
Should every user journey have an E2E test?
No. Automate representative, high-impact journeys at the system level, and cover detailed variations with faster unit, component, or API tests. Duplicating every edge case in a browser suite adds maintenance without necessarily adding useful confidence.
Should E2E tests run in production?
Most should run in a controlled test environment. If a team uses production checks, they should be deliberately designed around safe, reversible actions and must not create real charges, notify customers, or alter customer data.
Why are E2E tests flaky?
Common causes include timing assumptions, shared data, unstable selectors, and unavailable external services. Explicit state-based waits, isolated test data, stable locators, and controlled dependencies reduce these failures.
Is a successful E2E test proof the feature is bug-free?
No. It confirms only that the tested scenario passed under the conditions of that run. Uncovered inputs, browser differences, production data, and other system conditions can still expose defects.
What should a team automate first if it has no E2E tests?
Start with one repeatable, business-critical journey from entry to a verifiable outcome, using test data and safe dependencies. Add sign-in or recovery and a high-impact failure path according to customer needs and risk.
Related
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.