feat: allow URLSearchParams and string as params in APIRequestContext (#32120)

This commit is contained in:
Kuba Janik 2024-08-12 23:22:03 +02:00 committed by GitHub
parent 3d69c591d3
commit 308381eeae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 104 additions and 35 deletions

View file

@ -138,10 +138,13 @@ context cookies from the response. The method will automatically follow redirect
### param: APIRequestContext.delete.url = %%-fetch-param-url-%% ### param: APIRequestContext.delete.url = %%-fetch-param-url-%%
* since: v1.16 * since: v1.16
### option: APIRequestContext.delete.params = %%-js-fetch-option-params-%%
* since: v1.16
### param: APIRequestContext.delete.params = %%-java-csharp-fetch-params-%% ### param: APIRequestContext.delete.params = %%-java-csharp-fetch-params-%%
* since: v1.18 * since: v1.18
### option: APIRequestContext.delete.params = %%-js-python-fetch-option-params-%% ### option: APIRequestContext.delete.params = %%-python-fetch-option-params-%%
* since: v1.16 * since: v1.16
### option: APIRequestContext.delete.params = %%-csharp-fetch-option-params-%% ### option: APIRequestContext.delete.params = %%-csharp-fetch-option-params-%%
@ -297,10 +300,13 @@ await Request.FetchAsync("https://example.com/api/uploadScript", new() { Method
Target URL or Request to get all parameters from. Target URL or Request to get all parameters from.
### option: APIRequestContext.fetch.params = %%-js-fetch-option-params-%%
* since: v1.16
### param: APIRequestContext.fetch.params = %%-java-csharp-fetch-params-%% ### param: APIRequestContext.fetch.params = %%-java-csharp-fetch-params-%%
* since: v1.18 * since: v1.18
### option: APIRequestContext.fetch.params = %%-js-python-fetch-option-params-%% ### option: APIRequestContext.fetch.params = %%-python-fetch-option-params-%%
* since: v1.16 * since: v1.16
### option: APIRequestContext.fetch.params = %%-csharp-fetch-option-params-%% ### option: APIRequestContext.fetch.params = %%-csharp-fetch-option-params-%%
@ -397,10 +403,13 @@ await request.GetAsync("https://example.com/api/getText", new() { Params = query
### param: APIRequestContext.get.url = %%-fetch-param-url-%% ### param: APIRequestContext.get.url = %%-fetch-param-url-%%
* since: v1.16 * since: v1.16
### option: APIRequestContext.get.params = %%-js-fetch-option-params-%%
* since: v1.16
### param: APIRequestContext.get.params = %%-java-csharp-fetch-params-%% ### param: APIRequestContext.get.params = %%-java-csharp-fetch-params-%%
* since: v1.18 * since: v1.18
### option: APIRequestContext.get.params = %%-js-python-fetch-option-params-%% ### option: APIRequestContext.get.params = %%-python-fetch-option-params-%%
* since: v1.16 * since: v1.16
### option: APIRequestContext.get.params = %%-csharp-fetch-option-params-%% ### option: APIRequestContext.get.params = %%-csharp-fetch-option-params-%%
@ -453,10 +462,13 @@ context cookies from the response. The method will automatically follow redirect
### param: APIRequestContext.head.url = %%-fetch-param-url-%% ### param: APIRequestContext.head.url = %%-fetch-param-url-%%
* since: v1.16 * since: v1.16
### option: APIRequestContext.head.params = %%-js-fetch-option-params-%%
* since: v1.16
### param: APIRequestContext.head.params = %%-java-csharp-fetch-params-%% ### param: APIRequestContext.head.params = %%-java-csharp-fetch-params-%%
* since: v1.18 * since: v1.18
### option: APIRequestContext.head.params = %%-js-python-fetch-option-params-%% ### option: APIRequestContext.head.params = %%-python-fetch-option-params-%%
* since: v1.16 * since: v1.16
### option: APIRequestContext.head.params = %%-csharp-fetch-option-params-%% ### option: APIRequestContext.head.params = %%-csharp-fetch-option-params-%%
@ -509,10 +521,13 @@ context cookies from the response. The method will automatically follow redirect
### param: APIRequestContext.patch.url = %%-fetch-param-url-%% ### param: APIRequestContext.patch.url = %%-fetch-param-url-%%
* since: v1.16 * since: v1.16
### option: APIRequestContext.patch.params = %%-js-fetch-option-params-%%
* since: v1.16
### param: APIRequestContext.patch.params = %%-java-csharp-fetch-params-%% ### param: APIRequestContext.patch.params = %%-java-csharp-fetch-params-%%
* since: v1.18 * since: v1.18
### option: APIRequestContext.patch.params = %%-js-python-fetch-option-params-%% ### option: APIRequestContext.patch.params = %%-python-fetch-option-params-%%
* since: v1.16 * since: v1.16
### option: APIRequestContext.patch.params = %%-csharp-fetch-option-params-%% ### option: APIRequestContext.patch.params = %%-csharp-fetch-option-params-%%
@ -686,10 +701,13 @@ await request.PostAsync("https://example.com/api/uploadScript", new() { Multipar
### param: APIRequestContext.post.url = %%-fetch-param-url-%% ### param: APIRequestContext.post.url = %%-fetch-param-url-%%
* since: v1.16 * since: v1.16
### option: APIRequestContext.post.params = %%-js-fetch-option-params-%%
* since: v1.16
### param: APIRequestContext.post.params = %%-java-csharp-fetch-params-%% ### param: APIRequestContext.post.params = %%-java-csharp-fetch-params-%%
* since: v1.18 * since: v1.18
### option: APIRequestContext.post.params = %%-js-python-fetch-option-params-%% ### option: APIRequestContext.post.params = %%-python-fetch-option-params-%%
* since: v1.16 * since: v1.16
### option: APIRequestContext.post.params = %%-csharp-fetch-option-params-%% ### option: APIRequestContext.post.params = %%-csharp-fetch-option-params-%%
@ -742,10 +760,13 @@ context cookies from the response. The method will automatically follow redirect
### param: APIRequestContext.put.url = %%-fetch-param-url-%% ### param: APIRequestContext.put.url = %%-fetch-param-url-%%
* since: v1.16 * since: v1.16
### option: APIRequestContext.put.params = %%-js-fetch-option-params-%%
* since: v1.16
### param: APIRequestContext.put.params = %%-java-csharp-fetch-params-%% ### param: APIRequestContext.put.params = %%-java-csharp-fetch-params-%%
* since: v1.18 * since: v1.18
### option: APIRequestContext.put.params = %%-js-python-fetch-option-params-%% ### option: APIRequestContext.put.params = %%-python-fetch-option-params-%%
* since: v1.16 * since: v1.16
### option: APIRequestContext.put.params = %%-csharp-fetch-option-params-%% ### option: APIRequestContext.put.params = %%-csharp-fetch-option-params-%%

View file

@ -356,8 +356,14 @@ Emulates consistent window screen size available inside web page via `window.scr
Target URL. Target URL.
## js-python-fetch-option-params ## js-fetch-option-params
* langs: js, python * langs: js
- `params` <[Object]<[string], [string]|[number]|[boolean]>|[URLSearchParams]|[string]>
Query parameters to be sent with the URL.
## python-fetch-option-params
* langs: python
- `params` <[Object]<[string], [string]|[float]|[boolean]>> - `params` <[Object]<[string], [string]|[float]|[boolean]>>
Query parameters to be sent with the URL. Query parameters to be sent with the URL.

View file

@ -32,7 +32,7 @@ import { TargetClosedError, isTargetClosedError } from './errors';
import { toClientCertificatesProtocol } from './browserContext'; import { toClientCertificatesProtocol } from './browserContext';
export type FetchOptions = { export type FetchOptions = {
params?: { [key: string]: string; }, params?: { [key: string]: string | number | boolean; } | URLSearchParams | string,
method?: string, method?: string,
headers?: Headers, headers?: Headers,
data?: string | Buffer | Serializable, data?: string | Buffer | Serializable,
@ -175,7 +175,7 @@ export class APIRequestContext extends ChannelOwner<channels.APIRequestContextCh
assert(options.maxRedirects === undefined || options.maxRedirects >= 0, `'maxRedirects' must be greater than or equal to '0'`); assert(options.maxRedirects === undefined || options.maxRedirects >= 0, `'maxRedirects' must be greater than or equal to '0'`);
assert(options.maxRetries === undefined || options.maxRetries >= 0, `'maxRetries' must be greater than or equal to '0'`); assert(options.maxRetries === undefined || options.maxRetries >= 0, `'maxRetries' must be greater than or equal to '0'`);
const url = options.url !== undefined ? options.url : options.request!.url(); const url = options.url !== undefined ? options.url : options.request!.url();
const params = objectToArray(options.params); const params = mapParamsToArray(options.params);
const method = options.method || options.request?.method(); const method = options.method || options.request?.method();
// Cannot call allHeaders() here as the request may be paused inside route handler. // Cannot call allHeaders() here as the request may be paused inside route handler.
const headersObj = options.headers || options.request?.headers(); const headersObj = options.headers || options.request?.headers();
@ -407,6 +407,30 @@ function objectToArray(map?: { [key: string]: any }): NameValue[] | undefined {
return result; return result;
} }
function queryStringToArray(queryString: string): NameValue[] | undefined {
const searchParams = new URLSearchParams(queryString);
return searchParamsToArray(searchParams);
}
function searchParamsToArray(searchParams: URLSearchParams): NameValue[] | undefined {
if (searchParams.size === 0)
return undefined;
const result: NameValue[] = [];
for (const [name, value] of searchParams.entries())
result.push({ name, value });
return result;
}
function mapParamsToArray(params: FetchOptions['params']): NameValue[] | undefined {
if (params instanceof URLSearchParams)
return searchParamsToArray(params);
if (typeof params === 'string')
return queryStringToArray(params);
return objectToArray(params);
}
function isFilePayload(value: any): boolean { function isFilePayload(value: any): boolean {
return typeof value === 'object' && value['name'] && value['mimeType'] && value['buffer']; return typeof value === 'object' && value['name'] && value['mimeType'] && value['buffer'];
} }

View file

@ -157,7 +157,7 @@ export abstract class APIRequestContext extends SdkObject {
const requestUrl = new URL(params.url, defaults.baseURL); const requestUrl = new URL(params.url, defaults.baseURL);
if (params.params) { if (params.params) {
for (const { name, value } of params.params) for (const { name, value } of params.params)
requestUrl.searchParams.set(name, value); requestUrl.searchParams.append(name, value);
} }
const credentials = this._getHttpCredentials(requestUrl); const credentials = this._getHttpCredentials(requestUrl);

View file

@ -16518,7 +16518,7 @@ export interface APIRequestContext {
/** /**
* Query parameters to be sent with the URL. * Query parameters to be sent with the URL.
*/ */
params?: { [key: string]: string|number|boolean; }; params?: { [key: string]: string|number|boolean; }|URLSearchParams|string;
/** /**
* Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. * Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
@ -16654,7 +16654,7 @@ export interface APIRequestContext {
/** /**
* Query parameters to be sent with the URL. * Query parameters to be sent with the URL.
*/ */
params?: { [key: string]: string|number|boolean; }; params?: { [key: string]: string|number|boolean; }|URLSearchParams|string;
/** /**
* Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. * Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
@ -16754,7 +16754,7 @@ export interface APIRequestContext {
/** /**
* Query parameters to be sent with the URL. * Query parameters to be sent with the URL.
*/ */
params?: { [key: string]: string|number|boolean; }; params?: { [key: string]: string|number|boolean; }|URLSearchParams|string;
/** /**
* Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. * Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
@ -16840,7 +16840,7 @@ export interface APIRequestContext {
/** /**
* Query parameters to be sent with the URL. * Query parameters to be sent with the URL.
*/ */
params?: { [key: string]: string|number|boolean; }; params?: { [key: string]: string|number|boolean; }|URLSearchParams|string;
/** /**
* Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. * Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
@ -16926,7 +16926,7 @@ export interface APIRequestContext {
/** /**
* Query parameters to be sent with the URL. * Query parameters to be sent with the URL.
*/ */
params?: { [key: string]: string|number|boolean; }; params?: { [key: string]: string|number|boolean; }|URLSearchParams|string;
/** /**
* Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. * Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
@ -17054,7 +17054,7 @@ export interface APIRequestContext {
/** /**
* Query parameters to be sent with the URL. * Query parameters to be sent with the URL.
*/ */
params?: { [key: string]: string|number|boolean; }; params?: { [key: string]: string|number|boolean; }|URLSearchParams|string;
/** /**
* Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. * Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
@ -17140,7 +17140,7 @@ export interface APIRequestContext {
/** /**
* Query parameters to be sent with the URL. * Query parameters to be sent with the URL.
*/ */
params?: { [key: string]: string|number|boolean; }; params?: { [key: string]: string|number|boolean; }|URLSearchParams|string;
/** /**
* Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. * Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.

View file

@ -122,22 +122,40 @@ it('should add session cookies to request', async ({ context, server }) => {
}); });
for (const method of ['fetch', 'delete', 'get', 'head', 'patch', 'post', 'put'] as const) { for (const method of ['fetch', 'delete', 'get', 'head', 'patch', 'post', 'put'] as const) {
it(`${method} should support queryParams`, async ({ context, server }) => { it(`${method} should support params passed as object`, async ({ context, server }) => {
const url = new URL(server.EMPTY_PAGE); const params = {
url.searchParams.set('p1', 'v1'); 'first-param': 'value2',
url.searchParams.set('парам2', 'знач2'); 'second-param': 'value',
const [request] = await Promise.all([ };
server.waitForRequest(url.pathname + url.search),
context.request[method](server.EMPTY_PAGE + '?p1=foo', { const response = await context.request[method](server.EMPTY_PAGE + '?first-param=value1', { params });
params: {
'p1': 'v1', const { searchParams } = new URL(response.url());
'парам2': 'знач2', expect(searchParams.getAll('first-param')).toEqual(['value1', 'value2']);
} expect(searchParams.get('second-param')).toBe('value');
}), });
]);
const params = new URLSearchParams(request.url!.substr(request.url!.indexOf('?'))); it(`${method} should support params passed as URLSearchParams`, async ({ context, server }) => {
expect(params.get('p1')).toEqual('v1'); const params = new URLSearchParams();
expect(params.get('парам2')).toEqual('знач2'); params.append('first-param', 'value1');
params.append('first-param', 'value2');
params.append('second-param', 'value');
const response = await context.request[method](server.EMPTY_PAGE, { params });
const { searchParams } = new URL(response.url());
expect(searchParams.getAll('first-param')).toEqual(['value1', 'value2']);
expect(searchParams.get('second-param')).toBe('value');
});
it(`${method} should support params passed as string`, async ({ context, server }) => {
const params = 'first-param=value1&first-param=value2&second-param=value';
const response = await context.request[method](server.EMPTY_PAGE, { params });
const { searchParams } = new URL(response.url());
expect(searchParams.getAll('first-param')).toEqual(['value1', 'value2']);
expect(searchParams.get('second-param')).toBe('value');
}); });
it(`${method} should support failOnStatusCode`, async ({ context, server }) => { it(`${method} should support failOnStatusCode`, async ({ context, server }) => {