feat: allow URLSearchParams and string as params in APIRequestContext (#32120)
This commit is contained in:
parent
3d69c591d3
commit
308381eeae
|
|
@ -138,10 +138,13 @@ context cookies from the response. The method will automatically follow redirect
|
|||
### param: APIRequestContext.delete.url = %%-fetch-param-url-%%
|
||||
* since: v1.16
|
||||
|
||||
### option: APIRequestContext.delete.params = %%-js-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### param: APIRequestContext.delete.params = %%-java-csharp-fetch-params-%%
|
||||
* since: v1.18
|
||||
|
||||
### option: APIRequestContext.delete.params = %%-js-python-fetch-option-params-%%
|
||||
### option: APIRequestContext.delete.params = %%-python-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### 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.
|
||||
|
||||
### option: APIRequestContext.fetch.params = %%-js-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### param: APIRequestContext.fetch.params = %%-java-csharp-fetch-params-%%
|
||||
* since: v1.18
|
||||
|
||||
### option: APIRequestContext.fetch.params = %%-js-python-fetch-option-params-%%
|
||||
### option: APIRequestContext.fetch.params = %%-python-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### 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-%%
|
||||
* since: v1.16
|
||||
|
||||
### option: APIRequestContext.get.params = %%-js-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### param: APIRequestContext.get.params = %%-java-csharp-fetch-params-%%
|
||||
* since: v1.18
|
||||
|
||||
### option: APIRequestContext.get.params = %%-js-python-fetch-option-params-%%
|
||||
### option: APIRequestContext.get.params = %%-python-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### 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-%%
|
||||
* since: v1.16
|
||||
|
||||
### option: APIRequestContext.head.params = %%-js-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### param: APIRequestContext.head.params = %%-java-csharp-fetch-params-%%
|
||||
* since: v1.18
|
||||
|
||||
### option: APIRequestContext.head.params = %%-js-python-fetch-option-params-%%
|
||||
### option: APIRequestContext.head.params = %%-python-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### 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-%%
|
||||
* since: v1.16
|
||||
|
||||
### option: APIRequestContext.patch.params = %%-js-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### param: APIRequestContext.patch.params = %%-java-csharp-fetch-params-%%
|
||||
* since: v1.18
|
||||
|
||||
### option: APIRequestContext.patch.params = %%-js-python-fetch-option-params-%%
|
||||
### option: APIRequestContext.patch.params = %%-python-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### 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-%%
|
||||
* since: v1.16
|
||||
|
||||
### option: APIRequestContext.post.params = %%-js-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### param: APIRequestContext.post.params = %%-java-csharp-fetch-params-%%
|
||||
* since: v1.18
|
||||
|
||||
### option: APIRequestContext.post.params = %%-js-python-fetch-option-params-%%
|
||||
### option: APIRequestContext.post.params = %%-python-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### 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-%%
|
||||
* since: v1.16
|
||||
|
||||
### option: APIRequestContext.put.params = %%-js-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### param: APIRequestContext.put.params = %%-java-csharp-fetch-params-%%
|
||||
* since: v1.18
|
||||
|
||||
### option: APIRequestContext.put.params = %%-js-python-fetch-option-params-%%
|
||||
### option: APIRequestContext.put.params = %%-python-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### option: APIRequestContext.put.params = %%-csharp-fetch-option-params-%%
|
||||
|
|
|
|||
|
|
@ -356,8 +356,14 @@ Emulates consistent window screen size available inside web page via `window.scr
|
|||
|
||||
Target URL.
|
||||
|
||||
## js-python-fetch-option-params
|
||||
* langs: js, python
|
||||
## js-fetch-option-params
|
||||
* 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]>>
|
||||
|
||||
Query parameters to be sent with the URL.
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ import { TargetClosedError, isTargetClosedError } from './errors';
|
|||
import { toClientCertificatesProtocol } from './browserContext';
|
||||
|
||||
export type FetchOptions = {
|
||||
params?: { [key: string]: string; },
|
||||
params?: { [key: string]: string | number | boolean; } | URLSearchParams | string,
|
||||
method?: string,
|
||||
headers?: Headers,
|
||||
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.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 params = objectToArray(options.params);
|
||||
const params = mapParamsToArray(options.params);
|
||||
const method = options.method || options.request?.method();
|
||||
// Cannot call allHeaders() here as the request may be paused inside route handler.
|
||||
const headersObj = options.headers || options.request?.headers();
|
||||
|
|
@ -407,6 +407,30 @@ function objectToArray(map?: { [key: string]: any }): NameValue[] | undefined {
|
|||
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 {
|
||||
return typeof value === 'object' && value['name'] && value['mimeType'] && value['buffer'];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ export abstract class APIRequestContext extends SdkObject {
|
|||
const requestUrl = new URL(params.url, defaults.baseURL);
|
||||
if (params.params) {
|
||||
for (const { name, value } of params.params)
|
||||
requestUrl.searchParams.set(name, value);
|
||||
requestUrl.searchParams.append(name, value);
|
||||
}
|
||||
|
||||
const credentials = this._getHttpCredentials(requestUrl);
|
||||
|
|
|
|||
14
packages/playwright-core/types/types.d.ts
vendored
14
packages/playwright-core/types/types.d.ts
vendored
|
|
@ -16518,7 +16518,7 @@ export interface APIRequestContext {
|
|||
/**
|
||||
* 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.
|
||||
|
|
@ -16654,7 +16654,7 @@ export interface APIRequestContext {
|
|||
/**
|
||||
* 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.
|
||||
|
|
@ -16754,7 +16754,7 @@ export interface APIRequestContext {
|
|||
/**
|
||||
* 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.
|
||||
|
|
@ -16840,7 +16840,7 @@ export interface APIRequestContext {
|
|||
/**
|
||||
* 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.
|
||||
|
|
@ -16926,7 +16926,7 @@ export interface APIRequestContext {
|
|||
/**
|
||||
* 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.
|
||||
|
|
@ -17054,7 +17054,7 @@ export interface APIRequestContext {
|
|||
/**
|
||||
* 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.
|
||||
|
|
@ -17140,7 +17140,7 @@ export interface APIRequestContext {
|
|||
/**
|
||||
* 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.
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
it(`${method} should support queryParams`, async ({ context, server }) => {
|
||||
const url = new URL(server.EMPTY_PAGE);
|
||||
url.searchParams.set('p1', 'v1');
|
||||
url.searchParams.set('парам2', 'знач2');
|
||||
const [request] = await Promise.all([
|
||||
server.waitForRequest(url.pathname + url.search),
|
||||
context.request[method](server.EMPTY_PAGE + '?p1=foo', {
|
||||
params: {
|
||||
'p1': 'v1',
|
||||
'парам2': 'знач2',
|
||||
}
|
||||
}),
|
||||
]);
|
||||
const params = new URLSearchParams(request.url!.substr(request.url!.indexOf('?')));
|
||||
expect(params.get('p1')).toEqual('v1');
|
||||
expect(params.get('парам2')).toEqual('знач2');
|
||||
it(`${method} should support params passed as object`, async ({ context, server }) => {
|
||||
const params = {
|
||||
'first-param': 'value2',
|
||||
'second-param': 'value',
|
||||
};
|
||||
|
||||
const response = await context.request[method](server.EMPTY_PAGE + '?first-param=value1', { 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 URLSearchParams`, async ({ context, server }) => {
|
||||
const params = new URLSearchParams();
|
||||
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 }) => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue