api(route): allow fulfilling with a file path (#1301)

This commit is contained in:
Dmitry Gozman 2020-03-09 16:12:00 -07:00 committed by GitHub
parent cf46f1b056
commit eb2ca70955
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 45 additions and 10 deletions

View File

@ -3377,8 +3377,9 @@ page.on('requestfailed', request => {
- `response` <[Object]> Response that will fulfill this request - `response` <[Object]> Response that will fulfill this request
- `status` <[number]> Response status code, defaults to `200`. - `status` <[number]> Response status code, defaults to `200`.
- `headers` <[Object]> Optional response headers. Header values will be converted to a string. - `headers` <[Object]> Optional response headers. Header values will be converted to a string.
- `contentType` <[string]> If set, equals to setting `Content-Type` response header - `contentType` <[string]> If set, equals to setting `Content-Type` response header.
- `body` <[string]|[Buffer]> Optional response body - `body` <[string]|[Buffer]> Optional response body.
- `path` <[string]> Optional file path to respond with. The content type will be inferred from file extension. If `path` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd).
- returns: <[Promise]> - returns: <[Promise]>
Fulfills request with given response. To use this, request interception should Fulfills request with given response. To use this, request interception should
@ -3397,8 +3398,11 @@ await page.route('**/*', request => {
}); });
``` ```
> **NOTE** Mocking responses for dataURL requests is not supported. An example of serving static file:
> Calling `request.fulfill` for a dataURL request is a noop.
```js
await page.route('**/xhr_endpoint', request => request.fulfill({ path: 'mock_data.json' }));
```
#### request.headers() #### request.headers()
- returns: <[Object]> An object with HTTP headers associated with the request. All header names are lower-case. - returns: <[Object]> An object with HTTP headers associated with the request. All header names are lower-case.

View File

@ -267,7 +267,7 @@ class InterceptableRequest implements network.RequestDelegate {
}); });
} }
async fulfill(response: { status: number; headers: network.Headers; contentType: string; body: (string | platform.BufferType); }) { async fulfill(response: network.FulfillResponse) {
const responseBody = response.body && helper.isString(response.body) ? platform.Buffer.from(response.body) : (response.body || null); const responseBody = response.body && helper.isString(response.body) ? platform.Buffer.from(response.body) : (response.body || null);
const responseHeaders: { [s: string]: string; } = {}; const responseHeaders: { [s: string]: string; } = {};

View File

@ -174,7 +174,7 @@ class InterceptableRequest implements network.RequestDelegate {
}); });
} }
async fulfill(response: { status: number; headers: network.Headers; contentType: string; body: (string | platform.BufferType); }) { async fulfill(response: network.FulfillResponse) {
const responseBody = response.body && helper.isString(response.body) ? platform.Buffer.from(response.body) : (response.body || null); const responseBody = response.body && helper.isString(response.body) ? platform.Buffer.from(response.body) : (response.body || null);
const responseHeaders: { [s: string]: string; } = {}; const responseHeaders: { [s: string]: string; } = {};

View File

@ -202,10 +202,18 @@ export class Request {
await this._delegate.abort(errorCode); await this._delegate.abort(errorCode);
} }
async fulfill(response: { status: number; headers: Headers; contentType: string; body: (string | platform.BufferType); }) { // Mocking responses for dataURL requests is not currently supported. async fulfill(response: FulfillResponse & { path?: string }) {
assert(this._delegate, 'Request Interception is not enabled!'); assert(this._delegate, 'Request Interception is not enabled!');
assert(!this._interceptionHandled, 'Request is already handled!'); assert(!this._interceptionHandled, 'Request is already handled!');
this._interceptionHandled = true; this._interceptionHandled = true;
if (response.path) {
response = {
status: response.status,
headers: response.headers,
contentType: platform.getMimeType(response.path),
body: await platform.readFileBuffer(response.path)
};
}
await this._delegate.fulfill(response); await this._delegate.fulfill(response);
} }
@ -304,9 +312,16 @@ export class Response {
} }
} }
export type FulfillResponse = {
status?: number,
headers?: Headers,
contentType?: string,
body?: string | platform.BufferType,
};
export interface RequestDelegate { export interface RequestDelegate {
abort(errorCode: string): Promise<void>; abort(errorCode: string): Promise<void>;
fulfill(response: { status: number; headers: Headers; contentType: string; body: (string | platform.BufferType); }): Promise<void>; fulfill(response: FulfillResponse): Promise<void>;
continue(overrides: { method?: string; headers?: Headers; postData?: string; }): Promise<void>; continue(overrides: { method?: string; headers?: Headers; postData?: string; }): Promise<void>;
} }

View File

@ -187,6 +187,11 @@ export async function readFileAsync(file: string, encoding: string): Promise<str
return await promisify(nodeFS.readFile)(file, encoding); return await promisify(nodeFS.readFile)(file, encoding);
} }
export async function readFileBuffer(file: string): Promise<BufferType> {
assertFileAccess();
return await promisify(nodeFS.readFile)(file);
}
export async function writeFileAsync(file: string, data: any) { export async function writeFileAsync(file: string, data: any) {
assertFileAccess(); assertFileAccess();
return await promisify(nodeFS.writeFile)(file, data); return await promisify(nodeFS.writeFile)(file, data);

View File

@ -65,7 +65,7 @@ export class WKInterceptableRequest implements network.RequestDelegate {
}); });
} }
async fulfill(response: { status: number; headers: network.Headers; contentType: string; body: (string | platform.BufferType); }) { async fulfill(response: network.FulfillResponse) {
await this._interceptedPromise; await this._interceptedPromise;
const base64Encoded = !!response.body && !helper.isString(response.body); const base64Encoded = !!response.body && !helper.isString(response.body);

View File

@ -468,6 +468,17 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
const img = await page.$('img'); const img = await page.$('img');
expect(await img.screenshot()).toBeGolden('mock-binary-response.png'); expect(await img.screenshot()).toBeGolden('mock-binary-response.png');
}); });
it('should work with file path', async({page, server}) => {
await page.route('**/*', request => request.fulfill({ contentType: 'shouldBeIgnored', path: path.join(__dirname, 'assets', 'pptr.png') }));
await page.evaluate(PREFIX => {
const img = document.createElement('img');
img.src = PREFIX + '/does-not-exist.png';
document.body.appendChild(img);
return new Promise(fulfill => img.onload = fulfill);
}, server.PREFIX);
const img = await page.$('img');
expect(await img.screenshot()).toBeGolden('mock-binary-response.png');
});
it('should stringify intercepted request response headers', async({page, server}) => { it('should stringify intercepted request response headers', async({page, server}) => {
await page.route('**/*', request => { await page.route('**/*', request => {
request.fulfill({ request.fulfill({