From d1559a0fcc6ecd12bf6bacd3f66d848ea78aaa3a Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Tue, 13 Dec 2022 14:01:39 -0800 Subject: [PATCH] chore: route.fetch(postData) (#19436) --- docs/src/api/class-route.md | 35 ++-------------- docs/src/api/params.md | 8 ++++ .../playwright-core/src/client/network.ts | 42 +++++++++++++------ packages/playwright-core/types/types.d.ts | 30 ++++--------- tests/page/page-request-fallback.spec.ts | 18 ++++++++ tests/page/page-request-intercept.spec.ts | 2 +- 6 files changed, 70 insertions(+), 65 deletions(-) diff --git a/docs/src/api/class-route.md b/docs/src/api/class-route.md index 6e1c82e75d..ffeb7387b3 100644 --- a/docs/src/api/class-route.md +++ b/docs/src/api/class-route.md @@ -115,7 +115,7 @@ If set changes the request method (e.g. GET or POST). ### option: Route.continue.postData * since: v1.8 * langs: js, python, java -- `postData` <[string]|[Buffer]> +- `postData` <[string]|[Buffer]|[Serializable]> If set changes the post data of request. @@ -391,7 +391,7 @@ If set changes the request method (e.g. GET or POST). ### option: Route.fallback.postData * since: v1.23 * langs: js, python, java -- `postData` <[string]|[Buffer]> +- `postData` <[string]|[Buffer]|[Serializable]> If set changes the post data of request. @@ -480,10 +480,10 @@ If set changes the request URL. New URL must have same protocol as original one. If set changes the request method (e.g. GET or POST). -### option: Route.fetch.postData = %%-js-python-csharp-fetch-option-data-%% +### option: Route.fetch.postData = %%-js-python-csharp-fetch-option-post-data-%% * since: v1.29 -### option: Route.fetch.data +### option: Route.fetch.postData * since: v1.29 * langs: csharp - `postData` <[Buffer]> @@ -616,33 +616,6 @@ Optional response body as raw bytes. JSON response. This method will set the content type to `application/json` if not set. -**Usage** - -```js -await page.route('https://dog.ceo/api/breeds/list/all', async route => { - const json = { - message: { 'test_breed': [] } - }; - await route.fulfill({ json }); -}); -``` - -```python async -async def handle(route): - json = { "test_breed": [] } - await route.fulfill(json=json) - -await page.route("https://dog.ceo/api/breeds/list/all", handle) -``` - -```python sync -async def handle(route): - json = { "test_breed": [] } - route.fulfill(json=json) - -page.route("https://dog.ceo/api/breeds/list/all", handle) -``` - ### option: Route.fulfill.json * since: v1.29 * langs: csharp diff --git a/docs/src/api/params.md b/docs/src/api/params.md index d20ce3a651..0e07bcfc99 100644 --- a/docs/src/api/params.md +++ b/docs/src/api/params.md @@ -389,6 +389,14 @@ Allows to set post data of the request. If the data parameter is an object, it w and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` header will be set to `application/octet-stream` if not explicitly set. +## js-python-csharp-fetch-option-post-data +* langs: js, python, csharp +- `postData` <[string]|[Buffer]|[Serializable]> + +Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string +and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` header will be +set to `application/octet-stream` if not explicitly set. + ## js-python-csharp-fetch-option-ignorehttpserrors * langs: js, python, csharp - `ignoreHTTPSErrors` <[boolean]> diff --git a/packages/playwright-core/src/client/network.ts b/packages/playwright-core/src/client/network.ts index b6d536e878..1a7c63ed36 100644 --- a/packages/playwright-core/src/client/network.ts +++ b/packages/playwright-core/src/client/network.ts @@ -32,6 +32,7 @@ import type { HeadersArray, URLMatch } from '../common/types'; import { urlMatches } from '../common/netUtils'; import { MultiMap } from '../utils/multimap'; import { APIResponse } from './fetch'; +import type { Serializable } from '../../types/structs'; export type NetworkCookie = { name: string, @@ -56,11 +57,18 @@ export type SetNetworkCookieParam = { sameSite?: 'Strict' | 'Lax' | 'None' }; +type SerializedFallbackOverrides = { + url?: string; + method?: string; + headers?: Headers; + postDataBuffer?: Buffer; +}; + type FallbackOverrides = { url?: string; method?: string; headers?: Headers; - postData?: string | Buffer; + postData?: string | Buffer | Serializable; }; export class Request extends ChannelOwner implements api.Request { @@ -71,7 +79,7 @@ export class Request extends ChannelOwner implements ap private _actualHeadersPromise: Promise | undefined; private _postData: Buffer | null; _timing: ResourceTiming; - private _fallbackOverrides: FallbackOverrides = {}; + private _fallbackOverrides: SerializedFallbackOverrides = {}; static from(request: channels.RequestChannel): Request { return (request as any)._object; @@ -114,17 +122,14 @@ export class Request extends ChannelOwner implements ap } postData(): string | null { - if (this._fallbackOverrides.postData) - return this._fallbackOverrides.postData.toString('utf-8'); + if (this._fallbackOverrides.postDataBuffer) + return this._fallbackOverrides.postDataBuffer.toString('utf-8'); return this._postData ? this._postData.toString('utf8') : null; } postDataBuffer(): Buffer | null { - if (this._fallbackOverrides.postData) { - if (isString(this._fallbackOverrides.postData)) - return Buffer.from(this._fallbackOverrides.postData, 'utf-8'); - return this._fallbackOverrides.postData; - } + if (this._fallbackOverrides.postDataBuffer) + return this._fallbackOverrides.postDataBuffer; return this._postData; } @@ -251,7 +256,21 @@ export class Request extends ChannelOwner implements ap } _applyFallbackOverrides(overrides: FallbackOverrides) { - this._fallbackOverrides = { ...this._fallbackOverrides, ...overrides }; + const basicOptions = { ...overrides, postData: undefined }; + + const postData = overrides.postData; + let postDataBuffer = this._fallbackOverrides.postDataBuffer; + if (isString(postData)) + postDataBuffer = Buffer.from(postData, 'utf-8'); + else if (postData instanceof Buffer) + postDataBuffer = postData; + else if (postData) + postDataBuffer = Buffer.from(JSON.stringify(postData), 'utf-8'); + this._fallbackOverrides = { + ...this._fallbackOverrides, + ...basicOptions, + postDataBuffer, + }; } _fallbackOverridesForContinue() { @@ -400,12 +419,11 @@ export class Route extends ChannelOwner implements api.Ro async _innerContinue(internal = false) { const options = this.request()._fallbackOverridesForContinue(); return await this._wrapApiCall(async () => { - const postDataBuffer = isString(options.postData) ? Buffer.from(options.postData, 'utf8') : options.postData; await this._raceWithTargetClose(this._channel.continue({ url: options.url, method: options.method, headers: options.headers ? headersObjectToArray(options.headers) : undefined, - postData: postDataBuffer, + postData: options.postDataBuffer, })); }, !!internal); } diff --git a/packages/playwright-core/types/types.d.ts b/packages/playwright-core/types/types.d.ts index 023ed057bc..7de1eeaf2b 100644 --- a/packages/playwright-core/types/types.d.ts +++ b/packages/playwright-core/types/types.d.ts @@ -17067,7 +17067,7 @@ export interface Route { /** * If set changes the post data of request. */ - postData?: string|Buffer; + postData?: string|Buffer|Serializable; /** * If set changes the request URL. New URL must have same protocol as original one. @@ -17154,7 +17154,7 @@ export interface Route { /** * If set changes the post data of request. */ - postData?: string|Buffer; + postData?: string|Buffer|Serializable; /** * If set changes the request URL. New URL must have same protocol as original one. Changing the URL won't affect the @@ -17181,13 +17181,6 @@ export interface Route { * @param options */ fetch(options?: { - /** - * Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string - * and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` - * header will be set to `application/octet-stream` if not explicitly set. - */ - data?: string|Buffer|Serializable; - /** * If set changes the request HTTP headers. Header values will be converted to a string. */ @@ -17198,6 +17191,13 @@ export interface Route { */ method?: string; + /** + * Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string + * and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` + * header will be set to `application/octet-stream` if not explicitly set. + */ + postData?: string|Buffer|Serializable; + /** * If set changes the request URL. New URL must have same protocol as original one. */ @@ -17247,18 +17247,6 @@ export interface Route { /** * JSON response. This method will set the content type to `application/json` if not set. - * - * **Usage** - * - * ```js - * await page.route('https://dog.ceo/api/breeds/list/all', async route => { - * const json = { - * message: { 'test_breed': [] } - * }; - * await route.fulfill({ json }); - * }); - * ``` - * */ json?: Serializable; diff --git a/tests/page/page-request-fallback.spec.ts b/tests/page/page-request-fallback.spec.ts index d46ac9723d..ee852fd108 100644 --- a/tests/page/page-request-fallback.spec.ts +++ b/tests/page/page-request-fallback.spec.ts @@ -259,4 +259,22 @@ it.describe('post data', () => { expect(postDataBuffer[i]).toBe(arr[i]); } }); + + it('should amend json post data', async ({ page, server }) => { + await page.goto(server.EMPTY_PAGE); + let postData: string; + await page.route('**/*', route => { + postData = route.request().postDataJSON(); + route.continue(); + }); + await page.route('**/*', route => { + route.fallback({ postData: { foo: 'bar' } }); + }); + const [serverRequest] = await Promise.all([ + server.waitForRequest('/sleep.zzz'), + page.evaluate(() => fetch('/sleep.zzz', { method: 'POST', body: 'birdy' })) + ]); + expect(postData).toEqual({ foo: 'bar' }); + expect((await serverRequest.postBody).toString('utf8')).toBe('{"foo":"bar"}'); + }); }); diff --git a/tests/page/page-request-intercept.spec.ts b/tests/page/page-request-intercept.spec.ts index 5c686d9d05..f2fa09c53f 100644 --- a/tests/page/page-request-intercept.spec.ts +++ b/tests/page/page-request-intercept.spec.ts @@ -224,7 +224,7 @@ it('should intercept with post data override', async ({ page, server, isElectron const requestPromise = server.waitForRequest('/empty.html'); await page.route('**/*.html', async route => { const response = await route.fetch({ - data: { 'foo': 'bar' }, + postData: { 'foo': 'bar' }, }); await route.fulfill({ response }); });