Browser Contexts & Authentication
Reuse authenticated sessions across tests with storageState and manage multi-user scenarios using independent browser contexts.
What Is a Browser Context?
A browser context is an isolated browser session — like a private/incognito window — with its own cookies, localStorage, sessionStorage, and cache. Multiple contexts can run in the same browser process, sharing process overhead but fully isolated from each other. This makes contexts the perfect unit for multi-user testing: spin up one context per user role, each with its own session.
Saving and Reusing Authentication
Performing a full login flow before every test is slow and wasteful. A better approach is to log in once in a global setup script, save the resulting cookies and localStorage to a storageState.json file, and then load that file into the browser context for every subsequent test. This means the login page is visited only once per test run, regardless of how many tests need an authenticated session.
Multi-User Testing
Some features require multiple simultaneous users — for example, a live collaboration feature where one user makes a change and another sees it in real time. Create two browser contexts from the same browser, each loaded with a different storageState (one for Admin, one for a standard User). Drive both contexts in the same test to verify real-time interaction.
import { chromium, type FullConfig } from '@playwright/test';
async function globalSetup(config: FullConfig) {
const browser = await chromium.launch();
const page = await browser.newPage();
// Log in once and save the session
await page.goto('http://localhost:3000/login');
await page.getByLabel('Email').fill('admin@example.com');
await page.getByLabel('Password').fill('adminpass');
await page.getByRole('button', { name: 'Sign in' }).click();
await page.waitForURL('/dashboard');
// Persist cookies + localStorage
await page.context().storageState({ path: './auth/admin.json' });
await browser.close();
}
export default globalSetup;
import { test, expect } from '@playwright/test';
test('admin and user see different dashboards', async ({ browser }) => {
// Admin context — pre-authenticated
const adminCtx = await browser.newContext({
storageState: './auth/admin.json',
});
const adminPage = await adminCtx.newPage();
await adminPage.goto('/dashboard');
await expect(adminPage.getByText('Admin Panel')).toBeVisible();
// User context — different session
const userCtx = await browser.newContext({
storageState: './auth/user.json',
});
const userPage = await userCtx.newPage();
await userPage.goto('/dashboard');
await expect(userPage.getByText('Admin Panel')).not.toBeVisible();
await adminCtx.close();
await userCtx.close();
});
import com.microsoft.playwright.*;
import java.nio.file.Paths;
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
class AuthContextTest {
static void saveAuthState(Browser browser) {
BrowserContext ctx = browser.newContext();
Page page = ctx.newPage();
page.navigate("http://localhost:3000/login");
page.getByLabel("Email").fill("admin@example.com");
page.getByLabel("Password").fill("adminpass");
page.getByRole(AriaRole.BUTTON,
new Page.GetByRoleOptions().setName("Sign in")).click();
ctx.storageState(new BrowserContext.StorageStateOptions()
.setPath(Paths.get("auth/admin.json")));
ctx.close();
}
void testWithSavedAuth(Browser browser) {
BrowserContext ctx = browser.newContext(
new Browser.NewContextOptions()
.setStorageStatePath(Paths.get("auth/admin.json"))
);
Page page = ctx.newPage();
page.navigate("/dashboard");
assertThat(page.getByText("Admin Panel")).isVisible();
ctx.close();
}
}
# global_setup.py — run once before all tests
from playwright.sync_api import sync_playwright
from pathlib import Path
def save_admin_auth():
with sync_playwright() as p:
browser = p.chromium.launch()
context = browser.new_context()
page = context.new_page()
page.goto("http://localhost:3000/login")
page.get_by_label("Email").fill("admin@example.com")
page.get_by_label("Password").fill("adminpass")
page.get_by_role("button", name="Sign in").click()
page.wait_for_url("/dashboard")
Path("auth").mkdir(exist_ok=True)
context.storage_state(path="auth/admin.json")
browser.close()
if __name__ == "__main__":
save_admin_auth()
import pytest
from playwright.sync_api import BrowserContext, Page
@pytest.fixture
def admin_context(browser) -> BrowserContext:
ctx = browser.new_context(storage_state="auth/admin.json")
yield ctx
ctx.close()
@pytest.fixture
def admin_page(admin_context: BrowserContext) -> Page:
return admin_context.new_page()
Written by PV
© 2026 All Rights Reserved