WebAuthn changes the shape of login testing in a way that many UI automation suites still handle awkwardly. The old model was simple: fill username, fill password, submit, maybe solve an OTP step, then assert a session cookie exists. Passkeys, security keys, platform authenticators, and recovery flows add a different set of moving parts, browser APIs, device state, OS-level prompts, and conditional branching that may or may not be exposed to automation at all.

That is why Playwright vs Selenium WebAuthn testing is not just a question of which framework is newer. The real question is which stack lets a team validate secure login flows with enough control over prompts, enough realism around browser behavior, and enough maintainability to keep those tests useful as authentication evolves. For some teams, the answer is a code-based framework. For others, the stronger choice is a managed platform such as Endtest, especially when the requirement is repeatable secure-login coverage without building and maintaining a custom WebAuthn harness.

What makes WebAuthn testing different from ordinary login automation

WebAuthn, the W3C standard behind passkeys and many hardware-backed sign-ins, is not just another form field. The test surface includes at least four layers:

  1. The browser’s JavaScript WebAuthn APIs.
  2. The browser UI that may show a prompt for the authenticator.
  3. The operating system or device state behind that prompt.
  4. The server-side registration and assertion logic that verifies the credential.

That means a test can fail for reasons that are invisible in a normal DOM trace. For example:

  • The browser accepts the page call to navigator.credentials.get(), but the prompt never appears because the relying party ID is wrong.
  • The prompt appears, but the authenticator is not available on that execution host.
  • The authentication challenge succeeds locally, but the backend rejects the assertion because the credential metadata or attestation expectations differ.
  • Recovery flows, such as password fallback, backup codes, email link fallback, or account recovery, are not mutually equivalent and need separate coverage.

A useful rule of thumb: if the test depends on state outside the DOM, treat it as a systems test, not just a UI test.

That distinction matters when comparing frameworks.

The core difference: browser control versus authentication control

Playwright and Selenium both automate browsers. Neither one is, by itself, a complete WebAuthn test solution. The practical difference is in how much browser-level control they expose, how easy it is to simulate authenticator behavior, and how much setup the team must own.

Playwright

Playwright is usually the first framework teams consider when they need modern browser automation with strong waiting semantics and direct APIs for browser contexts. In WebAuthn testing, its appeal is that it provides better primitives for mocking and controlled browser state than older UI-only approaches. Teams can create isolated browser contexts, intercept requests, and in some scenarios emulate credential flows more predictably than with a raw WebDriver setup.

For passkey testing, that matters because the test often needs:

  • A predictable authenticated browser session.
  • A way to inject or control credentials at the browser context level.
  • Deterministic handling of prompts and conditional UI.
  • Strong synchronization so the test waits for the actual authentication event rather than a timeout guess.

The limitation is that Playwright still runs inside the browser automation layer. It is not a magic authenticator emulator. When the flow crosses into OS prompts or device-bound authenticators, you may need test doubles, backend hooks, or special test accounts. That is where implementation effort grows quickly.

Selenium

Selenium remains the broadest compatibility option and still matters for teams with large existing suites, mixed language stacks, or enterprise browser requirements. For WebAuthn, Selenium’s advantage is not that it is especially elegant. It is that many organizations already have the infrastructure, driver management, language bindings, and CI patterns needed to extend existing login coverage.

The tradeoff is that Selenium is lower level for this use case. Teams often need to layer more logic around waits, browser capabilities, and environmental assumptions. WebAuthn is already stateful and prompt-driven, so adding lower-level WebDriver orchestration can increase the chance of brittle tests if the team does not create a carefully isolated harness.

What each stack handles well

Where Playwright tends to be stronger

Playwright is usually the better fit when a team needs to test the browser-side behavior of passkeys and secure login flows with tight control over state and timing. Typical strengths include:

  • Better synchronization primitives, which reduce false negatives in prompt-heavy flows.
  • Easier test isolation through browser contexts.
  • More ergonomic request interception and API setup for creating the right preconditions.
  • A clearer path to writing helpers around auth setup, such as reusable fixtures for logged-in state or credential registration preconditions.

A practical example is a test suite that needs to validate:

  • sign-up with passkey enrollment,
  • sign-in with a previously registered passkey,
  • fallback to password when no credential is available,
  • recovery when the browser refuses the WebAuthn prompt.

Playwright is often easier to structure for that sequence because the same test runner can manage API setup, browser state, and DOM assertions in one place.

Where Selenium tends to be stronger

Selenium is often strongest in organizations that already have mature cross-browser coverage and want to extend an established pattern rather than introduce a new one. This is particularly true when:

  • the suite already spans Java, Python, or C#,
  • the team has centralized WebDriver expertise,
  • there is existing grid infrastructure,
  • browser coverage includes older or more specialized environments.

