diff --git a/dotnet/docs/api/class-page.mdx b/dotnet/docs/api/class-page.mdx index 0075e64141..08e3980e78 100644 --- a/dotnet/docs/api/class-page.mdx +++ b/dotnet/docs/api/class-page.mdx @@ -1214,6 +1214,11 @@ Returns the main resource response. In case of multiple redirects, the navigatio Navigate to the previous page in history. +:::warning + +**Testing Back/Forward Cache (BFCache) is not supported.** By default, Playwright disables the Back/Forward Cache across all browsers. Even if explicitly enabled, Playwright's internal state relies on network-level navigation events. Because BFCache restores unfreeze the DOM without firing these events, using `page.goBack()` or `page.goForward()` to trigger a BFCache restore will result in timeouts and a desynchronized `Page` state. +::: + **Usage** ```csharp @@ -1246,6 +1251,11 @@ Returns the main resource response. In case of multiple redirects, the navigatio Navigate to the next page in history. +:::warning + +**Testing Back/Forward Cache (BFCache) is not supported.** By default, Playwright disables the Back/Forward Cache across all browsers. Even if explicitly enabled, Playwright's internal state relies on network-level navigation events. Because BFCache restores unfreeze the DOM without firing these events, using `page.goBack()` or `page.goForward()` to trigger a BFCache restore will result in timeouts and a desynchronized `Page` state. +::: + **Usage** ```csharp diff --git a/dotnet/docs/navigations.mdx b/dotnet/docs/navigations.mdx index 0d44a3c7aa..829d099812 100644 --- a/dotnet/docs/navigations.mdx +++ b/dotnet/docs/navigations.mdx @@ -60,6 +60,16 @@ await page.GetByText("Click me").ClickAsync(); await page.WaitForURL("**/login"); ``` +## Back/Forward Cache (BFCache) + +Modern browsers utilize a Back/Forward Cache (BFCache) to instantly load a page when a user navigates back or forward. This is achieved by freezing the page's DOM and JavaScript heap in memory, and thawing it upon return. + +By default, Playwright disables the BFCache across all browsers to ensure consistent, clean testing environments. + +Even if you explicitly enable BFCache, **testing BFCache restorations is not supported**. Because a BFCache restore skips the network fetch phase, the browser does not fire standard navigation lifecycle events (such as `commit`, `domcontentloaded`, or `load`). Playwright's internal `Page` state heavily relies on these network-level events to stay synchronized. + +Consequently, triggering a BFCache restore (e.g., via `page.goBack()`) will bypass Playwright's lifecycle tracking, resulting in timeouts and a completely desynchronized `Page` object where subsequent interactions will fail. + ## Navigation events Playwright splits the process of showing a new document in a page into **navigation** and **loading**. diff --git a/java/docs/api/class-page.mdx b/java/docs/api/class-page.mdx index 937d0287e3..d1ad77c016 100644 --- a/java/docs/api/class-page.mdx +++ b/java/docs/api/class-page.mdx @@ -1218,6 +1218,11 @@ Returns the main resource response. In case of multiple redirects, the navigatio Navigate to the previous page in history. +:::warning + +**Testing Back/Forward Cache (BFCache) is not supported.** By default, Playwright disables the Back/Forward Cache across all browsers. Even if explicitly enabled, Playwright's internal state relies on network-level navigation events. Because BFCache restores unfreeze the DOM without firing these events, using `page.goBack()` or `page.goForward()` to trigger a BFCache restore will result in timeouts and a desynchronized `Page` state. +::: + **Usage** ```java @@ -1251,6 +1256,11 @@ Returns the main resource response. In case of multiple redirects, the navigatio Navigate to the next page in history. +:::warning + +**Testing Back/Forward Cache (BFCache) is not supported.** By default, Playwright disables the Back/Forward Cache across all browsers. Even if explicitly enabled, Playwright's internal state relies on network-level navigation events. Because BFCache restores unfreeze the DOM without firing these events, using `page.goBack()` or `page.goForward()` to trigger a BFCache restore will result in timeouts and a desynchronized `Page` state. +::: + **Usage** ```java diff --git a/java/docs/navigations.mdx b/java/docs/navigations.mdx index ca04efa537..5a7f3a90fd 100644 --- a/java/docs/navigations.mdx +++ b/java/docs/navigations.mdx @@ -60,6 +60,16 @@ page.getByText("Click me").click(); page.waitForURL("**/login"); ``` +## Back/Forward Cache (BFCache) + +Modern browsers utilize a Back/Forward Cache (BFCache) to instantly load a page when a user navigates back or forward. This is achieved by freezing the page's DOM and JavaScript heap in memory, and thawing it upon return. + +By default, Playwright disables the BFCache across all browsers to ensure consistent, clean testing environments. + +Even if you explicitly enable BFCache, **testing BFCache restorations is not supported**. Because a BFCache restore skips the network fetch phase, the browser does not fire standard navigation lifecycle events (such as `commit`, `domcontentloaded`, or `load`). Playwright's internal `Page` state heavily relies on these network-level events to stay synchronized. + +Consequently, triggering a BFCache restore (e.g., via `page.goBack()`) will bypass Playwright's lifecycle tracking, resulting in timeouts and a completely desynchronized `Page` object where subsequent interactions will fail. + ## Navigation events Playwright splits the process of showing a new document in a page into **navigation** and **loading**. diff --git a/nodejs/docs/api/class-browsercontext.mdx b/nodejs/docs/api/class-browsercontext.mdx index bda17d41ce..b3c6646892 100644 --- a/nodejs/docs/api/class-browsercontext.mdx +++ b/nodejs/docs/api/class-browsercontext.mdx @@ -121,6 +121,10 @@ The order of evaluation of multiple scripts installed via [browserContext.addIni - `arg` [Serializable] *(optional)*# Optional argument to pass to [script](/api/class-browsercontext.mdx#browser-context-add-init-script-option-script) (only supported when passing a function). +- `options` [Object] *(optional)* + - `exposeFunctions` [boolean] *(optional)* Added in: v1.62# + + When set to `true`, functions passed inside [arg](/api/class-browsercontext.mdx#browser-context-add-init-script-option-arg) are exposed in the page and can be called from the init script. Calling one returns a [Promise] of its result. Under the hood, each function is exposed via [page.exposeFunction()](/api/class-page.mdx#page-expose-function), so it is technically accessible from all frames and worlds of the page. Unlike functions passed to [page.evaluate()](/api/class-page.mdx#page-evaluate), functions passed to an init script are exposed in every new document, so they survive navigations. Defaults to `false`, in which case functions are not serializable and are silently dropped. **Returns** - [Promise]<[Disposable]># diff --git a/nodejs/docs/api/class-cdpsession.mdx b/nodejs/docs/api/class-cdpsession.mdx index 9ea3409d98..5f114a4883 100644 --- a/nodejs/docs/api/class-cdpsession.mdx +++ b/nodejs/docs/api/class-cdpsession.mdx @@ -100,8 +100,8 @@ Emitted for every CDP event received from the session. Allows subscribing to all **Usage** ```js -session.on('event', ({ name, params }) => { - console.log(`CDP event: ${name}`, params); +session.on('event', ({ method, params }) => { + console.log(`CDP event: ${method}`, params); }); ``` diff --git a/nodejs/docs/api/class-fixtures.mdx b/nodejs/docs/api/class-fixtures.mdx index 2a73900a9d..85681cd365 100644 --- a/nodejs/docs/api/class-fixtures.mdx +++ b/nodejs/docs/api/class-fixtures.mdx @@ -24,6 +24,54 @@ Given the test above, Playwright Test will set up the `page` fixture before runn Playwright Test comes with builtin fixtures listed below, and you can add your own fixtures as well. Playwright Test also [provides options][TestOptions] to configure [fixtures.browser](/api/class-fixtures.mdx#fixtures-browser), [fixtures.context](/api/class-fixtures.mdx#fixtures-context) and [fixtures.page](/api/class-fixtures.mdx#fixtures-page). +--- + +## Methods + +### mount {/* #fixtures-mount */} + +Added in: v1.62fixtures.mount + +Mounts a component story and returns a [Locator] pointing to the root element the story was rendered into. Scope your queries from the returned locator: `component.getByRole('button')`, not `page.getByRole('button')`. + +A **story** is a small wrapper component that embeds the component under test in one specific scenario: hard-coded props, mock data, providers, recorded callbacks. Stories are rendered by a **gallery** page that you implement and serve at [testOptions.baseURL](/api/class-testoptions.mdx#test-options-base-url). The gallery exposes `window.mount(params)` and `window.unmount()` functions that render a story into its root element. Each call to [fixtures.mount()](/api/class-fixtures.mdx#fixtures-mount) navigates to [testOptions.baseURL](/api/class-testoptions.mdx#test-options-base-url) and calls `window.mount()` with the story id and props, so tests are fully isolated from each other. + +**Usage** + +```js +test('click should expand', async ({ mount }) => { + const component = await mount('components/Expandable/Stateful'); + await component.getByRole('button').click(); + await expect(component.getByTestId('expanded')).toHaveValue('true'); +}); +``` + +Pass the story type as a template argument to type-check the props: + +```js +import type { WithTitle } from './Button.story'; + +test('renders the title', async ({ mount }) => { + const component = await mount('Button/WithTitle', { title: 'Hello' }); + await expect(component).toContainText('Hello'); +}); +``` + +The returned locator is augmented with two methods: +* `update(props)` - re-renders the same story with new props without remounting, preserving component state; +* `unmount()` - unmounts the story. + +**Arguments** +- `storyId` [string]# + + Identifier of the story to mount, as resolved by the gallery page. Conventionally, the story file path plus the exported story name, for example `'components/Button/Primary'`. +- `props` [Object] *(optional)*# + + Optional plain, serializable props passed to the story. + +**Returns** +- [Locator]# + --- ## Properties diff --git a/nodejs/docs/api/class-frame.mdx b/nodejs/docs/api/class-frame.mdx index ca029255b8..7484809317 100644 --- a/nodejs/docs/api/class-frame.mdx +++ b/nodejs/docs/api/class-frame.mdx @@ -253,7 +253,7 @@ await bodyHandle.dispose(); - `options` [Object] *(optional)* - `exposeFunctions` [boolean] *(optional)* Added in: v1.62# - When set to `true`, functions passed inside [arg](/api/class-frame.mdx#frame-evaluate-option-arg) are exposed in the page and can be called from the page function. Calling one returns a [Promise] of its result. The page-side functions are scoped to the execution context they were passed to and disappear when the page navigates. Defaults to `false`, in which case functions are not serializable and passing one throws an error, as before. + When set to `true`, functions passed inside [arg](/api/class-frame.mdx#frame-evaluate-option-arg) are exposed in the page and can be called from the page function. Calling one returns a [Promise] of its result. Under the hood, each function is exposed via [page.exposeFunction()](/api/class-page.mdx#page-expose-function), so it is technically accessible from all frames and worlds of the page. Exposed functions are cleared upon the top-level navigation. Defaults to `false`, in which case functions are not serializable and passing one throws an error. **Returns** - [Promise]<[Serializable]># @@ -304,7 +304,7 @@ await resultHandle.dispose(); - `options` [Object] *(optional)* - `exposeFunctions` [boolean] *(optional)* Added in: v1.62# - When set to `true`, functions passed inside [arg](/api/class-frame.mdx#frame-evaluate-handle-option-arg) are exposed in the page and can be called from the page function. Calling one returns a [Promise] of its result. The page-side functions are scoped to the execution context they were passed to and disappear when the page navigates. Defaults to `false`, in which case functions are not serializable and passing one throws an error, as before. + When set to `true`, functions passed inside [arg](/api/class-frame.mdx#frame-evaluate-handle-option-arg) are exposed in the page and can be called from the page function. Calling one returns a [Promise] of its result. Under the hood, each function is exposed via [page.exposeFunction()](/api/class-page.mdx#page-expose-function), so it is technically accessible from all frames and worlds of the page. Exposed functions are cleared upon the top-level navigation. Defaults to `false`, in which case functions are not serializable and passing one throws an error. **Returns** - [Promise]<[JSHandle]># diff --git a/nodejs/docs/api/class-jshandle.mdx b/nodejs/docs/api/class-jshandle.mdx index abbff64d2b..2672c8dd61 100644 --- a/nodejs/docs/api/class-jshandle.mdx +++ b/nodejs/docs/api/class-jshandle.mdx @@ -84,7 +84,7 @@ expect(await tweetHandle.evaluate(node => node.innerText)).toBe('10 retweets'); - `options` [Object] *(optional)* - `exposeFunctions` [boolean] *(optional)* Added in: v1.62# - When set to `true`, functions passed inside [arg](/api/class-jshandle.mdx#js-handle-evaluate-option-arg) are exposed in the page and can be called from the page function. Calling one returns a [Promise] of its result. The page-side functions are scoped to the execution context they were passed to and disappear when the page navigates. Defaults to `false`, in which case functions are not serializable and passing one throws an error, as before. + When set to `true`, functions passed inside [arg](/api/class-jshandle.mdx#js-handle-evaluate-option-arg) are exposed in the page and can be called from the page function. Calling one returns a [Promise] of its result. Under the hood, each function is exposed via [page.exposeFunction()](/api/class-page.mdx#page-expose-function), so it is technically accessible from all frames and worlds of the page. Exposed functions are cleared upon the top-level navigation. Defaults to `false`, in which case functions are not serializable and passing one throws an error. **Returns** - [Promise]<[Serializable]># @@ -122,7 +122,7 @@ await jsHandle.evaluateHandle(pageFunction, arg, options); - `options` [Object] *(optional)* - `exposeFunctions` [boolean] *(optional)* Added in: v1.62# - When set to `true`, functions passed inside [arg](/api/class-jshandle.mdx#js-handle-evaluate-handle-option-arg) are exposed in the page and can be called from the page function. Calling one returns a [Promise] of its result. The page-side functions are scoped to the execution context they were passed to and disappear when the page navigates. Defaults to `false`, in which case functions are not serializable and passing one throws an error, as before. + When set to `true`, functions passed inside [arg](/api/class-jshandle.mdx#js-handle-evaluate-handle-option-arg) are exposed in the page and can be called from the page function. Calling one returns a [Promise] of its result. Under the hood, each function is exposed via [page.exposeFunction()](/api/class-page.mdx#page-expose-function), so it is technically accessible from all frames and worlds of the page. Exposed functions are cleared upon the top-level navigation. Defaults to `false`, in which case functions are not serializable and passing one throws an error. **Returns** - [Promise]<[JSHandle]># diff --git a/nodejs/docs/api/class-locator.mdx b/nodejs/docs/api/class-locator.mdx index 1252521b5e..b74c62456a 100644 --- a/nodejs/docs/api/class-locator.mdx +++ b/nodejs/docs/api/class-locator.mdx @@ -849,7 +849,7 @@ console.log(result); // prints "myId text 56" - `options` [Object] *(optional)* - `exposeFunctions` [boolean] *(optional)* Added in: v1.62# - When set to `true`, functions passed inside [arg](/api/class-locator.mdx#locator-evaluate-option-arg) are exposed in the page and can be called from the page function. Calling one returns a [Promise] of its result. The page-side functions are scoped to the execution context they were passed to and disappear when the page navigates. Defaults to `false`, in which case functions are not serializable and passing one throws an error, as before. + When set to `true`, functions passed inside [arg](/api/class-locator.mdx#locator-evaluate-option-arg) are exposed in the page and can be called from the page function. Calling one returns a [Promise] of its result. Under the hood, each function is exposed via [page.exposeFunction()](/api/class-page.mdx#page-expose-function), so it is technically accessible from all frames and worlds of the page. Exposed functions are cleared upon the top-level navigation. Defaults to `false`, in which case functions are not serializable and passing one throws an error. - `signal` [AbortSignal] *(optional)* Added in: v1.62# Allows to cancel the operation using an [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal). If the signal is aborted, the operation will be aborted and throw an error. Note that providing a signal does not disable the default timeout, which can be changed using [browserContext.setDefaultTimeout()](/api/class-browsercontext.mdx#browser-context-set-default-timeout) or [page.setDefaultTimeout()](/api/class-page.mdx#page-set-default-timeout); pass `timeout: 0` to disable the timeout entirely. @@ -927,7 +927,7 @@ await locator.evaluateHandle(pageFunction, arg, options); - `options` [Object] *(optional)* - `exposeFunctions` [boolean] *(optional)* Added in: v1.62# - When set to `true`, functions passed inside [arg](/api/class-locator.mdx#locator-evaluate-handle-option-arg) are exposed in the page and can be called from the page function. Calling one returns a [Promise] of its result. The page-side functions are scoped to the execution context they were passed to and disappear when the page navigates. Defaults to `false`, in which case functions are not serializable and passing one throws an error, as before. + When set to `true`, functions passed inside [arg](/api/class-locator.mdx#locator-evaluate-handle-option-arg) are exposed in the page and can be called from the page function. Calling one returns a [Promise] of its result. Under the hood, each function is exposed via [page.exposeFunction()](/api/class-page.mdx#page-expose-function), so it is technically accessible from all frames and worlds of the page. Exposed functions are cleared upon the top-level navigation. Defaults to `false`, in which case functions are not serializable and passing one throws an error. - `signal` [AbortSignal] *(optional)* Added in: v1.62# Allows to cancel the operation using an [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal). If the signal is aborted, the operation will be aborted and throw an error. Note that providing a signal does not disable the default timeout, which can be changed using [browserContext.setDefaultTimeout()](/api/class-browsercontext.mdx#browser-context-set-default-timeout) or [page.setDefaultTimeout()](/api/class-page.mdx#page-set-default-timeout); pass `timeout: 0` to disable the timeout entirely. diff --git a/nodejs/docs/api/class-page.mdx b/nodejs/docs/api/class-page.mdx index 0c997395d8..9cff3523d8 100644 --- a/nodejs/docs/api/class-page.mdx +++ b/nodejs/docs/api/class-page.mdx @@ -95,6 +95,10 @@ The order of evaluation of multiple scripts installed via [browserContext.addIni - `arg` [Serializable] *(optional)*# Optional argument to pass to [script](/api/class-page.mdx#page-add-init-script-option-script) (only supported when passing a function). +- `options` [Object] *(optional)* + - `exposeFunctions` [boolean] *(optional)* Added in: v1.62# + + When set to `true`, functions passed inside [arg](/api/class-page.mdx#page-add-init-script-option-arg) are exposed in the page and can be called from the init script. Calling one returns a [Promise] of its result. Under the hood, each function is exposed via [page.exposeFunction()](/api/class-page.mdx#page-expose-function), so it is technically accessible from all frames and worlds of the page. Unlike functions passed to [page.evaluate()](/api/class-page.mdx#page-evaluate), functions passed to an init script are exposed in every new document, so they survive navigations. Defaults to `false`, in which case functions are not serializable and are silently dropped. **Returns** - [Promise]<[Disposable]># @@ -636,7 +640,7 @@ await bodyHandle.dispose(); - `options` [Object] *(optional)* - `exposeFunctions` [boolean] *(optional)* Added in: v1.62# - When set to `true`, functions passed inside [arg](/api/class-page.mdx#page-evaluate-option-arg) are exposed in the page and can be called from the page function. Calling one returns a [Promise] of its result. The page-side functions are scoped to the execution context they were passed to and disappear when the page navigates. Defaults to `false`, in which case functions are not serializable and passing one throws an error, as before. + When set to `true`, functions passed inside [arg](/api/class-page.mdx#page-evaluate-option-arg) are exposed in the page and can be called from the page function. Calling one returns a [Promise] of its result. Under the hood, each function is exposed via [page.exposeFunction()](/api/class-page.mdx#page-expose-function), so it is technically accessible from all frames and worlds of the page. Exposed functions are cleared upon the top-level navigation. Defaults to `false`, in which case functions are not serializable and passing one throws an error. **Returns** - [Promise]<[Serializable]># @@ -685,7 +689,7 @@ await resultHandle.dispose(); - `options` [Object] *(optional)* - `exposeFunctions` [boolean] *(optional)* Added in: v1.62# - When set to `true`, functions passed inside [arg](/api/class-page.mdx#page-evaluate-handle-option-arg) are exposed in the page and can be called from the page function. Calling one returns a [Promise] of its result. The page-side functions are scoped to the execution context they were passed to and disappear when the page navigates. Defaults to `false`, in which case functions are not serializable and passing one throws an error, as before. + When set to `true`, functions passed inside [arg](/api/class-page.mdx#page-evaluate-handle-option-arg) are exposed in the page and can be called from the page function. Calling one returns a [Promise] of its result. Under the hood, each function is exposed via [page.exposeFunction()](/api/class-page.mdx#page-expose-function), so it is technically accessible from all frames and worlds of the page. Exposed functions are cleared upon the top-level navigation. Defaults to `false`, in which case functions are not serializable and passing one throws an error. **Returns** - [Promise]<[JSHandle]># @@ -1218,6 +1222,11 @@ Returns the main resource response. In case of multiple redirects, the navigatio Navigate to the previous page in history. +:::warning + +**Testing Back/Forward Cache (BFCache) is not supported.** By default, Playwright disables the Back/Forward Cache across all browsers. Even if explicitly enabled, Playwright's internal state relies on network-level navigation events. Because BFCache restores unfreeze the DOM without firing these events, using `page.goBack()` or `page.goForward()` to trigger a BFCache restore will result in timeouts and a desynchronized `Page` state. +::: + **Usage** ```js @@ -1254,6 +1263,11 @@ Returns the main resource response. In case of multiple redirects, the navigatio Navigate to the next page in history. +:::warning + +**Testing Back/Forward Cache (BFCache) is not supported.** By default, Playwright disables the Back/Forward Cache across all browsers. Even if explicitly enabled, Playwright's internal state relies on network-level navigation events. Because BFCache restores unfreeze the DOM without firing these events, using `page.goBack()` or `page.goForward()` to trigger a BFCache restore will result in timeouts and a desynchronized `Page` state. +::: + **Usage** ```js diff --git a/nodejs/docs/api/class-testconfig.mdx b/nodejs/docs/api/class-testconfig.mdx index 3c82e2bd99..9c37e27207 100644 --- a/nodejs/docs/api/class-testconfig.mdx +++ b/nodejs/docs/api/class-testconfig.mdx @@ -359,104 +359,6 @@ export default defineConfig({ --- -### httpCache {/* #test-config-http-cache */} - -Added in: v1.62testConfig.httpCache - -Records network responses to disk and replays them on later runs, so large static dependencies are downloaded from a remote server once instead of on every run. This is most useful against a slow or remote environment such as staging. - -When `httpCache` is set, Playwright starts a caching proxy for the run and routes all browser traffic through it. On the first run, eligible responses are recorded under `dir`; on subsequent runs they are served from disk without reaching the network. A single proxy is shared by all workers, so a resource fetched by one worker is a cache hit for the rest, and the cache persists across runs until you delete `dir`. - -Loopback traffic (`localhost`, `127.0.0.1`) is never cached — a local dev server already serves from disk, so there is nothing to optimize. The cache targets remote origins. - -**What is cached by default** - -With no `match`, the cache stores only **shared static assets**: successful `GET` requests the browser makes for a static subresource — a script, stylesheet, image, font, or media element — as reported by the request's `Sec-Fetch-Dest` metadata. These bytes do not depend on who is signed in, so replaying them into a fresh browser context is always safe, which keeps tests that each create their own context isolated by construction. - -The following are therefore **not** cached by default: -* `fetch`/`XMLHttpRequest` (API) requests and top-level documents — their request destination is not a static subresource. This is the dynamic, per-user surface. -* Any response marked `Cache-Control: no-store`. -* Any response carrying a personalization signal: `Cache-Control: private`, a `Set-Cookie` header, or `Vary: Cookie`/`Vary: Authorization`. - -The `Authorization` and `Cookie` request headers are deliberately ignored when deciding what to cache. On a gated staging environment these are a shared environment credential attached to every request, not a per-user identity, so caching on their presence would be wrong. - -Freshness directives (`max-age`, `no-cache`, `Expires`) are ignored: once a response is recorded it is replayed until `dir` is deleted, keeping runs deterministic. `Vary` is honored — responses are keyed by the request-header values they vary on, and `Vary: *` is never stored. - -**Customizing with `match`** - -A string or [RegExp] restricts caching to requests whose URL matches; other requests pass straight through to the network. For full control, pass a callback that returns a decision object per request: -* `disposition` — `'cache'` force-stores the response and serves it back, `'no-cache'` bypasses the cache entirely, and `'default'` (or an empty object) applies the rules above. -* `identity` — a stable principal id (such as a session token) that partitions the cache. Entries recorded under one identity are never served to a request with a different one, so per-user content can be cached without leaking across contexts. The value is hashed into the cache key and never written to disk. - -Set `proxy` to fetch cache misses through an upstream proxy — for example, to reach a staging environment that is only accessible behind one. Browsers connect to the caching proxy, which chains to `proxy` for anything not served from disk. - -**Usage** - -Cache shared static assets from a staging server with zero configuration: - -```js title="playwright.config.ts" -import { defineConfig } from '@playwright/test'; - -export default defineConfig({ - httpCache: { dir: './.network-cache' }, -}); -``` - -Fetch cache misses through an upstream proxy: - -```js title="playwright.config.ts" -import { defineConfig } from '@playwright/test'; - -export default defineConfig({ - httpCache: { dir: './.network-cache', proxy: { server: 'http://myproxy.com:3128' } }, -}); -``` - -Take control per request — force-cache a per-user API response with session isolation, and bypass the cache for others: - -```js title="playwright.config.ts" -import { defineConfig } from '@playwright/test'; - -export default defineConfig({ - httpCache: { - dir: './.network-cache', - match: request => { - if (request.url.includes('/api/config')) - return { disposition: 'cache', identity: request.headers.get('authorization') }; - if (request.url.includes('/telemetry')) - return { disposition: 'no-cache' }; - return {}; - }, - }, -}); -``` - -**Type** -- [Object] - - `dir` [string] - - Directory where the cache is stored, resolved relative to the configuration file. - - `match` [string] | [RegExp] | [HttpCachePolicy] *(optional)* - - Limits or customizes what is cached. A glob pattern or regular expression restricts caching to requests whose URL matches; a callback returns a per-request decision (see [HttpCachePolicy]). When omitted, every request is considered with the default behavior. - - `proxy` [Object] *(optional)* - - `server` [string] - - Proxy to be used for all requests. HTTP and SOCKS proxies are supported, for example `http://myproxy.com:3128` or `socks5://myproxy.com:3128`. Short form `myproxy.com:3128` is considered an HTTP proxy. - - `bypass` [string] *(optional)* - - Optional comma-separated domains to bypass proxy. - - `username` [string] *(optional)* - - Optional username to use if HTTP proxy requires authentication. - - `password` [string] *(optional)* - - Optional password to use if HTTP proxy requires authentication. - - Upstream proxy for cache misses. - ---- - ### ignoreSnapshots {/* #test-config-ignore-snapshots */} Added in: v1.26testConfig.ignoreSnapshots diff --git a/nodejs/docs/api/class-testoptions.mdx b/nodejs/docs/api/class-testoptions.mdx index cec293d807..61917bfb7b 100644 --- a/nodejs/docs/api/class-testoptions.mdx +++ b/nodejs/docs/api/class-testoptions.mdx @@ -1133,6 +1133,55 @@ export default defineConfig({ page height in pixels. +--- + +## Deprecated + +### reuseContext {/* #test-options-reuse-context */} + +Added in: v1.62testOptions.reuseContext + +:::warning[Discouraged] + +This option trades test isolation for speed and is intended for component tests that drive a story gallery. Leave it unset for end-to-end tests - a fresh browser context per test is one of the core guarantees of Playwright Test. + +::: + + +**Experimental.** When set to `true`, all tests in a worker process run in a single browser context that is reused between tests, instead of getting a brand new context per test. Defaults to `false`. + +Between tests, Playwright resets the state that component tests typically touch: it clears cookies, cache, local storage and IndexedDB of visited origins, unregisters service workers, closes extra pages, removes routes, bindings and init scripts, and re-applies the configured storage state, viewport and emulation options. + +This reset is best-effort, not a guarantee of isolation. State that is **not** reset includes: +* Permissions granted with [browserContext.grantPermissions()](/api/class-browsercontext.mdx#browser-context-grant-permissions) during a test. +* Runtime changes made through [browserContext.setGeolocation()](/api/class-browsercontext.mdx#browser-context-set-geolocation), [browserContext.setOffline()](/api/class-browsercontext.mdx#browser-context-set-offline) and [browserContext.setExtraHTTPHeaders()](/api/class-browsercontext.mdx#browser-context-set-extra-http-headers). +* Browsing history, `window.name` and any browser-process-wide state. + +Additional restrictions: +* The option is ignored when [testOptions.video](/api/class-testoptions.mdx#test-options-video) recording is enabled. +* Only a few context options may differ between consecutive tests: `colorScheme`, `forcedColors`, `reducedMotion`, `contrast`, `screen`, `userAgent`, `viewport` and `testIdAttribute`. Changing any other option in [test.use()](/api/class-test.mdx#test-use), for example `locale` or `storageState`, silently forces a fresh context and negates the speedup. +* Do not combine with [testOptions.connectOptions](/api/class-testoptions.mdx#test-options-connect-options) pointing multiple workers at a shared browser - workers would compete for the single reusable context. +* `recordHar` in [testOptions.contextOptions](/api/class-testoptions.mdx#test-options-context-options) is not supported and produces no HAR file. + +**Usage** + +```js title="playwright.config.ts" +import { defineConfig } from '@playwright/test'; + +export default defineConfig({ + projects: [ + { + name: 'components', + testDir: './tests/components', + use: { reuseContext: true }, + }, + ], +}); +``` + +**Type** +- [boolean] + [APIRequest]: /api/class-apirequest.mdx "APIRequest" [APIRequestContext]: /api/class-apirequestcontext.mdx "APIRequestContext" diff --git a/nodejs/docs/navigations.mdx b/nodejs/docs/navigations.mdx index e168544c6d..99d58c60fe 100644 --- a/nodejs/docs/navigations.mdx +++ b/nodejs/docs/navigations.mdx @@ -60,6 +60,16 @@ await page.getByText('Click me').click(); await page.waitForURL('**/login'); ``` +## Back/Forward Cache (BFCache) + +Modern browsers utilize a Back/Forward Cache (BFCache) to instantly load a page when a user navigates back or forward. This is achieved by freezing the page's DOM and JavaScript heap in memory, and thawing it upon return. + +By default, Playwright disables the BFCache across all browsers to ensure consistent, clean testing environments. + +Even if you explicitly enable BFCache, **testing BFCache restorations is not supported**. Because a BFCache restore skips the network fetch phase, the browser does not fire standard navigation lifecycle events (such as `commit`, `domcontentloaded`, or `load`). Playwright's internal `Page` state heavily relies on these network-level events to stay synchronized. + +Consequently, triggering a BFCache restore (e.g., via `page.goBack()`) will bypass Playwright's lifecycle tracking, resulting in timeouts and a completely desynchronized `Page` object where subsequent interactions will fail. + ## Navigation events Playwright splits the process of showing a new document in a page into **navigation** and **loading**. diff --git a/nodejs/docs/test-components.mdx b/nodejs/docs/test-components.mdx index ccbf5ac10b..1f80d1a2c1 100644 --- a/nodejs/docs/test-components.mdx +++ b/nodejs/docs/test-components.mdx @@ -1,399 +1,195 @@ --- id: test-components -title: "Components (experimental)" +title: "Component testing" --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import HTMLCard from '@site/src/components/HTMLCard'; -import LiteYouTube from '@site/src/components/LiteYouTube'; - ## Introduction -Playwright Test can now test your components. - - - -## Example - -Here is what a typical component test looks like: +Playwright Test can test the components of your web application in isolation. A component test is a regular Playwright end-to-end test that runs against a small **story gallery** page served by your own dev server. There is no dedicated component-testing runtime, no bundler integration and no extra npm packages — the built-in [fixtures.mount()](/api/class-fixtures.mdx#fixtures-mount) fixture of `@playwright/test` drives it all. ```js -test('event should work', async ({ mount }) => { - let clicked = false; - - // Mount a component. Returns locator pointing to the component. - const component = await mount( - - ); +import { test, expect } from '@playwright/test'; - // As with any Playwright test, assert locator text. - await expect(component).toContainText('Submit'); - - // Perform locator click. This will trigger the event. - await component.click(); - - // Assert that respective events have been fired. - expect(clicked).toBeTruthy(); +test('click should expand', async ({ mount }) => { + const component = await mount('components/Expandable/Stateful'); + await component.getByRole('button').click(); + await expect(component.getByTestId('expanded')).toHaveValue('true'); }); ``` -## How to get started - -Adding Playwright Test to an existing project is easy. Below are the steps to enable Playwright Test for a React or Vue project. - -### Step 1: Install Playwright Test for components for your respective framework - - - - - -```bash -npm init playwright@latest -- --ct -``` - - - - - -```bash -yarn create playwright --ct -``` - - +Tests run in Node.js while components run in a real browser: real clicks are triggered, real layout is executed, visual regression is possible. At the same time, tests get everything Playwright Test offers: parallelism, parametrization, retries and post-mortem tracing. - +:::note -```bash -pnpm create playwright --ct -``` +This guide replaces the experimental `@playwright/experimental-ct-react` and `@playwright/experimental-ct-vue` packages. If you are using them today, see the [migration guide](#migration-from-the-experimental-packages) below. +::: - +## Why a framework-agnostic approach - +The `@playwright/experimental-ct-*` packages let tests write JSX inline — `mount(