Reliably Testing Authentication Flows End to End
AI generated
PASS
expect()
Authentication · E2E Testing
Reliably Testing Authentication Flows End to End
How login, logout, session timeout, and two-factor authentication get tested automatically, without test users and secrets turning into the actual risk

The login process is the entry point to virtually every personalized feature of a Magento application, from order history through saved addresses to the wish list, and at the same time one of the most frequently, silently broken areas of a test suite, since login tests are especially prone to orphaned test users, expired test sessions, and accidentally checked-in credentials. A cleanly built authentication test flow treats login, logout, session timeout, and two-factor authentication as separate, clearly distinguished test cases backed by thoughtful test user management, instead of blending every aspect into a single, cluttered test case.

15 min read Authentication E2E Testing

1. Why authentication deserves its own test area

Authentication differs from most other test areas in that it cuts across virtually every other feature of an application: a broken login flow doesn't just block the login test itself, but potentially every downstream test that assumes a logged-in state too, say tests for order history, the customer account, or saved payment methods, turning a single login flow bug into a cascade of failing tests across the entire test report.

For this reason, it pays to deliberately treat authentication tests as a separate test area running early in the suite, whose outcome immediately indicates whether the basic foundation for all subsequent, login-dependent tests is even sound, instead of only noticing a failed login late, somewhere in the middle of a long test run, after dozens of downstream tests have already failed for the same underlying reason.

2. Login and logout as separate test cases

A solid login test checks not just the successful path with correct credentials, but deliberately also the expected error states: a wrong combination of email address and password, a locked account after too many failed attempts, and the correct behavior for a not-yet-confirmed email account, if the application requires such confirmation.

The logout test, in turn, should check not just that the visible user state correctly switches to logged out, but also that a subsequent, direct navigation to an actually protected page, say order history, reliably redirects to the login page, instead of wrongly still showing protected content, which would indicate an incompletely invalidated session.


test('login with correct credentials leads to the customer account', async ({ page }) => {
  await page.goto('/customer/account/login');
  await page.fill('#email', testUser.email);
  await page.fill('#pass', testUser.password);
  await page.click('#send2');
  await expect(page).toHaveURL(/customer\/account/);
});

test('logout fully invalidates the session', async ({ page }) => {
  await loginAs(page, testUser);
  await page.click('[data-testid="customer-logout"]');
  await page.goto('/sales/order/history');
  await expect(page).toHaveURL(/customer\/account\/login/);
});

3. Deliberately testing session timeout without real waiting

Actually testing a session timeout by really waiting out the configured expiry time is barely viable in any CI pipeline, since session lifetimes in Magento typically span several hours and a test correspondingly can't block for hours, which calls for a different approach to reliably and quickly check the same behavior.

One practical way is to deliberately reduce the session configuration in the test environment to a very short value of a few seconds, so real expiry actually happens within a reasonable test window instead of being artificially simulated. Alternatively, the session cookie can be directly manipulated or removed in the test to produce the same expired state without actually waiting, though this second variant, while faster, is less realistic, since it doesn't run through the real server-side expiry mechanism but only reproduces its symptom.

4. Automatically testing two-factor authentication

Two-factor authentication presents E2E tests with a particular hurdle, since the second factor typically gets delivered over an external channel like SMS or an authenticator app, which an automated test naturally has no direct access to, making a direct reproduction of the real user flow barely possible without extra effort.

In practice, it has proven effective to store a deterministic TOTP secret key in the test user's profile for testing purposes and compute the currently valid one-time code in the test itself, using the same TOTP library real authenticator apps rely on, instead of waiting for a real SMS or push notification. This approach realistically tests the application's actual verification mechanism, without depending on an external, uncontrollable communication channel.


import { authenticator } from 'otplib';

test('login with 2FA accepts a valid TOTP code', async ({ page }) => {
  await loginAs(page, twoFactorTestUser);
  const code = authenticator.generate(twoFactorTestUser.totpSecret);
  await page.fill('[data-testid="totp-code"]', code);
  await page.click('[data-testid="totp-submit"]');
  await expect(page).toHaveURL(/customer\/account/);
});

5. Managing test users across a team without collisions

A common mistake in growing test suites is using a single, permanently shared test user for all login tests across the whole team, causing unpredictable collisions the moment two parallel test runs use the same user at once, say when one test run is currently changing this user's password while a second, parallel test run tries to log in with the old password.

More robust is programmatically creating a fresh, unique test user at the start of every single test run, say directly through the Magento REST API instead of the slower UI, combined with a reliable cleanup routine removing that test user again once the test finishes. This approach not only fully avoids collisions between parallel test runs, but also keeps the test database clean long term, instead of letting hundreds of orphaned test accounts accumulate in the production or staging database over months.

