Playwright v1.61.0 Lands WebAuthn Passkeys, a Real WebStorage API, and Trace-Style Video Modes for the Test Runner

Playwright v1.61.0 Lands WebAuthn Passkeys, a Real WebStorage API, and Trace-Style Video Modes for the Test Runner

lschvn

Playwright v1.61.0 shipped today, June 15, 2026, at 10:05 UTC, about six weeks after v1.60.0 on May 11. It is a feature release with no breaking changes, and three of the new APIs directly address long-standing gaps in how teams test passkey flows, manipulate browser storage, and reason about flaky CI runs. The release also ships the Chromium 149, Firefox 151, and WebKit 26.5 browser channels and adds Ubuntu 26.04 to the supported platform list.

A virtual WebAuthn authenticator for passkey tests

The headline feature is browserContext.credentials, a virtual authenticator that can register passkeys and answer navigator.credentials.create() / navigator.credentials.get() ceremonies in the page. No real hardware key is required, and it works in every browser channel Chromium, Firefox, and WebKit.

The typical flow is to seed a passkey the backend already provisioned for a test user, then have the page's navigator.credentials.get() answer the challenge with that key:

const context = await browser.newContext();

// Seed a passkey your backend provisioned for a test user.
await context.credentials.create('example.com', {
  id: credentialId,
  userHandle,
  privateKey,
  publicKey,
});
await context.credentials.install();

const page = await context.newPage();
await page.goto('https://example.com/login');
// The page's navigator.credentials.get() is answered with the seeded passkey.

The release notes call out an alternative pattern: run a one-shot setup test that registers a passkey through the real UI, read it back with credentials.get(), and seed it into the rest of the suite. That is the right shape for projects that discover passkey support is required to log in and that previously skipped those tests entirely.

The practical consequence is that the explicit resource management patch Bun shipped in 1.3.12 is now a much smaller excuse: testing a passkey-only login used to require a real YubiKey on the CI runner, a custom virtual authenticator driver, or skipping the flow. After 1.61.0, it is a credentials.create call in a beforeEach.

A first-class page.localStorage and page.sessionStorage API

The second piece is the new WebStorage API, exposed as page.localStorage and page.sessionStorage. Reads and writes go directly to the page's storage for the current origin, no page.evaluate round-trip required:

await page.localStorage.setItem('token', 'abc');
const token = await page.localStorage.getItem('token');
const items = await page.sessionStorage.items();

page.evaluate(() => localStorage.setItem('token', 'abc')) still works, but the new API is a first-class protocol command on the same shape Playwright uses for cookies and storage state. That makes it usable on background pages, on service workers, and in tests that just want to assert storage state without bouncing through the JS context.

Network: securityDetails() and serverAddr() on API responses

The new apiResponse.securityDetails() and apiResponse.serverAddr() mirror the browser-side response.securityDetails() and response.serverAddr(). For teams that intercept and replay HTTP via Playwright's request / APIRequestContext API, that is finally a way to assert the negotiated TLS version, the cipher, the certificate subject, and the resolved server address, all in a single test. It is the same kind of capability that drove the esbuild 0.28.1 dev-server path-traversal story for offense; this is the defense side.

Test runner: trace-style video modes and expect.soft.poll

The runner picks up three video modes that bring testOptions.video to parity with testOptions.trace. The new values are 'on-all-retries', 'retain-on-first-failure', and 'retain-on-failure-and-retries'. The video modes table documents which runs are recorded and which are kept in each mode. For CI, 'retain-on-failure' is the obvious win: only broken runs burn disk.

Other runner improvements are small but useful:

  • expect.soft.poll(...) is now supported, the polling form of expect.soft. Failed assertions are recorded against the test, but execution continues, so a dashboard test can assert five loosely-coupled things and report all the failures at the end instead of fixing one, re-running, finding the next, and repeating.
  • fullConfig.argv is a snapshot of process.argv from the runner process, which reporters can read to surface custom arguments passed after the -- separator.
  • fullConfig.failOnFlakyTests mirrors the config option, so reporters can explain why a run marked flaky failed.
  • testInfo.errors now lists each sub-error of an AggregateError as a separate entry, so a multi-failure assertion no longer collapses to a single line in the report.
  • A new -G shorthand for --grep-invert on the CLI.

Browser versions, HAR, and platform support

The release pins Chromium 149.0.7827.55, Mozilla Firefox 151.0, and WebKit 26.5, and is also tested against Google Chrome 149 and Microsoft Edge 149 stable channels. Ubuntu 26.04 is now a supported platform.

HAR and trace recordings now include WebSocket requests. Before 1.61.0, a regression that surfaced only over a WebSocket connection (chat, live cursors, real-time updates, server-sent events that are multiplexed over a single socket) was invisible in the recorded artifact. The trace viewer's network panel and the HAR file now both contain the WebSocket frames, which is what most teams expected from day one.

Smaller touches

  • A new artifactsDir option on browserType.connectOverCDP() controls where traces and downloads go when attaching to an existing browser.
  • A new cursor option on screencast.showActions() controls the cursor decoration rendered for pointer actions.
  • The onFrame callback in screencast.start() now receives a timestamp of when the frame was presented by the browser.

For most teams the upgrade is bun install @playwright/test@latest and a re-install of the browsers. The new APIs are additive, no flag day. The passkey and WebStorage APIs are the parts worth a small migration, since they make the test suite meaningfully more honest about what the production app actually has to handle.

Frequently Asked Questions

Related articles

More coverage with overlapping topics and tags.

esbuild 0.28.1: First Release in Two Months Ships a High-Severity Deno RCE, a Windows Path Traversal, and a `using` Disposal Bug
security

esbuild 0.28.1: First Release in Two Months Ships a High-Severity Deno RCE, a Windows Path Traversal, and a `using` Disposal Bug

esbuild v0.28.1 (June 11, 2026) is the first release since April. It fixes a CVSS 8.1 remote code execution in the Deno API via NPM_CONFIG_REGISTRY, a Windows-only dev-server path traversal, and a minifier bug that silently broke `using` and `await using` resource disposal.
Google's JSIR: An MLIR-Based Intermediate Representation for JavaScript Analysis
security

Google's JSIR: An MLIR-Based Intermediate Representation for JavaScript Analysis

Google has open sourced JSIR, a next-generation JavaScript analysis tool built on MLIR. It supports both high-level dataflow analysis and lossless source-to-source transformation, used internally for Hermes bytecode decompilation and AI-powered JavaScript deobfuscation.
Vite 8.1 Beta Lands Direct `.wasm` Imports, `build.chunkImportMap`, and a `server.hmr` → `server.ws` Rename
tooling

Vite 8.1 Beta Lands Direct `.wasm` Imports, `build.chunkImportMap`, and a `server.hmr` → `server.ws` Rename

Vite 8.1.0-beta.0 (June 15, 2026) is the first beta of the 8.1 line. It ships the WASM ESM Integration standard as direct .wasm imports, a build.chunkImportMap option that uses import maps to improve chunk cache hit rates, integration with Vite Task for zero-config build caching, support for lightningcss plugin dependencies, and a breaking rename of every `server.hmr` option to `server.ws`.

Comments

Log in Log in to join the conversation.

No comments yet. Be the first to share your thoughts.