Skip to content

Commit e3da3eb

Browse files
authored
feat(har): do not expose HAR types, remove HARResponse fulfill (#14992)
1 parent eb87966 commit e3da3eb

File tree

6 files changed

+22
-46
lines changed

6 files changed

+22
-46
lines changed

docs/src/api/class-route.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -484,9 +484,9 @@ File path to respond with. The content type will be inferred from file extension
484484
is resolved relative to the current working directory.
485485

486486
### option: Route.fulfill.response
487-
- `response` <[APIResponse]|[HARResponse]>
487+
- `response` <[APIResponse]>
488488

489-
[APIResponse] or [HARResponse] to fulfill route's request with. Individual fields of the response (such as headers) can be overridden using fulfill options.
489+
[APIResponse] to fulfill route's request with. Individual fields of the response (such as headers) can be overridden using fulfill options.
490490

491491
## method: Route.request
492492
- returns: <[Request]>

packages/playwright-core/src/client/network.ts

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { Frame } from './frame';
2121
import type { Headers, RemoteAddr, SecurityDetails, WaitForEventOptions } from './types';
2222
import fs from 'fs';
2323
import { mime } from '../utilsBundle';
24-
import { isString, headersObjectToArray, headersArrayToObject } from '../utils';
24+
import { isString, headersObjectToArray } from '../utils';
2525
import { ManualPromise } from '../utils/manualPromise';
2626
import { Events } from './events';
2727
import type { Page } from './page';
@@ -31,7 +31,6 @@ import type { HeadersArray, URLMatch } from '../common/types';
3131
import { urlMatches } from '../common/netUtils';
3232
import { MultiMap } from '../utils/multimap';
3333
import { APIResponse } from './fetch';
34-
import type { HARResponse } from '../../types/har';
3534

3635
export type NetworkCookie = {
3736
name: string,
@@ -292,17 +291,17 @@ export class Route extends ChannelOwner<channels.RouteChannel> implements api.Ro
292291
this._reportHandled(true);
293292
}
294293

295-
async fulfill(options: { response?: api.APIResponse | HARResponse, status?: number, headers?: Headers, contentType?: string, body?: string | Buffer, path?: string } = {}) {
294+
async fulfill(options: { response?: api.APIResponse, status?: number, headers?: Headers, contentType?: string, body?: string | Buffer, path?: string } = {}) {
296295
this._checkNotHandled();
297296
await this._wrapApiCall(async () => {
298297
await this._innerFulfill(options);
299298
this._reportHandled(true);
300299
});
301300
}
302301

303-
private async _innerFulfill(options: { response?: api.APIResponse | HARResponse, status?: number, headers?: Headers, contentType?: string, body?: string | Buffer, path?: string } = {}): Promise<void> {
302+
private async _innerFulfill(options: { response?: api.APIResponse, status?: number, headers?: Headers, contentType?: string, body?: string | Buffer, path?: string } = {}): Promise<void> {
304303
let fetchResponseUid;
305-
let { status: statusOption, headers: headersOption, body, contentType } = options;
304+
let { status: statusOption, headers: headersOption, body } = options;
306305

307306
if (options.response instanceof APIResponse) {
308307
statusOption ??= options.response.status();
@@ -313,16 +312,6 @@ export class Route extends ChannelOwner<channels.RouteChannel> implements api.Ro
313312
else
314313
body = await options.response.body();
315314
}
316-
} else if (options.response) {
317-
const harResponse = options.response as HARResponse;
318-
statusOption ??= harResponse.status;
319-
headersOption ??= headersArrayToObject(harResponse.headers, false);
320-
if (body === undefined && options.path === undefined) {
321-
body = harResponse.content.text;
322-
contentType ??= harResponse.content.mimeType;
323-
if (body !== undefined && harResponse.content.encoding === 'base64')
324-
body = Buffer.from(body, 'base64');
325-
}
326315
}
327316

328317
let isBase64 = false;
@@ -344,8 +333,8 @@ export class Route extends ChannelOwner<channels.RouteChannel> implements api.Ro
344333
const headers: Headers = {};
345334
for (const header of Object.keys(headersOption || {}))
346335
headers[header.toLowerCase()] = String(headersOption![header]);
347-
if (contentType)
348-
headers['content-type'] = String(contentType);
336+
if (options.contentType)
337+
headers['content-type'] = String(options.contentType);
349338
else if (options.path)
350339
headers['content-type'] = mime.getType(options.path) || 'application/octet-stream';
351340
if (length && !('content-length' in headers))

packages/playwright-core/src/server/dispatchers/localUtilsDispatcher.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import type { DispatcherScope } from './dispatcher';
2424
import { Dispatcher } from './dispatcher';
2525
import { yazl, yauzl } from '../../zipBundle';
2626
import { ZipFile } from '../../utils/zipFile';
27-
import type { HAREntry, HARFile } from '../../../types/types';
27+
import type { HAREntry, HARFile } from '../../../types/har';
2828
import type { HeadersArray } from '../types';
2929

3030
export class LocalUtilsDispatcher extends Dispatcher<{ guid: string }, channels.LocalUtilsChannel> implements channels.LocalUtilsChannel {

packages/playwright-core/types/types.d.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ import { Readable } from 'stream';
2222
import { ReadStream } from 'fs';
2323
import { Serializable, EvaluationArgument, PageFunction, PageFunctionOn, SmartHandle, ElementHandleForTag, BindingSource } from 'playwright-core/types/structs';
2424

25-
export * from 'playwright-core/types/har';
26-
2725
type PageWaitForSelectorOptionsNotHidden = PageWaitForSelectorOptions & {
2826
state?: 'visible'|'attached';
2927
};
@@ -15457,10 +15455,10 @@ export interface Route {
1545715455
path?: string;
1545815456

1545915457
/**
15460-
* [APIResponse] or [HARResponse] to fulfill route's request with. Individual fields of the response (such as headers) can
15461-
* be overridden using fulfill options.
15458+
* [APIResponse] to fulfill route's request with. Individual fields of the response (such as headers) can be overridden
15459+
* using fulfill options.
1546215460
*/
15463-
response?: APIResponse|HARResponse;
15461+
response?: APIResponse;
1546415462

1546515463
/**
1546615464
* Response status code, defaults to `200`.

tests/page/page-request-fulfill.spec.ts

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
import { test as base, expect } from './pageTest';
1919
import fs from 'fs';
20-
import type { HARFile } from '@playwright/test';
20+
import type { HARFile, HARResponse } from 'playwright-core/types/har';
2121

2222
const it = base.extend<{
2323
// We access test servers at 10.0.2.2 from inside the browser on Android,
@@ -330,7 +330,14 @@ it('should fulfill with har response', async ({ page, isAndroid, asset }) => {
330330
const har = JSON.parse(await fs.promises.readFile(harPath, 'utf-8')) as HARFile;
331331
await page.route('**/*', async route => {
332332
const response = findResponse(har, route.request().url());
333-
await route.fulfill({ response });
333+
const headers = {};
334+
for (const { name, value } of response.headers)
335+
headers[name] = value;
336+
await route.fulfill({
337+
status: response.status,
338+
headers,
339+
body: Buffer.from(response.content.text || '', (response.content.encoding as 'base64' | undefined) || 'utf-8'),
340+
});
334341
});
335342
await page.goto('http://no.playwright/');
336343
// HAR contains a redirect for the script.
@@ -339,23 +346,7 @@ it('should fulfill with har response', async ({ page, isAndroid, asset }) => {
339346
await expect(page.locator('body')).toHaveCSS('background-color', 'rgb(0, 255, 255)');
340347
});
341348

342-
it('should override status when fulfill with response from har', async ({ page, isAndroid, asset }) => {
343-
it.fixme(isAndroid);
344-
345-
const harPath = asset('har-fulfill.har');
346-
const har = JSON.parse(await fs.promises.readFile(harPath, 'utf-8')) as HARFile;
347-
await page.route('**/*', async route => {
348-
const response = findResponse(har, route.request().url());
349-
await route.fulfill({ response, status: route.request().url().endsWith('.css') ? 404 : undefined });
350-
});
351-
await page.goto('http://no.playwright/');
352-
// Script should work.
353-
expect(await page.evaluate('window.value')).toBe('foo');
354-
// 404 should fail the CSS and styles should not apply.
355-
await expect(page.locator('body')).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)');
356-
});
357-
358-
function findResponse(har: HARFile, url: string) {
349+
function findResponse(har: HARFile, url: string): HARResponse {
359350
let entry;
360351
const originalUrl = url;
361352
while (url.trim()) {

utils/generate_types/overrides.d.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ import { Readable } from 'stream';
2121
import { ReadStream } from 'fs';
2222
import { Serializable, EvaluationArgument, PageFunction, PageFunctionOn, SmartHandle, ElementHandleForTag, BindingSource } from 'playwright-core/types/structs';
2323

24-
export * from 'playwright-core/types/har';
25-
2624
type PageWaitForSelectorOptionsNotHidden = PageWaitForSelectorOptions & {
2725
state?: 'visible'|'attached';
2826
};

0 commit comments

Comments
 (0)