6. Handling tokens in tests without secrets in the repository

For API-driven test setup, say programmatically creating a test user via the REST API before the actual UI test, an admin or integration token is needed that must under no circumstances sit directly in the test code or in a versioned configuration file, since such a token, once accidentally checked in, stays permanently in the Git history even if it later gets removed from the current file state.

The correct place for such credentials is environment variables set exclusively at runtime by the CI pipeline or the local development environment, typically via the given CI platform's secret management, combined with a clear .gitignore rule for all local .env files, so a token never accidentally ends up in the repository through a regular commit.

Likewise, the test user's password itself should never appear as a fixed, recurring value in the source code, but instead get generated randomly at runtime and used exclusively within that test run, so that even an accidentally publicly visible test report never exposes genuinely reusable credentials that could get abused against another system or service.

7. Reliably testing the password reset flow

Despite its apparent simplicity, the password reset flow is one of the most frequently overlooked test areas, even though it gets used regularly in real operation and, if broken, can permanently lock customers out of their own account. A complete test covers both sending the reset email to a known email address and the deliberately non-revealing behavior for an unknown address, since an application shouldn't reveal, for security reasons, whether a given email address actually exists as a customer account.

For automatically checking the actual reset link, usually delivered by email, a locally run mail catcher like Mailhog or Mailpit is a good fit, intercepting outgoing test emails and making them programmatically readable through its own API, instead of depending on a real, publicly reachable mailbox. The test extracts the reset token contained in the email directly from this intercepted message, then navigates to the corresponding reset page and checks that a new password can be successfully set and that the previously used token can't be used again afterward.

8. Parallel logins and multi-device sessions

Shoppers today are frequently logged in on several devices at once, say in a desktop browser plus a mobile view on a smartphone, which is why a realistic test case should check that a login on a second device doesn't automatically invalidate the session on the first device, provided the application is meant to deliberately support several concurrent sessions.

For applications that, for security reasons, deliberately allow only a single active session per user account, the opposite holds: a test should in this case deliberately check that a new login on a second device actually reliably ends the previous session, instead of both sessions silently staying valid in parallel, which would pose a security risk if the first device had meanwhile been lost or stolen.

9. Authentication test cases at a glance

The table below summarizes the presented test cases around authentication.

Test case Goal Note
Login with correct credentials Successful base flow Foundation for all downstream tests
Login with wrong credentials Checking error handling Include lockout behavior after failed attempts
Logout Full session invalidation Check access to a protected page afterward
Session timeout Checking expiry behavior Short test configuration instead of real waiting
2FA login Second factor correctly verified Compute the TOTP code deterministically in the test

Mironsoft

E2E test strategy, CI integration, and stable test suites

Test suites that actually find bugs instead of just blinking red?

We review existing E2E test suites for flakiness, missing test isolation, and inefficient CI runtimes, then build a test strategy that genuinely creates confidence instead of just checking a box.

Test Audit

Systematically uncovering flaky tests, testing pyramid gaps, and coverage blind spots.

CI Optimization

Building parallel execution, retry strategies, and fast feedback loops.

Cypress/Playwright Setup

Setting up robust E2E suites for Magento frontends from the ground up.

10. Summary

Auth Flow Tests: The Essentials at a Glance

Core idea

Treat login, logout, session timeout, and 2FA as separate, clearly distinguished test cases.

Test users

Fresh, unique test user per test run instead of a shared, collision-prone account.

2FA approach

Compute the TOTP code deterministically in the test instead of waiting for external SMS or push.

Secrets

Tokens only through environment variables, never in versioned test code.

11. FAQ: Auth Flow Tests: The Essentials at a Glance

1Why should authentication run early in the test suite?
A broken login flow otherwise causes a cascade of failing downstream tests that wrongly look like separate bugs.
2How do I test a session timeout without waiting for hours?
Through a short test configuration of the expiry time or by directly manipulating the session cookie.
3How can 2FA be automatically tested without real SMS?
Through a deterministic TOTP secret key on the test user and computing the code directly in the test.
4Why is a shared test user problematic?
Parallel test runs can interfere with each other through password changes or lockouts.
5Where should test users get created?
Programmatically via the REST API before the UI test, not by manually clicking through registration.
6Where do admin tokens for test setup belong?
In environment variables of the CI platform, never directly in test code or versioned files.
7What should I check besides the visible logout state?
That a subsequent navigation to protected pages reliably redirects to the login page.
8Does every login error case need its own test?
At least wrong credentials and account lockout after too many failed attempts should be their own test cases.
9How do I avoid orphaned test accounts in the database?
Through a reliable cleanup routine removing every created test user once the test finishes.
10Does this approach also apply to Magento B2B accounts?
Yes, the basic principle of fresh test users, isolated test cases, and secure token handling applies equally.