Auth State Steps

Save once, log in everywhere. The auth steps persist Playwright storageState - the cookies and localStorage of an authenticated browser context - to a JSON file, and replay that snapshot in later scenarios so tests start already signed in. Logging in through the UI adds 1-3 seconds per scenario and is a classic source of flakiness; snapshotting the session once is the single biggest speedup available for suites that touch authenticated pages, and it removes login flakiness from CI/CD lanes entirely.

The recommended workflow is a one-shot setup feature tagged @auth-setup that walks the real login form and ends with I save the auth state to "...". Run it once with npx cucumber-js --tags @auth-setup after every credential rotation. Everyday scenarios then start from Given I restore the auth state from "..." in a Background: block. Keep one snapshot file per role - for example tests/auth/admin.json, tests/auth/editor.json, tests/auth/customer.json - and pick the role each scenario needs.

Restoring an auth state swaps the current browser context for a fresh one built from the saved file, and the webship-js init script (the AJAX/timer/mutation tracker) is re-installed automatically, so BBR smart waits and web-first assertions keep working against the restored session. All three steps accept either I or we as the pronoun.

Quick reference

StepWhat it does
When I save the auth state to "tests/auth/admin.json"Save the current context's cookies + localStorage to a JSON file.
Given I restore the auth state from "tests/auth/admin.json"Open a fresh context with the saved cookies + localStorage.
Given I clear the auth stateClear cookies and localStorage / sessionStorage for the current context.

Steps in detail

When I save the auth state to "<file>"

Saves the current browser context's cookies and localStorage to a JSON file via Playwright's storageState(). Run this after a successful interactive login - typically at the end of a dedicated setup scenario, once the URL confirms you have landed on an authenticated page. The path may be relative (resolved against the project root) or absolute; parent directories are created automatically, and an existing file is overwritten, so re-running the setup feature refreshes the snapshot in place.

Given I am on "/login"
When I fill in "admin@example.com" for "Email"
And I fill in "secret" for "Password"
And I press "Sign in"
And I wait until the URL contains "/dashboard"
Then I save the auth state to "tests/auth/admin.json"

Given I restore the auth state from "<file>"

Restores cookies and localStorage from a previously saved JSON file. The current browser context is closed and a fresh one is opened with the saved storageState, using the same contextOptions from your playwright.config. The webship-js tracker init script is re-installed automatically, so smart waits and count/visibility assertions behave exactly as they would after a real login. If the file does not exist the step fails immediately with a friendly Auth state file not found error - a reminder to run the @auth-setup feature first.

Because the restore opens a blank page, follow it with a navigation step such as And I am on "/dashboard" before making assertions.

Given I restore the auth state from "tests/auth/admin.json"
And I am on "/dashboard"
Then "<#user-list>" should have a count of 5 within 5 seconds

Given I clear the auth state

Clears all cookies for the current context and wipes localStorage and sessionStorage on the current page, anonymizing the session mid-scenario. This is the quickest way to verify access control: perform a logged-in action, clear the state, then confirm the same path now redirects to the login form (or returns a 302) for an anonymous visitor. Storage clearing is best-effort - if the page is not yet on a real URL, cookies are still cleared and the step does not fail.

Given I restore the auth state from "tests/auth/admin.json"
And I am on "/dashboard"
Given I clear the auth state
When I am on "/dashboard"
Then I should see "Sign in"

Complete example

The examples/account.html fixture models a protected page: a small script redirects to the homepage unless a session cookie is present. With a saved snapshot the page loads authenticated; after clearing the auth state the same URL bounces back to the homepage.

@auth
Feature: Auth state save, restore, and clear

  @auth-setup
  Scenario: Save admin auth state once
    Given I am on "/login"
    When I fill in "admin@example.com" for "Email"
    And I fill in "secret" for "Password"
    And I press "Sign in"
    And I wait until the URL contains "/dashboard"
    Then I save the auth state to "tests/auth/admin.json"

  Scenario: Restored session opens the protected account page
    Given I restore the auth state from "tests/auth/admin.json"
    When I am on "/account.html"
    Then I should see "My Account"
    And I should see "Welcome back! You are logged in."

  Scenario: Cleared session is redirected away from the account page
    Given I restore the auth state from "tests/auth/admin.json"
    And I am on "/account.html"
    Given I clear the auth state
    When I am on "/account.html"
    Then I should not see "Welcome back! You are logged in."

Tips

  • One file per role. Keep tests/auth/admin.json, tests/auth/editor.json, tests/auth/customer.json, and restore the role each scenario needs - for example an editor-permissions check: Given I restore the auth state from "tests/auth/editor.json" then Then the "Delete" button should not be visible.
  • Refresh after credential rotation. Re-run npx cucumber-js --tags @auth-setup whenever test passwords or session secrets change; the save step overwrites the snapshot in place.
  • IP / User-Agent bound sessions. Session keys signed against IP or User-Agent will reject the restored cookie. Use a longer, unpinned session lifetime in test environments.
  • CSRF tokens. Tokens embedded in form pages must be re-fetched after a restore - always navigate with Given I am on "/path" after the restore step before submitting forms.
  • Two-factor login. 2FA flows cannot be replayed from a snapshot; keep an environment-specific TOTP bypass behind a feature flag for the setup feature.

Back to all step groups