mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
feat: added follow and redirect arguments to fetch (#17033)
This commit is contained in:
parent
47b9595b95
commit
17b203affb
@ -161,6 +161,8 @@ context cookies from the response. The method will automatically follow redirect
|
||||
* since: v1.16
|
||||
### option: APIRequestContext.delete.ignoreHTTPSErrors = %%-js-python-fetch-option-ignorehttpserrors-%%
|
||||
* since: v1.16
|
||||
### option: APIRequestContext.delete.maxRedirects = %%-js-python-fetch-option-maxredirects-%%
|
||||
* since: v1.26
|
||||
|
||||
## async method: APIRequestContext.dispose
|
||||
* since: v1.16
|
||||
@ -214,6 +216,8 @@ If set changes the fetch method (e.g. [PUT](https://developer.mozilla.org/en-US/
|
||||
* since: v1.16
|
||||
### option: APIRequestContext.fetch.ignoreHTTPSErrors = %%-js-python-fetch-option-ignorehttpserrors-%%
|
||||
* since: v1.16
|
||||
### option: APIRequestContext.fetch.maxRedirects = %%-js-python-fetch-option-maxredirects-%%
|
||||
* since: v1.26
|
||||
|
||||
## async method: APIRequestContext.get
|
||||
* since: v1.16
|
||||
@ -239,6 +243,8 @@ context cookies from the response. The method will automatically follow redirect
|
||||
* since: v1.16
|
||||
### option: APIRequestContext.get.ignoreHTTPSErrors = %%-js-python-fetch-option-ignorehttpserrors-%%
|
||||
* since: v1.16
|
||||
### option: APIRequestContext.get.maxRedirects = %%-js-python-fetch-option-maxredirects-%%
|
||||
* since: v1.26
|
||||
|
||||
## async method: APIRequestContext.head
|
||||
* since: v1.16
|
||||
@ -264,6 +270,8 @@ context cookies from the response. The method will automatically follow redirect
|
||||
* since: v1.16
|
||||
### option: APIRequestContext.head.ignoreHTTPSErrors = %%-js-python-fetch-option-ignorehttpserrors-%%
|
||||
* since: v1.16
|
||||
### option: APIRequestContext.head.maxRedirects = %%-js-python-fetch-option-maxredirects-%%
|
||||
* since: v1.26
|
||||
|
||||
## async method: APIRequestContext.patch
|
||||
* since: v1.16
|
||||
@ -299,6 +307,8 @@ context cookies from the response. The method will automatically follow redirect
|
||||
* since: v1.16
|
||||
### option: APIRequestContext.patch.ignoreHTTPSErrors = %%-js-python-fetch-option-ignorehttpserrors-%%
|
||||
* since: v1.16
|
||||
### option: APIRequestContext.patch.maxRedirects = %%-js-python-fetch-option-maxredirects-%%
|
||||
* since: v1.26
|
||||
|
||||
## async method: APIRequestContext.post
|
||||
* since: v1.16
|
||||
@ -334,6 +344,8 @@ context cookies from the response. The method will automatically follow redirect
|
||||
* since: v1.16
|
||||
### option: APIRequestContext.post.ignoreHTTPSErrors = %%-js-python-fetch-option-ignorehttpserrors-%%
|
||||
* since: v1.16
|
||||
### option: APIRequestContext.post.maxRedirects = %%-js-python-fetch-option-maxredirects-%%
|
||||
* since: v1.26
|
||||
|
||||
## async method: APIRequestContext.put
|
||||
* since: v1.16
|
||||
@ -369,6 +381,8 @@ context cookies from the response. The method will automatically follow redirect
|
||||
* since: v1.16
|
||||
### option: APIRequestContext.put.ignoreHTTPSErrors = %%-js-python-fetch-option-ignorehttpserrors-%%
|
||||
* since: v1.16
|
||||
### option: APIRequestContext.put.maxRedirects = %%-js-python-fetch-option-maxredirects-%%
|
||||
* since: v1.26
|
||||
|
||||
## async method: APIRequestContext.storageState
|
||||
* since: v1.16
|
||||
|
||||
@ -398,6 +398,12 @@ set to `application/octet-stream` if not explicitly set.
|
||||
|
||||
Whether to ignore HTTPS errors when sending network requests. Defaults to `false`.
|
||||
|
||||
## js-python-fetch-option-maxredirects
|
||||
* langs: js
|
||||
- `maxRedirects` <[int]>
|
||||
|
||||
Maximum number of request allowed redirects. Defaults to `20`. Pass `0` to disable automatic follow.
|
||||
|
||||
## evaluate-expression
|
||||
- `expression` <[string]>
|
||||
|
||||
|
||||
@ -42,6 +42,7 @@ export type FetchOptions = {
|
||||
timeout?: number,
|
||||
failOnStatusCode?: boolean,
|
||||
ignoreHTTPSErrors?: boolean,
|
||||
maxRedirects?: number,
|
||||
};
|
||||
|
||||
type NewContextOptions = Omit<channels.PlaywrightNewRequestOptions, 'extraHTTPHeaders' | 'storageState'> & {
|
||||
@ -146,9 +147,11 @@ export class APIRequestContext extends ChannelOwner<channels.APIRequestContextCh
|
||||
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');
|
||||
assert((options.data === undefined ? 0 : 1) + (options.form === undefined ? 0 : 1) + (options.multipart === undefined ? 0 : 1) <= 1, `Only one of 'data', 'form' or 'multipart' can be specified`);
|
||||
assert(options.maxRedirects === undefined || options.maxRedirects >= 0, `'maxRedirects' should be greater than or equal to '0'`);
|
||||
const url = request ? request.url() : urlOrRequest as string;
|
||||
const params = objectToArray(options.params);
|
||||
const method = options.method || request?.method();
|
||||
const maxRedirects = options.maxRedirects;
|
||||
// Cannot call allHeaders() here as the request may be paused inside route handler.
|
||||
const headersObj = options.headers || request?.headers() ;
|
||||
const headers = headersObj ? headersObjectToArray(headersObj) : undefined;
|
||||
@ -201,6 +204,7 @@ export class APIRequestContext extends ChannelOwner<channels.APIRequestContextCh
|
||||
timeout: options.timeout,
|
||||
failOnStatusCode: options.failOnStatusCode,
|
||||
ignoreHTTPSErrors: options.ignoreHTTPSErrors,
|
||||
maxRedirects: maxRedirects,
|
||||
});
|
||||
return new APIResponse(this, result.response);
|
||||
});
|
||||
|
||||
@ -310,6 +310,7 @@ export type APIRequestContextFetchParams = {
|
||||
timeout?: number,
|
||||
failOnStatusCode?: boolean,
|
||||
ignoreHTTPSErrors?: boolean,
|
||||
maxRedirects?: number,
|
||||
};
|
||||
export type APIRequestContextFetchOptions = {
|
||||
params?: NameValue[],
|
||||
@ -322,6 +323,7 @@ export type APIRequestContextFetchOptions = {
|
||||
timeout?: number,
|
||||
failOnStatusCode?: boolean,
|
||||
ignoreHTTPSErrors?: boolean,
|
||||
maxRedirects?: number,
|
||||
};
|
||||
export type APIRequestContextFetchResult = {
|
||||
response: APIResponse,
|
||||
|
||||
@ -284,6 +284,7 @@ APIRequestContext:
|
||||
timeout: number?
|
||||
failOnStatusCode: boolean?
|
||||
ignoreHTTPSErrors: boolean?
|
||||
maxRedirects: number?
|
||||
returns:
|
||||
response: APIResponse
|
||||
|
||||
|
||||
@ -171,6 +171,7 @@ scheme.APIRequestContextFetchParams = tObject({
|
||||
timeout: tOptional(tNumber),
|
||||
failOnStatusCode: tOptional(tBoolean),
|
||||
ignoreHTTPSErrors: tOptional(tBoolean),
|
||||
maxRedirects: tOptional(tNumber),
|
||||
});
|
||||
scheme.APIRequestContextFetchResult = tObject({
|
||||
response: tType('APIResponse'),
|
||||
|
||||
@ -162,7 +162,7 @@ export abstract class APIRequestContext extends SdkObject {
|
||||
method,
|
||||
headers,
|
||||
agent,
|
||||
maxRedirects: 20,
|
||||
maxRedirects: params.maxRedirects === 0 ? -1 : params.maxRedirects === undefined ? 20 : params.maxRedirects,
|
||||
timeout,
|
||||
deadline
|
||||
};
|
||||
@ -268,7 +268,7 @@ export abstract class APIRequestContext extends SdkObject {
|
||||
if (cookies.length)
|
||||
await this._addCookies(cookies);
|
||||
|
||||
if (redirectStatus.includes(response.statusCode!)) {
|
||||
if (redirectStatus.includes(response.statusCode!) && options.maxRedirects >= 0) {
|
||||
if (!options.maxRedirects) {
|
||||
reject(new Error('Max redirect count exceeded'));
|
||||
request.destroy();
|
||||
|
||||
35
packages/playwright-core/types/types.d.ts
vendored
35
packages/playwright-core/types/types.d.ts
vendored
@ -12667,6 +12667,11 @@ export interface APIRequestContext {
|
||||
*/
|
||||
ignoreHTTPSErrors?: boolean;
|
||||
|
||||
/**
|
||||
* Maximum number of request allowed redirects. Defaults to `20`. Pass `0` to disable automatic follow.
|
||||
*/
|
||||
maxRedirects?: number;
|
||||
|
||||
/**
|
||||
* Provides an object that will be serialized as html form using `multipart/form-data` encoding and sent as this request
|
||||
* body. If this parameter is specified `content-type` header will be set to `multipart/form-data` unless explicitly
|
||||
@ -12747,6 +12752,11 @@ export interface APIRequestContext {
|
||||
*/
|
||||
ignoreHTTPSErrors?: boolean;
|
||||
|
||||
/**
|
||||
* Maximum number of request allowed redirects. Defaults to `20`. Pass `0` to disable automatic follow.
|
||||
*/
|
||||
maxRedirects?: number;
|
||||
|
||||
/**
|
||||
* If set changes the fetch method (e.g. [PUT](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT) or
|
||||
* [POST](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST)). If not specified, GET method is used.
|
||||
@ -12810,6 +12820,11 @@ export interface APIRequestContext {
|
||||
*/
|
||||
ignoreHTTPSErrors?: boolean;
|
||||
|
||||
/**
|
||||
* Maximum number of request allowed redirects. Defaults to `20`. Pass `0` to disable automatic follow.
|
||||
*/
|
||||
maxRedirects?: number;
|
||||
|
||||
/**
|
||||
* Query parameters to be sent with the URL.
|
||||
*/
|
||||
@ -12844,6 +12859,11 @@ export interface APIRequestContext {
|
||||
*/
|
||||
ignoreHTTPSErrors?: boolean;
|
||||
|
||||
/**
|
||||
* Maximum number of request allowed redirects. Defaults to `20`. Pass `0` to disable automatic follow.
|
||||
*/
|
||||
maxRedirects?: number;
|
||||
|
||||
/**
|
||||
* Query parameters to be sent with the URL.
|
||||
*/
|
||||
@ -12892,6 +12912,11 @@ export interface APIRequestContext {
|
||||
*/
|
||||
ignoreHTTPSErrors?: boolean;
|
||||
|
||||
/**
|
||||
* Maximum number of request allowed redirects. Defaults to `20`. Pass `0` to disable automatic follow.
|
||||
*/
|
||||
maxRedirects?: number;
|
||||
|
||||
/**
|
||||
* Provides an object that will be serialized as html form using `multipart/form-data` encoding and sent as this request
|
||||
* body. If this parameter is specified `content-type` header will be set to `multipart/form-data` unless explicitly
|
||||
@ -12963,6 +12988,11 @@ export interface APIRequestContext {
|
||||
*/
|
||||
ignoreHTTPSErrors?: boolean;
|
||||
|
||||
/**
|
||||
* Maximum number of request allowed redirects. Defaults to `20`. Pass `0` to disable automatic follow.
|
||||
*/
|
||||
maxRedirects?: number;
|
||||
|
||||
/**
|
||||
* Provides an object that will be serialized as html form using `multipart/form-data` encoding and sent as this request
|
||||
* body. If this parameter is specified `content-type` header will be set to `multipart/form-data` unless explicitly
|
||||
@ -13034,6 +13064,11 @@ export interface APIRequestContext {
|
||||
*/
|
||||
ignoreHTTPSErrors?: boolean;
|
||||
|
||||
/**
|
||||
* Maximum number of request allowed redirects. Defaults to `20`. Pass `0` to disable automatic follow.
|
||||
*/
|
||||
maxRedirects?: number;
|
||||
|
||||
/**
|
||||
* Provides an object that will be serialized as html form using `multipart/form-data` encoding and sent as this request
|
||||
* body. If this parameter is specified `content-type` header will be set to `multipart/form-data` unless explicitly
|
||||
|
||||
@ -383,3 +383,34 @@ it('should return body for failing requests', async ({ playwright, server }) =>
|
||||
}
|
||||
await request.dispose();
|
||||
});
|
||||
|
||||
it('should throw an error when maxRedirects is exceeded', async ({ playwright, server }) => {
|
||||
server.setRedirect('/a/redirect1', '/b/c/redirect2');
|
||||
server.setRedirect('/b/c/redirect2', '/b/c/redirect3');
|
||||
server.setRedirect('/b/c/redirect3', '/b/c/redirect4');
|
||||
server.setRedirect('/b/c/redirect4', '/simple.json');
|
||||
|
||||
const request = await playwright.request.newContext();
|
||||
for (const method of ['GET', 'PUT', 'POST', 'OPTIONS', 'HEAD', 'PATCH'])
|
||||
for (const maxRedirects of [1, 2, 3]) await expect(async () => request.fetch(`${server.PREFIX}/a/redirect1`, { method: method, maxRedirects: maxRedirects })).rejects.toThrow('Max redirect count exceeded');
|
||||
});
|
||||
|
||||
it('should not follow redirects when maxRedirects is set to 0', async ({ playwright, server }) => {
|
||||
server.setRedirect('/a/redirect1', '/b/c/redirect2');
|
||||
server.setRedirect('/b/c/redirect2', '/simple.json');
|
||||
|
||||
const request = await playwright.request.newContext();
|
||||
for (const method of ['GET', 'PUT', 'POST', 'OPTIONS', 'HEAD', 'PATCH']){
|
||||
const response = await request.fetch(`${server.PREFIX}/a/redirect1`, { method: method, maxRedirects: 0 });
|
||||
expect(response.headers()['location']).toBe('/b/c/redirect2');
|
||||
expect(response.status()).toBe(302);
|
||||
}
|
||||
});
|
||||
|
||||
it('should throw an error when maxRedirects is less than 0', async ({ playwright, server }) => {
|
||||
server.setRedirect('/a/redirect1', '/b/c/redirect2');
|
||||
server.setRedirect('/b/c/redirect2', '/simple.json');
|
||||
|
||||
const request = await playwright.request.newContext();
|
||||
for (const method of ['GET', 'PUT', 'POST', 'OPTIONS', 'HEAD', 'PATCH']) await expect(async () => request.fetch(`${server.PREFIX}/a/redirect1`, { method: method, maxRedirects: -1 })).rejects.toThrow(`'maxRedirects' should be greater than or equal to '0'`);
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user