For secure login recovery, Selenium can still be perfectly serviceable if the team has built deterministic helpers for the non-DOM parts of the flow. For example, if recovery is triggered by backend account state rather than a browser prompt, Selenium’s job is mostly to drive the visible UI and confirm the right branch was taken.

The common failure mode is assuming Selenium’s general-purpose browser automation is enough to solve WebAuthn by itself. It is not. It needs explicit harness design, and that harness is often where maintenance cost accumulates.

Passkey testing is less about clicking than about state modeling

A passkey flow often has at least three distinct states that deserve separate tests:

  1. No passkey enrolled.
  2. Passkey enrolled but unavailable in the current browser or device state.
  3. Passkey enrolled and available, with prompt success.

Each state can lead to a different branch in the product. If the application offers password fallback, email recovery, or device-based sign-in fallback, the tests should assert which branch is shown and what security assumptions hold.

A good suite does not just test the happy path. It verifies whether recovery is intentionally constrained. For example:

  • Are backup codes one-time use?
  • Does the application re-prompt for step-up verification after a risky action?
  • Does the recovery flow invalidate the old device credential?
  • Is passkey registration blocked after account compromise signals?

These are product decisions, not framework decisions, but the framework determines how cheaply they can be verified.

Device prompts are the hardest part

The real pain point in WebAuthn automation is the prompt itself. Depending on the browser and OS, the user may see:

  • a native passkey chooser,
  • a biometric prompt,
  • a security key dialog,
  • a device verification sheet,
  • a conditional mediation flow that appears only after focus or click behavior.

That means tests can fail because of environment mismatch rather than product defects.

Common failure modes to plan for

  • The test host does not have an available authenticator, so the prompt cannot complete.
  • A headless browser does not surface the same authentication UI as a headed browser.
  • WebKit in a container is not equivalent to real Safari behavior.
  • The browser version changes prompt timing or UI text, breaking brittle locators.
  • The application caches auth state, so the next test does not start from a clean session.

This is one reason real-browser coverage matters. If the passkey experience must be validated on Safari or on specific macOS behavior, you want execution on actual browsers rather than approximations. Endtest’s cross-browser testing on real browsers and real macOS hardware is relevant here because prompt behavior is often browser and platform specific, not just DOM specific.

Secure login recovery needs separate test design

Secure login recovery is not one thing. A team might need to test several distinct fallback paths:

  • password fallback after passkey enrollment,
  • email or SMS fallback when a device is missing,
  • recovery codes after account lockout,
  • admin-assisted recovery for enterprise users,
  • re-enrollment after device rotation.

Each recovery path has different risk characteristics. A test should verify both functionality and security policy.

For example, a recovery test should ask:

  • Does the fallback path weaken account assurance more than intended?
  • Does the app reveal whether a passkey exists before a user is verified?
  • Does the recovery step produce a session that requires step-up auth before sensitive operations?

This is where brittle automation becomes expensive. If your framework requires custom harness code for every recovery branch, coverage tends to drift. If your team is spending more time keeping the harness alive than checking security behavior, the framework is no longer paying for itself.

A small Playwright example for authenticated setup

Playwright is often used to combine API setup with UI verification, which is useful when you need a known account state before entering the browser prompt.

import { test, expect } from '@playwright/test';
test('shows passkey sign-in option', async ({ page, request }) => {
  await request.post('/api/test/users', {
    data: { email: 'qa@example.com', passkeyEnabled: true }
  });

await page.goto(‘/login’); await expect(page.getByText(‘Sign in with passkey’)).toBeVisible(); });

That example does not solve the prompt problem. It solves the precondition problem, which is often the more stable part of the test. The authenticator behavior still needs either a controlled test environment or a platform that handles the workflow more directly.

A Selenium example for recovery branch verification

Selenium is still useful when the important assertion is the visible recovery branch, not the authenticator itself.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

