feat: update protocol.yml file to include fetchFailOnStatusCode flag. Include flag for BrowserContext

This commit is contained in:
JacksonLei123 2025-01-20 12:03:40 -05:00
parent 40d8f2cb71
commit c1d510afaf
6 changed files with 84 additions and 34 deletions

View file

@ -21,6 +21,8 @@ Creates new instances of [APIRequestContext].
### option: APIRequest.newContext.extraHTTPHeaders = %%-context-option-extrahttpheaders-%% ### option: APIRequest.newContext.extraHTTPHeaders = %%-context-option-extrahttpheaders-%%
* since: v1.16 * since: v1.16
### option: APIRequest.newContext.fetchFailOnStatusCode = %%-context-option-fetchFailOnStatusCode-%%
### option: APIRequest.newContext.httpCredentials = %%-context-option-httpcredentials-%% ### option: APIRequest.newContext.httpCredentials = %%-context-option-httpcredentials-%%
* since: v1.16 * since: v1.16

View file

@ -620,9 +620,8 @@ A list of permissions to grant to all pages in this context. See
An object containing additional HTTP headers to be sent with every request. Defaults to none. An object containing additional HTTP headers to be sent with every request. Defaults to none.
## context-option-apirequest ## context-option-fetchFailOnStatusCode
- `apiRequest` <[Object]> - `fetchFailOnStatusCode` <[boolean]>
- `failOnStatusCode` <[boolean]>
An object containing an option to throw an error when API request returns status codes other than 2xx and 3xx. By default, response object is returned for all status codes. An object containing an option to throw an error when API request returns status codes other than 2xx and 3xx. By default, response object is returned for all status codes.
@ -971,6 +970,7 @@ between the same pixel in compared images, between zero (strict) and one (lax),
- %%-context-option-locale-%% - %%-context-option-locale-%%
- %%-context-option-permissions-%% - %%-context-option-permissions-%%
- %%-context-option-extrahttpheaders-%% - %%-context-option-extrahttpheaders-%%
- %%-context-option-fetchFailOnStatusCode-%%
- %%-context-option-offline-%% - %%-context-option-offline-%%
- %%-context-option-httpcredentials-%% - %%-context-option-httpcredentials-%%
- %%-context-option-colorscheme-%% - %%-context-option-colorscheme-%%

View file

