From c7b6a764371b7cadca643d96bb669a656f2df2a4 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Mon, 30 Oct 2023 15:23:12 -0700 Subject: [PATCH] fix(fetch): throw when methods are called on disposed context (#27868) Fixes #27822 --- docs/src/api/class-apirequestcontext.md | 4 ++++ .../src/server/dispatchers/networkDispatchers.ts | 4 +++- packages/playwright-core/types/types.d.ts | 10 ++++++++++ tests/library/browsercontext-fetch.spec.ts | 6 ++++++ tests/library/global-fetch.spec.ts | 7 +++++++ 5 files changed, 30 insertions(+), 1 deletion(-) diff --git a/docs/src/api/class-apirequestcontext.md b/docs/src/api/class-apirequestcontext.md index 8d6715d948..d1e6b5bcd6 100644 --- a/docs/src/api/class-apirequestcontext.md +++ b/docs/src/api/class-apirequestcontext.md @@ -183,6 +183,10 @@ context cookies from the response. The method will automatically follow redirect All responses returned by [`method: APIRequestContext.get`] and similar methods are stored in the memory, so that you can later call [`method: APIResponse.body`]. This method discards all stored responses, and makes [`method: APIResponse.body`] throw "Response disposed" error. +If this [APIRequestContext] is obtained via [`property: BrowserContext.request`] or [`property: Page.request`], it will keep working until its owning [BrowserContext] closes. + +If this [APIRequestContext] was created by [`method: APIRequest.newContext`], this method discards all its resources, calling any method on disposed [APIRequestContext] will throw an exception. + ## async method: APIRequestContext.fetch * since: v1.16 - returns: <[APIResponse]> diff --git a/packages/playwright-core/src/server/dispatchers/networkDispatchers.ts b/packages/playwright-core/src/server/dispatchers/networkDispatchers.ts index 78d862bc8d..325020f802 100644 --- a/packages/playwright-core/src/server/dispatchers/networkDispatchers.ts +++ b/packages/playwright-core/src/server/dispatchers/networkDispatchers.ts @@ -15,7 +15,7 @@ */ import type * as channels from '@protocol/channels'; -import type { APIRequestContext } from '../fetch'; +import { APIRequestContext } from '../fetch'; import type { CallMetadata } from '../instrumentation'; import type { Request, Response, Route } from '../network'; import { WebSocket } from '../network'; @@ -191,6 +191,8 @@ export class APIRequestContextDispatcher extends Dispatcher this._dispose()); + this.adopt(tracing); } diff --git a/packages/playwright-core/types/types.d.ts b/packages/playwright-core/types/types.d.ts index 986846c9a6..9f4ab6438b 100644 --- a/packages/playwright-core/types/types.d.ts +++ b/packages/playwright-core/types/types.d.ts @@ -15262,6 +15262,16 @@ export interface APIRequestContext { * stored responses, and makes * [apiResponse.body()](https://playwright.dev/docs/api/class-apiresponse#api-response-body) throw "Response disposed" * error. + * + * If this {@link APIRequestContext} is obtained via + * [browserContext.request](https://playwright.dev/docs/api/class-browsercontext#browser-context-request) or + * [page.request](https://playwright.dev/docs/api/class-page#page-request), it will keep working until its owning + * {@link BrowserContext} closes. + * + * If this {@link APIRequestContext} was created by + * [apiRequest.newContext([options])](https://playwright.dev/docs/api/class-apirequest#api-request-new-context), this + * method discards all its resources, calling any method on disposed {@link APIRequestContext} will throw an + * exception. */ dispose(): Promise; diff --git a/tests/library/browsercontext-fetch.spec.ts b/tests/library/browsercontext-fetch.spec.ts index 105eea9220..f9c83b9e72 100644 --- a/tests/library/browsercontext-fetch.spec.ts +++ b/tests/library/browsercontext-fetch.spec.ts @@ -1192,3 +1192,9 @@ it('should update host header on redirect', async ({ context, server }) => { expect((await reqPromise).headers.host).toBe(new URL(server.CROSS_PROCESS_PREFIX).host); }); + +it('should keep working after dispose', async ({ context, server }) => { + it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/27822' }); + await context.request.dispose(); + await expect(await context.request.get(server.EMPTY_PAGE)).toBeOK(); +}); diff --git a/tests/library/global-fetch.spec.ts b/tests/library/global-fetch.spec.ts index af0d7f770d..a16b4b6172 100644 --- a/tests/library/global-fetch.spec.ts +++ b/tests/library/global-fetch.spec.ts @@ -451,3 +451,10 @@ it('should serialize post data on the client', async ({ playwright, server }) => // expect(serverRequest.rawHeaders).toContain('vaLUE'); await request.dispose(); }); + +it('should throw after dispose', async ({ playwright, server }) => { + it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/27822' }); + const request = await playwright.request.newContext(); + await request.dispose(); + await expect(request.get(server.EMPTY_PAGE)).rejects.toThrow('Target page, context or browser has been closed'); +});