如何跨测试用例保存localStorage状态,避免重复身份验证?
Persisting LocalStorage Across Test Cases to Skip Repetitive Authentication
Absolutely, you can pull this off—persisting localStorage across test cases to avoid re-running auth flows is totally feasible, especially when API workarounds aren’t an option. Let’s break down how to implement your desired workflow for the most common testing frameworks:
Core Workflow Recap (Matched to Your Request)
First, let’s align with exactly what you want:
- Run a one-time login flow to populate localStorage with session data
- Save that localStorage state to a persistent file
- Load the saved state before every subsequent test to stay authenticated
Cypress (Super Straightforward)
Cypress has built-in tools to handle this with minimal code—here’s how:
- Save auth state once before all tests
// In cypress/support/e2e.js or a dedicated setup spec before(() => { // Only run login if we don't already have saved state cy.readFile('cypress/fixtures/auth-state.json').catch(async () => { cy.visit('/login'); cy.get('#username').type('your-valid-username'); cy.get('#password').type('your-secure-password'); cy.get('button[type="submit"]').click(); // Wait for auth to fully complete (critical!) cy.url().should('include', '/dashboard'); // Save entire localStorage to a fixture file cy.window().then(win => { const authState = {}; for (let i = 0; i < win.localStorage.length; i++) { const key = win.localStorage.key(i); authState[key] = win.localStorage.getItem(key); } cy.writeFile('cypress/fixtures/auth-state.json', authState); }); }); }); - Load state before each test
Pro tip: Use Cypress’sbeforeEach(() => { cy.readFile('cypress/fixtures/auth-state.json').then(authState => { cy.window().then(win => { // Restore every key-value pair from the saved state Object.entries(authState).forEach(([key, value]) => { win.localStorage.setItem(key, value); }); }); // Navigate to the app to use the restored auth state cy.visit('/dashboard'); }); });sessioncommand (v12+) for even cleaner state management—it handles persistence under the hood with less boilerplate!
Playwright
Playwright uses contexts to isolate browser states, but you can serialize localStorage between contexts easily:
- Save auth state in a global setup
// global-setup.js const { chromium } = require('playwright'); const fs = require('fs'); module.exports = async () => { const browser = await chromium.launch(); const context = await browser.newContext(); const page = await context.newPage(); // Run login flow await page.goto('/login'); await page.locator('#username').fill('your-username'); await page.locator('#password').fill('your-password'); await page.locator('button[type="submit"]').click(); await page.waitForURL('/dashboard'); // Extract and save localStorage const localStorage = await page.evaluate(() => { const state = {}; for (let i = 0; i < localStorage.length; i++) { const key = localStorage.key(i); state[key] = localStorage.getItem(key); } return state; }); fs.writeFileSync('./auth-state.json', JSON.stringify(localStorage)); await browser.close(); }; - Load state in your test file
Bonus: Playwright’s// your-test.spec.js const { test } = require('@playwright/test'); const authState = require('./auth-state.json'); test.beforeEach(async ({ page }) => { // Navigate to app first to initialize localStorage await page.goto('/'); // Restore saved state await page.evaluate((state) => { Object.entries(state).forEach(([key, value]) => { localStorage.setItem(key, value); }); }, authState); // Now you're authenticated—navigate to your target page await page.goto('/dashboard'); });storageStatemethod can save/load full browser state (cookies + localStorage) if you need a more comprehensive solution.
Selenium WebDriver
For Selenium, you’ll handle serialization manually using JavaScript execution:
- Save auth state after login
// Java example import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; import com.google.gson.Gson; import java.io.FileWriter; import java.io.IOException; public class AuthUtils { public static void saveAuthState(WebDriver driver) { JavascriptExecutor js = (JavascriptExecutor) driver; // Extract all localStorage items Object localStorage = js.executeScript(""" const state = {}; for (let i = 0; i < localStorage.length; i++) { const key = localStorage.key(i); state[key] = localStorage.getItem(key); } return state; """); // Write to JSON file try (FileWriter writer = new FileWriter("auth-state.json")) { new Gson().toJson(localStorage, writer); } catch (IOException e) { e.printStackTrace(); } } } - Load state before tests
import com.google.gson.Gson; import java.io.FileReader; import java.io.IOException; import java.util.Map; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; public class TestSetup { public static void loadAuthState(WebDriver driver) { try (FileReader reader = new FileReader("auth-state.json")) { Map<String, String> authState = new Gson().fromJson(reader, Map.class); JavascriptExecutor js = (JavascriptExecutor) driver; // Restore each localStorage item for (Map.Entry<String, String> entry : authState.entrySet()) { js.executeScript("localStorage.setItem(arguments[0], arguments[1]);", entry.getKey(), entry.getValue()); } } catch (IOException e) { e.printStackTrace(); } driver.get("/dashboard"); } }
Key Things to Keep in Mind
- Wait for auth completion: Always wait for a reliable signal (like the dashboard URL or an authenticated user element) before saving localStorage—race conditions will break your flow.
- Token expiration: If your auth tokens have short lifespans, add logic to re-run the login setup periodically (e.g., once per test suite run).
- Test isolation: For tests that need unauthenticated users, clear localStorage at the start of those tests to avoid cross-test contamination.
内容的提问来源于stack exchange,提问作者Arash Outadi
相关产品推荐
相关产品推荐