@ -45,9 +45,7 @@ import { TLSSocket } from 'tls';
type FetchRequestOptions = { type FetchRequestOptions = {
userAgent: string; userAgent: string;
extraHTTPHeaders?: HeadersArray; extraHTTPHeaders?: HeadersArray;
apiRequest?: { fetchFailOnStatusCode?: boolean;
failOnStatusCode: boolean;
}
httpCredentials?: HTTPCredentials; httpCredentials?: HTTPCredentials;
proxy?: ProxySettings; proxy?: ProxySettings;
timeoutSettings: TimeoutSettings; timeoutSettings: TimeoutSettings;
@ -208,7 +206,7 @@ export abstract class APIRequestContext extends SdkObject {
}); });
const fetchUid = this._storeResponseBody(fetchResponse.body); const fetchUid = this._storeResponseBody(fetchResponse.body);
this.fetchLog.set(fetchUid, controller.metadata.log); this.fetchLog.set(fetchUid, controller.metadata.log);
const failOnStatusCode = params.failOnStatusCode !== undefined ? params.failOnStatusCode : !!defaults.apiRequest?.failOnStatusCode; const failOnStatusCode = params.failOnStatusCode !== undefined ? params.failOnStatusCode : !!defaults.fetchFailOnStatusCode;
if (failOnStatusCode && (fetchResponse.status < 200 || fetchResponse.status >= 400)) { if (failOnStatusCode && (fetchResponse.status < 200 || fetchResponse.status >= 400)) {
let responseText = ''; let responseText = '';
if (fetchResponse.body.byteLength) { if (fetchResponse.body.byteLength) {
@ -614,6 +612,7 @@ export class BrowserContextAPIRequestContext extends APIRequestContext {
return { return {
userAgent: this._context._options.userAgent || this._context._browser.userAgent(), userAgent: this._context._options.userAgent || this._context._browser.userAgent(),
extraHTTPHeaders: this._context._options.extraHTTPHeaders, extraHTTPHeaders: this._context._options.extraHTTPHeaders,
fetchFailOnStatusCode: this._context._options.fetchFailOnStatusCode,
httpCredentials: this._context._options.httpCredentials, httpCredentials: this._context._options.httpCredentials,
proxy: this._context._options.proxy || this._context._browser.options.proxy, proxy: this._context._options.proxy || this._context._browser.options.proxy,
timeoutSettings: this._context._timeoutSettings, timeoutSettings: this._context._timeoutSettings,
@ -665,7 +664,7 @@ export class GlobalAPIRequestContext extends APIRequestContext {
baseURL: options.baseURL, baseURL: options.baseURL,
userAgent: options.userAgent || getUserAgent(), userAgent: options.userAgent || getUserAgent(),
extraHTTPHeaders: options.extraHTTPHeaders, extraHTTPHeaders: options.extraHTTPHeaders,
apiRequest: { failOnStatusCode: !!options.apiRequest?.failOnStatusCode }, fetchFailOnStatusCode: !!options.fetchFailOnStatusCode,
ignoreHTTPSErrors: !!options.ignoreHTTPSErrors, ignoreHTTPSErrors: !!options.ignoreHTTPSErrors,
httpCredentials: options.httpCredentials, httpCredentials: options.httpCredentials,
clientCertificates: options.clientCertificates, clientCertificates: options.clientCertificates,

View file

@ -468,6 +468,7 @@ ContextOptions:
extraHTTPHeaders: extraHTTPHeaders:
type: array? type: array?
items: NameValue items: NameValue
fetchFailOnStatusCode: boolean?
offline: boolean? offline: boolean?
httpCredentials: httpCredentials:
type: object? type: object?
@ -693,6 +694,7 @@ Playwright:
extraHTTPHeaders: extraHTTPHeaders:
type: array? type: array?
items: NameValue items: NameValue
fetchFailOnStatusCode: boolean?
clientCertificates: clientCertificates:
type: array? type: array?
items: items:

View file

@ -0,0 +1,67 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { browserTest as it, expect } from '../config/browserTest';
it('should throw when fetchFailOnStatusCode is set to true inside BrowserContext options', async ({ browser, server }) => {
it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/34204' });
const context = await browser.newContext({ fetchFailOnStatusCode: true });
server.setRoute('/empty.html', (req, res) => {
res.writeHead(404, { 'Content-Length': 10, 'Content-Type': 'text/plain' });
res.end('Not found.');
});
const error = await context.request.fetch(server.EMPTY_PAGE).catch(e => e);
expect(error.message).toContain('404 Not Found');
await context.close();
});
it('should not throw when failOnStatusCode is set to false inside BrowserContext options', async ({ browser, server }) => {
it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/34204' });
const context = await browser.newContext({ fetchFailOnStatusCode: false });
server.setRoute('/empty.html', (req, res) => {
res.writeHead(404, { 'Content-Length': 10, 'Content-Type': 'text/plain' });
res.end('Not found.');
});
const error = await context.request.fetch(server.EMPTY_PAGE).catch(e => e);
expect(error.message).toBeUndefined();
await context.close();
});
it('should throw when fetchFailOnStatusCode is set to true inside browserType.launchPersistentContext options', async ({ browserType, server, createUserDataDir }) => {
it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/34204' });
const userDataDir = await createUserDataDir();
const context = await browserType.launchPersistentContext(userDataDir, { fetchFailOnStatusCode: true });
server.setRoute('/empty.html', (req, res) => {
res.writeHead(404, { 'Content-Length': 10, 'Content-Type': 'text/plain' });
res.end('Not found.');
});
const error = await context.request.fetch(server.EMPTY_PAGE).catch(e => e);
expect(error.message).toContain('404 Not Found');
await context.close();
});
it('should not throw when fetchFailOnStatusCode is set to false inside browserType.launchPersistentContext options', async ({ browserType, server, createUserDataDir }) => {
it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/34204' });
const userDataDir = await createUserDataDir();
const context = await browserType.launchPersistentContext(userDataDir, { fetchFailOnStatusCode: false });
server.setRoute('/empty.html', (req, res) => {
res.writeHead(404, { 'Content-Length': 10, 'Content-Type': 'text/plain' });
res.end('Not found.');
});
const error = await context.request.fetch(server.EMPTY_PAGE).catch(e => e);
expect(error.message).toBeUndefined();
await context.close();
});

View file

@ -537,46 +537,26 @@ it('should retry ECONNRESET', {
await request.dispose(); await request.dispose();
}); });
it('should throw when failOnStatusCode is set to true', async ({ playwright, server }) => { it('should throw when fetchFailOnStatusCode is set to true inside APIRequest context options', async ({ playwright, server }) => {
it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/34204' }); it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/34204' });
const request = await playwright.request.newContext({ apiRequest: { failOnStatusCode: true } }); const request = await playwright.request.newContext({ fetchFailOnStatusCode: true });
server.setRoute('/empty.html', (req, res) => { server.setRoute('/empty.html', (req, res) => {
res.writeHead(404, { 'Content-Length': 10, 'Content-Type': 'text/plain' }); res.writeHead(404, { 'Content-Length': 10, 'Content-Type': 'text/plain' });
res.end('Not found.'); res.end('Not found.');
}); });
const error = await request.fetch(server.EMPTY_PAGE).catch(e => e); const error = await request.fetch(server.EMPTY_PAGE).catch(e => e);
expect(error.message).toContain('404 Not Found'); expect(error.message).toContain('404 Not Found');
await request.dispose();
}); });
it('should throw when failOnStatusCode is set to true inside the fetch API call', async ({ playwright, server }) => { it('should not throw when fetchFailOnStatusCode is set to false inside APIRequest context options', async ({ playwright, server }) => {
it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/34204' }); it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/34204' });
const request = await playwright.request.newContext({ apiRequest: { failOnStatusCode: false } }); const request = await playwright.request.newContext({ fetchFailOnStatusCode: false });
server.setRoute('/empty.html', (req, res) => {
res.writeHead(404, { 'Content-Length': 10, 'Content-Type': 'text/plain' });
res.end('Not found.');
});
const error = await request.fetch(server.EMPTY_PAGE, { failOnStatusCode: true }).catch(e => e);
expect(error.message).toContain('404 Not Found');
});
it('should not throw when failOnStatusCode is set to false', async ({ playwright, server }) => {
it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/34204' });
const request = await playwright.request.newContext({ apiRequest: { failOnStatusCode: false } });
server.setRoute('/empty.html', (req, res) => { server.setRoute('/empty.html', (req, res) => {
res.writeHead(404, { 'Content-Length': 10, 'Content-Type': 'text/plain' }); res.writeHead(404, { 'Content-Length': 10, 'Content-Type': 'text/plain' });
res.end('Not found.'); res.end('Not found.');
}); });
const error = await request.fetch(server.EMPTY_PAGE).catch(e => e); const error = await request.fetch(server.EMPTY_PAGE).catch(e => e);
expect(error.message).toBeUndefined(); expect(error.message).toBeUndefined();
}); await request.dispose();
it('should not throw when failOnStatusCode is set to false inside the fetch API call', async ({ playwright, server }) => {
it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/34204' });
const request = await playwright.request.newContext({ apiRequest: { failOnStatusCode: true } });
server.setRoute('/empty.html', (req, res) => {
res.writeHead(404, { 'Content-Length': 10, 'Content-Type': 'text/plain' });
res.end('Not found.');
});
const error = await request.fetch(server.EMPTY_PAGE, { failOnStatusCode: false }).catch(e => e);
expect(error.message).toBeUndefined();
}); });