The End-to-End Illusion
End-to-end testing promises to simulate real user journeys, but in practice, most tests stop at the UI. A user signs up, submits a form and an assertion confirms that a success message appeared. Test passed.
But in reality, the journey doesn’t stop there.
Most applications rely on email at some point in the user flow, whether it’s for verifying an account, resetting a password, confirming a booking or delivering a receipt. If your test stops at the frontend, you’re not catching the moments where real users are most likely to get stuck.
Why Multi-Surface Testing Matters
Modern web applications are made up of many interconnected parts. When we talk about end-to-end testing, we should be testing the entire journey, not just the browser interface.
Here are a few common flows that extend into email:
A new user signs up → receives a verification email → clicks a link → completes account setup
User resets their password → gets an OTP or reset link → creates a new password
A Customer makes a purchase → gets an order confirmation → tracks the delivery
Each of these involves critical functionality outside the browser. If the email doesn’t arrive, contains the wrong link, or fails to render correctly, the user is blocked. Most the time those bugs often don’t show up unless you’re explicitly testing for them.
Cypress: Automating the UI layer
Cypress is an excellent tool for automating frontend testing. It simulates real user interactions like typing, clicking, and navigating. It also gives you control over the browser environment, letting you:
For the UI part of an end-to-end flow, Cypress does a great job. But it doesn’t natively support monitoring or interacting with an email inbox. That’s where external tooling comes in.
Testing the Email Layer
To fully cover an end-to-end flow, we need to go beyond the browser and into the user’s inbox. Here’s what that typically involves:
👉 Trigger an action
👉 Wait for an email to arrive
👉 Extract a piece of dynamic content (such as a link or OTP code)
👉 Continue the journey
This turns a fragmented test into a continuous, real-world simulation of what your users experience.
A Practical Example: Email Verification Flow
Let’s walk through a realistic test scenario: verifying a user signup that requires email confirmation.
The flow:
- User signs up via a form on your website
- The application sends a verification email
- The user clicks the link in the email to activate their account
- They land on a welcome/ setup page.
What your Cypress with Mailosaur test might look like:
javascript/cypress
// Step 1: Fill out the signup form
cy.get('input[name="email"]').type('testEmail@email.com');
cy.get('input[name="password"]').type('SecurePass123!');
cy.get('form').submit();
// Step 2: Use Mailosaur to wait for the email
cy.mailosaurGetMessage('serverId', {
sentTo: 'testEmail@email.com'
}).then((email) => {
// Step 3: Extract the link from the email body
const verificationLink = email.html.links[0].href;
// Step 4: Visit the verification link
cy.visit(verificationLink);
//depending on link domain, cy.origin() might be necessary here
// Step 5: Assert the user is on the correct page
cy.contains('Welcome to your account').should('be.visible');
});
Note: The actual implementation may vary based on your test environment, framework setup, and how your app structures its emails.
Dealing with Real-World Testing Challenges
When you step beyond the UI, you introduce some extra complexity. Here are a few common problems and how to handle them:
Asynchronous Delivery
Emails don’t always arrive instantly. You’ll need to account for that and there are a few tactics to achieve that. You can employ granular timeout increases at the individual command level, which is the Cypress recommended best practice over using hard coded waits. Additionally, you can create reusable, recursive functions to run a set of commands for retrieving the email (step 2 above) continually until a true value is returned or a rate/time limit is reached.
Message Filtering
If you’re testing in a shared environment or use real mailboxes, make sure you can uniquely identify the right message (e.g. by subject line or recipient).
Data Cleanup
Ensure each test uses unique test data or is run in an isolated environment to avoid flaky results from stale content.
Security Concerns
Never run these tests against real customer data. Use isolated test environments and dummy accounts.
Why This Approach Benefits More Than QA
Writing tests that span both UI and email isn’t just good for test coverage, it’s good for the whole team.
Developers gain visibility into how email content performs in the real flow
QA/QE can catch subtle integration bugs that fall between UI and backend
Product teams can be more confident that real users won’t get blocked during key journeys
It’s a collaborative process that bridges frontend and backend testing, and helps teams shift testing earlier in the development cycle.
Test What the User Actually Experiences
If your end-to-end tests stop at the browser, you’re not testing the whole experience. In today’s apps, email is part of the product. Failing to test email flows means you’re leaving critical gaps in your coverage.
By combining Cypress browser automation with a tool like Mailosaur to handle inbox validation, QA/QE teams can write smarter tests that reflect the real world and prevent bugs before they reach production.
Top comments (0)