feat(fetch): support query params (#8893)
This commit is contained in:
parent
3e5645ecea
commit
f8c0f0d637
|
|
@ -16,6 +16,11 @@ context cookies from the response. The method will automatically follow redirect
|
|||
|
||||
Target URL or Request to get all fetch parameters from.
|
||||
|
||||
### option: FetchRequest.fetch.params
|
||||
- `params` <[Object]<[string], [string]>>
|
||||
|
||||
Query parameters to be send with the URL.
|
||||
|
||||
### option: FetchRequest.fetch.method
|
||||
- `method` <[string]>
|
||||
|
||||
|
|
@ -47,6 +52,11 @@ context cookies from the response. The method will automatically follow redirect
|
|||
|
||||
Target URL or Request to get all fetch parameters from.
|
||||
|
||||
### option: FetchRequest.get.params
|
||||
- `params` <[Object]<[string], [string]>>
|
||||
|
||||
Query parameters to be send with the URL.
|
||||
|
||||
### option: FetchRequest.get.headers
|
||||
- `headers` <[Object]<[string], [string]>>
|
||||
|
||||
|
|
@ -68,6 +78,11 @@ context cookies from the response. The method will automatically follow redirect
|
|||
|
||||
Target URL or Request to get all fetch parameters from.
|
||||
|
||||
### option: FetchRequest.post.params
|
||||
- `params` <[Object]<[string], [string]>>
|
||||
|
||||
Query parameters to be send with the URL.
|
||||
|
||||
### option: FetchRequest.post.headers
|
||||
- `headers` <[Object]<[string], [string]>>
|
||||
|
||||
|
|
|
|||
|
|
@ -17,13 +17,19 @@
|
|||
import * as api from '../../types/types';
|
||||
import { HeadersArray } from '../common/types';
|
||||
import * as channels from '../protocol/channels';
|
||||
import { assert, headersObjectToArray, isString } from '../utils/utils';
|
||||
import { assert, headersObjectToArray, isString, objectToArray } from '../utils/utils';
|
||||
import { BrowserContext } from './browserContext';
|
||||
import * as network from './network';
|
||||
import { RawHeaders } from './network';
|
||||
import { Headers } from './types';
|
||||
|
||||
export type FetchOptions = { method?: string, headers?: Headers, data?: string | Buffer, timeout?: number };
|
||||
export type FetchOptions = {
|
||||
params?: { [key: string]: string; },
|
||||
method?: string,
|
||||
headers?: Headers,
|
||||
data?: string | Buffer,
|
||||
timeout?: number
|
||||
};
|
||||
|
||||
export class FetchRequest implements api.FetchRequest {
|
||||
private _context: BrowserContext;
|
||||
|
|
@ -35,6 +41,7 @@ export class FetchRequest implements api.FetchRequest {
|
|||
async get(
|
||||
urlOrRequest: string | api.Request,
|
||||
options?: {
|
||||
params?: { [key: string]: string; };
|
||||
headers?: { [key: string]: string; };
|
||||
timeout?: number;
|
||||
}): Promise<FetchResponse> {
|
||||
|
|
@ -47,6 +54,7 @@ export class FetchRequest implements api.FetchRequest {
|
|||
async post(
|
||||
urlOrRequest: string | api.Request,
|
||||
options?: {
|
||||
params?: { [key: string]: string; };
|
||||
headers?: { [key: string]: string; };
|
||||
data?: string | Buffer;
|
||||
timeout?: number;
|
||||
|
|
@ -62,6 +70,7 @@ export class FetchRequest implements api.FetchRequest {
|
|||
const request: network.Request | undefined = (urlOrRequest instanceof network.Request) ? urlOrRequest as network.Request : undefined;
|
||||
assert(request || typeof urlOrRequest === 'string', 'First argument must be either URL string or Request');
|
||||
const url = request ? request.url() : urlOrRequest as string;
|
||||
const params = objectToArray(options.params);
|
||||
const method = options.method || request?.method();
|
||||
// Cannot call allHeaders() here as the request may be paused inside route handler.
|
||||
const headersObj = options.headers || request?.headers() ;
|
||||
|
|
@ -72,6 +81,7 @@ export class FetchRequest implements api.FetchRequest {
|
|||
const postData = (postDataBuffer ? postDataBuffer.toString('base64') : undefined);
|
||||
const result = await channel.fetch({
|
||||
url,
|
||||
params,
|
||||
method,
|
||||
headers,
|
||||
postData,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import { CallMetadata } from '../server/instrumentation';
|
|||
import { ArtifactDispatcher } from './artifactDispatcher';
|
||||
import { Artifact } from '../server/artifact';
|
||||
import { Request, Response } from '../server/network';
|
||||
import { headersArrayToObject } from '../utils/utils';
|
||||
import { arrayToObject, headersArrayToObject } from '../utils/utils';
|
||||
|
||||
export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channels.BrowserContextInitializer, channels.BrowserContextEvents> implements channels.BrowserContextChannel {
|
||||
private _context: BrowserContext;
|
||||
|
|
@ -110,6 +110,7 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
|
|||
async fetch(params: channels.BrowserContextFetchParams): Promise<channels.BrowserContextFetchResult> {
|
||||
const { fetchResponse, error } = await playwrightFetch(this._context, {
|
||||
url: params.url,
|
||||
params: arrayToObject(params.params),
|
||||
method: params.method,
|
||||
headers: params.headers ? headersArrayToObject(params.headers, false) : undefined,
|
||||
postData: params.postData ? Buffer.from(params.postData, 'base64') : undefined,
|
||||
|
|
|
|||
|
|
@ -857,12 +857,14 @@ export type BrowserContextExposeBindingOptions = {
|
|||
export type BrowserContextExposeBindingResult = void;
|
||||
export type BrowserContextFetchParams = {
|
||||
url: string,
|
||||
params?: NameValue[],
|
||||
method?: string,
|
||||
headers?: NameValue[],
|
||||
postData?: Binary,
|
||||
timeout?: number,
|
||||
};
|
||||
export type BrowserContextFetchOptions = {
|
||||
params?: NameValue[],
|
||||
method?: string,
|
||||
headers?: NameValue[],
|
||||
postData?: Binary,
|
||||
|
|
|
|||
|
|
@ -616,6 +616,9 @@ BrowserContext:
|
|||
fetch:
|
||||
parameters:
|
||||
url: string
|
||||
params:
|
||||
type: array?
|
||||
items: NameValue
|
||||
method: string?
|
||||
headers:
|
||||
type: array?
|
||||
|
|
|
|||
|
|
@ -394,6 +394,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
|
|||
});
|
||||
scheme.BrowserContextFetchParams = tObject({
|
||||
url: tString,
|
||||
params: tOptional(tArray(tType('NameValue'))),
|
||||
method: tOptional(tString),
|
||||
headers: tOptional(tArray(tType('NameValue'))),
|
||||
postData: tOptional(tBinary),
|
||||
|
|
|
|||
|
|
@ -66,7 +66,13 @@ export async function playwrightFetch(context: BrowserContext, params: types.Fet
|
|||
if (context._options.ignoreHTTPSErrors)
|
||||
options.rejectUnauthorized = false;
|
||||
|
||||
const fetchResponse = await sendRequest(context, new URL(params.url, context._options.baseURL), options, params.postData);
|
||||
const requestUrl = new URL(params.url, context._options.baseURL);
|
||||
if (params.params) {
|
||||
for (const [name, value] of Object.entries(params.params))
|
||||
requestUrl.searchParams.set(name, value);
|
||||
}
|
||||
|
||||
const fetchResponse = await sendRequest(context, requestUrl, options, params.postData);
|
||||
const fetchUid = context.storeFetchResponseBody(fetchResponse.body);
|
||||
return { fetchResponse: { ...fetchResponse, fetchUid } };
|
||||
} catch (e) {
|
||||
|
|
|
|||
|
|
@ -374,6 +374,7 @@ export type SetStorageState = {
|
|||
|
||||
export type FetchOptions = {
|
||||
url: string,
|
||||
params?: { [name: string]: string },
|
||||
method?: string,
|
||||
headers?: { [name: string]: string },
|
||||
postData?: Buffer,
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import { spawn } from 'child_process';
|
|||
import { getProxyForUrl } from 'proxy-from-env';
|
||||
import * as URL from 'url';
|
||||
import { getUbuntuVersionSync } from './ubuntuVersion';
|
||||
import { NameValue } from '../protocol/channels';
|
||||
|
||||
// `https-proxy-agent` v5 is written in TypeScript and exposes generated types.
|
||||
// However, as of June 2020, its types are generated with tsconfig that enables
|
||||
|
|
@ -288,6 +289,24 @@ class HashStream extends stream.Writable {
|
|||
}
|
||||
}
|
||||
|
||||
export function objectToArray(map?: { [key: string]: string }): NameValue[] | undefined {
|
||||
if (!map)
|
||||
return undefined;
|
||||
const result = [];
|
||||
for (const [name, value] of Object.entries(map))
|
||||
result.push({ name, value });
|
||||
return result;
|
||||
}
|
||||
|
||||
export function arrayToObject(array?: NameValue[]): { [key: string]: string } | undefined {
|
||||
if (!array)
|
||||
return undefined;
|
||||
const result: { [key: string]: string } = {};
|
||||
for (const {name, value} of array)
|
||||
result[name] = value;
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function calculateFileSha1(filename: string): Promise<string> {
|
||||
const hashStream = new HashStream();
|
||||
const stream = fs.createReadStream(filename);
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ it.afterAll(() => {
|
|||
http.globalAgent = prevAgent;
|
||||
});
|
||||
|
||||
it('should work', async ({context, server}) => {
|
||||
it('get should work', async ({context, server}) => {
|
||||
const response = await context.request.get(server.PREFIX + '/simple.json');
|
||||
expect(response.url()).toBe(server.PREFIX + '/simple.json');
|
||||
expect(response.status()).toBe(200);
|
||||
|
|
@ -128,6 +128,25 @@ it('should add session cookies to request', async ({context, server}) => {
|
|||
expect(req.headers.cookie).toEqual('username=John Doe');
|
||||
});
|
||||
|
||||
it('should support queryParams', async ({context, server}) => {
|
||||
let request;
|
||||
server.setRoute('/empty.html', (req, res) => {
|
||||
request = req;
|
||||
server.serveFile(req, res);
|
||||
});
|
||||
for (const method of ['get', 'post', 'fetch']) {
|
||||
await 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('should not add context cookie if cookie header passed as a parameter', async ({context, server}) => {
|
||||
await context.addCookies([{
|
||||
name: 'username',
|
||||
|
|
|
|||
15
types/types.d.ts
vendored
15
types/types.d.ts
vendored
|
|
@ -12646,6 +12646,11 @@ export interface FetchRequest {
|
|||
*/
|
||||
method?: string;
|
||||
|
||||
/**
|
||||
* Query parameters to be send with the URL.
|
||||
*/
|
||||
params?: { [key: string]: string; };
|
||||
|
||||
/**
|
||||
* Request timeout in milliseconds.
|
||||
*/
|
||||
|
|
@ -12664,6 +12669,11 @@ export interface FetchRequest {
|
|||
*/
|
||||
headers?: { [key: string]: string; };
|
||||
|
||||
/**
|
||||
* Query parameters to be send with the URL.
|
||||
*/
|
||||
params?: { [key: string]: string; };
|
||||
|
||||
/**
|
||||
* Request timeout in milliseconds.
|
||||
*/
|
||||
|
|
@ -12687,6 +12697,11 @@ export interface FetchRequest {
|
|||
*/
|
||||
headers?: { [key: string]: string; };
|
||||
|
||||
/**
|
||||
* Query parameters to be send with the URL.
|
||||
*/
|
||||
params?: { [key: string]: string; };
|
||||
|
||||
/**
|
||||
* Request timeout in milliseconds.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ class TestServer {
|
|||
request.on('data', chunk => body = Buffer.concat([body, chunk]));
|
||||
request.on('end', () => resolve(body));
|
||||
});
|
||||
const pathName = url.parse(request.url).path;
|
||||
const pathName = url.parse(request.url).pathname;
|
||||
this.debugServer(`request ${request.method} ${pathName}`);
|
||||
if (this._auths.has(pathName)) {
|
||||
const auth = this._auths.get(pathName);
|
||||
|
|
|
|||
Loading…
Reference in a new issue