browser = webdriver.Chrome() browser.get(‘https://example.test/login’)

browser.find_element(By.CSS_SELECTOR, ‘[data-testid=”use-password-fallback”]’).click() WebDriverWait(browser, 10).until( EC.visibility_of_element_located((By.CSS_SELECTOR, ‘[data-testid=”password-form”]’)) )

This works if the browser is just navigating the branch. It becomes much less satisfying if you need to emulate the full passkey interaction in a reliable, cross-browser way.

How to evaluate reliability across browsers

The right evaluation criteria are narrower than generic end-to-end automation criteria. For WebAuthn testing, ask whether the stack can consistently handle:

  • real Chrome, Firefox, Safari, and Edge where relevant,
  • clean browser state between runs,
  • visible prompt timing differences,
  • device and OS-dependent branches,
  • stable recovery-path assertions,
  • CI execution without ad hoc local setup.

A code-based framework can meet these requirements, but it usually does so only after the team builds additional infrastructure. That infrastructure can include fixtures, helper libraries, mock authenticators, browser policies, environment setup scripts, and custom cleanup logic.

By contrast, a managed platform can reduce the amount of custom harness work. This is where Endtest’s no-code testing approach is a credible complement for teams that need repeatable secure-login coverage without writing and maintaining WebAuthn-specific framework code. Endtest’s agentic AI approach is especially relevant when the workflow needs to stay readable, editable, and reviewable by more than one role on the team. Instead of maintaining a large amount of custom browser code, teams can keep tests as human-readable steps and focus engineering effort on the authentication behavior itself.

Where Endtest fits in this comparison

Endtest is not the right answer for every team, but it addresses a real gap in this area. WebAuthn and secure login testing often fail because the team owns too much infrastructure: browser orchestration, driver management, environment setup, and prompt handling. Endtest reduces that burden by providing a managed platform for browser execution and Endtest vs Playwright and Endtest vs Selenium are useful comparisons if your team is deciding whether to keep investing in framework code or move part of the test surface into a maintained platform.

The practical advantage is not just less code. It is less ownership concentration. When passkey and recovery tests are represented as editable, platform-native steps instead of tens of thousands of lines of framework code, more people can review them, more people can maintain them, and the test suite is less dependent on one framework specialist. That matters when login policy changes often or when security and QA teams need to collaborate quickly.

Decision criteria by team shape

Choose Playwright when

  • you want modern browser automation with strong synchronization,
  • your team is comfortable in TypeScript or Python,
  • the auth flow needs API setup plus browser verification,
  • you can invest in custom helpers for WebAuthn edge cases,
  • your browser matrix is mostly Chromium, Firefox, and WebKit, with an acceptance that WebKit is not the same as real Safari.

Choose Selenium when

  • you already have a large Selenium estate,
  • your organization standardizes on WebDriver across multiple languages,
  • you need continuity with existing CI and grid infrastructure,
  • your priority is extending mature browser coverage rather than redesigning the suite,
  • the WebAuthn flow is only one part of a larger regression pack.

Choose a managed platform like Endtest when

  • the team wants repeatable secure-login coverage without owning a browser harness,
  • non-developers should be able to review or maintain the tests,
  • you need real-browser cross-coverage with less setup overhead,
  • the recovery matrix changes frequently,
  • you want a platform that keeps the test representation human-readable and maintainable.

A practical hybrid strategy often works best

For many teams, the best answer is not a single stack. It is a split strategy:

  • Use Playwright or Selenium for lower-level developer-owned checks, API setup, and focused assertions around auth logic.
  • Use Endtest for broader secure-login coverage, especially across browser combinations and recovery branches that should be visible to QA, product, or security teams.
  • Keep the most brittle authenticator-specific flows out of the codebase unless there is a clear reason to own them there.

That hybrid approach is useful because passkey support is still evolving across browsers and devices. A login test suite should be resilient to browser changes, but it should also be cheap to update when product policy changes. Human-readable automation helps here because security flows are often reviewed outside engineering, and the test artifact should support that review.

How to keep these tests from rotting

Whatever stack you choose, these practices matter more than the framework brand:

  1. Separate enrollment tests from sign-in tests.
  2. Isolate recovery flows from normal login.
  3. Use dedicated test accounts and reset them deterministically.
  4. Prefer data setup through API or fixtures rather than UI if the setup is not the thing being tested.
  5. Avoid asserting on exact prompt text unless the browser text is the product requirement.
  6. Keep fallback paths explicit, because implicit fallbacks are where security regressions hide.

A useful CI rule is to run a small smoke subset on every commit, then run the browser matrix on a schedule or before release. WebAuthn flows tend to be slower and more environment-sensitive than ordinary navigation tests, so forcing them into the same cadence as basic unit checks usually increases noise.

name: auth-smoke
on:
  push:
  schedule:
    - cron: '0 3 * * *'
jobs:
  playwright-auth:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npx playwright test auth-smoke

Final judgment

For Playwright vs Selenium WebAuthn testing, the most honest answer is that Playwright is usually the stronger code-based choice for new work because it gives teams better control over browser state, synchronization, and test structure. Selenium remains a valid option when compatibility, language diversity, or existing investment matter more than elegance.

But neither framework removes the hardest part of WebAuthn, which is not clicking the login button. It is modeling device state, prompt behavior, and secure recovery branches in a way that stays trustworthy over time. If your team wants to avoid building and maintaining a custom WebAuthn harness, Endtest is worth serious consideration, especially when the goal is repeatable secure-login coverage that more than one person can understand and maintain.

In practice, the right choice is the one that lets your team verify authentication behavior with the least hidden infrastructure and the fewest brittle assumptions. For many organizations, that means a code-based framework for deep engineering-owned checks, plus a managed no-code layer for the cross-browser secure-login coverage that needs to stay visible, stable, and easy to change.