mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore: remove protocol recordHar option in favor of explicit harStart (#36030)
This commit is contained in:
parent
8168dc3496
commit
28e925c001
@ -259,6 +259,7 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel> i
|
||||
const result = await this._channel.launchBrowser(contextOptions);
|
||||
const context = BrowserContext.from(result.context) as BrowserContext;
|
||||
context._setOptions(contextOptions, {});
|
||||
await context._initializeHarFromOptions(options.recordHar);
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
@ -84,6 +84,7 @@ export class Browser extends ChannelOwner<channels.BrowserChannel> implements ap
|
||||
const contextOptions = await prepareBrowserContextParams(this._platform, options);
|
||||
const response = forReuse ? await this._channel.newContextForReuse(contextOptions) : await this._channel.newContext(contextOptions);
|
||||
const context = BrowserContext.from(response.context);
|
||||
await context._initializeHarFromOptions(options.recordHar);
|
||||
await this._browserType._didCreateContext(context, contextOptions, this._options, options.logger || this._logger);
|
||||
return context;
|
||||
}
|
||||
|
||||
@ -156,10 +156,19 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
||||
]));
|
||||
}
|
||||
|
||||
async _initializeHarFromOptions(recordHar: BrowserContextOptions['recordHar']) {
|
||||
if (!recordHar)
|
||||
return;
|
||||
const defaultContent = recordHar.path.endsWith('.zip') ? 'attach' : 'embed';
|
||||
await this._recordIntoHAR(recordHar.path, null, {
|
||||
url: recordHar.urlFilter,
|
||||
updateContent: recordHar.content ?? (recordHar.omitContent ? 'omit' : defaultContent),
|
||||
updateMode: recordHar.mode ?? 'full',
|
||||
});
|
||||
}
|
||||
|
||||
_setOptions(contextOptions: channels.BrowserNewContextParams, browserOptions: LaunchOptions) {
|
||||
this._options = contextOptions;
|
||||
if (this._options.recordHar)
|
||||
this._harRecorders.set('', { path: this._options.recordHar.path, content: this._options.recordHar.content });
|
||||
this.tracing._tracesDir = browserOptions.tracesDir;
|
||||
}
|
||||
|
||||
@ -343,15 +352,17 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
||||
await this._updateWebSocketInterceptionPatterns();
|
||||
}
|
||||
|
||||
async _recordIntoHAR(har: string, page: Page | null, options: { url?: string | RegExp, notFound?: 'abort' | 'fallback', update?: boolean, updateContent?: 'attach' | 'embed', updateMode?: 'minimal' | 'full'} = {}): Promise<void> {
|
||||
async _recordIntoHAR(har: string, page: Page | null, options: { url?: string | RegExp, updateContent?: 'attach' | 'embed' | 'omit', updateMode?: 'minimal' | 'full'} = {}): Promise<void> {
|
||||
const { harId } = await this._channel.harStart({
|
||||
page: page?._channel,
|
||||
options: prepareRecordHarOptions({
|
||||
path: har,
|
||||
options: {
|
||||
zip: har.endsWith('.zip'),
|
||||
content: options.updateContent ?? 'attach',
|
||||
urlGlob: isString(options.url) ? options.url : undefined,
|
||||
urlRegexSource: isRegExp(options.url) ? options.url.source : undefined,
|
||||
urlRegexFlags: isRegExp(options.url) ? options.url.flags : undefined,
|
||||
mode: options.updateMode ?? 'minimal',
|
||||
urlFilter: options.url
|
||||
})!
|
||||
},
|
||||
});
|
||||
this._harRecorders.set(harId, { path: har, content: options.updateContent ?? 'attach' });
|
||||
}
|
||||
@ -512,19 +523,6 @@ async function prepareStorageState(platform: Platform, options: BrowserContextOp
|
||||
}
|
||||
}
|
||||
|
||||
function prepareRecordHarOptions(options: BrowserContextOptions['recordHar']): channels.RecordHarOptions | undefined {
|
||||
if (!options)
|
||||
return;
|
||||
return {
|
||||
path: options.path,
|
||||
content: options.content || (options.omitContent ? 'omit' : undefined),
|
||||
urlGlob: isString(options.urlFilter) ? options.urlFilter : undefined,
|
||||
urlRegexSource: isRegExp(options.urlFilter) ? options.urlFilter.source : undefined,
|
||||
urlRegexFlags: isRegExp(options.urlFilter) ? options.urlFilter.flags : undefined,
|
||||
mode: options.mode
|
||||
};
|
||||
}
|
||||
|
||||
export async function prepareBrowserContextParams(platform: Platform, options: BrowserContextOptions): Promise<channels.BrowserNewContextParams> {
|
||||
if (options.videoSize && !options.videosPath)
|
||||
throw new Error(`"videoSize" option requires "videosPath" to be specified`);
|
||||
@ -537,7 +535,6 @@ export async function prepareBrowserContextParams(platform: Platform, options: B
|
||||
extraHTTPHeaders: options.extraHTTPHeaders ? headersObjectToArray(options.extraHTTPHeaders) : undefined,
|
||||
storageState: await prepareStorageState(platform, options),
|
||||
serviceWorkers: options.serviceWorkers,
|
||||
recordHar: prepareRecordHarOptions(options.recordHar),
|
||||
colorScheme: options.colorScheme === null ? 'no-override' : options.colorScheme,
|
||||
reducedMotion: options.reducedMotion === null ? 'no-override' : options.reducedMotion,
|
||||
forcedColors: options.forcedColors === null ? 'no-override' : options.forcedColors,
|
||||
|
||||
@ -113,6 +113,7 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel> imple
|
||||
return await this._wrapApiCall(async () => {
|
||||
const result = await this._channel.launchPersistentContext(persistentParams);
|
||||
const context = BrowserContext.from(result.context);
|
||||
await context._initializeHarFromOptions(options.recordHar);
|
||||
await this._didCreateContext(context, contextParams, options, logger);
|
||||
return context;
|
||||
});
|
||||
|
||||
@ -60,6 +60,7 @@ export class Electron extends ChannelOwner<channels.ElectronChannel> implements
|
||||
timeout: new TimeoutSettings(this._platform).launchTimeout(options),
|
||||
};
|
||||
const app = ElectronApplication.from((await this._channel.launch(params)).electronApplication);
|
||||
await app._context._initializeHarFromOptions(options.recordHar);
|
||||
app._context._setOptions(params, options);
|
||||
return app;
|
||||
}
|
||||
|
||||
@ -193,7 +193,7 @@ scheme.SerializedError = tObject({
|
||||
value: tOptional(tType('SerializedValue')),
|
||||
});
|
||||
scheme.RecordHarOptions = tObject({
|
||||
path: tString,
|
||||
zip: tOptional(tBoolean),
|
||||
content: tOptional(tEnum(['embed', 'attach', 'omit'])),
|
||||
mode: tOptional(tEnum(['full', 'minimal'])),
|
||||
urlGlob: tOptional(tString),
|
||||
@ -632,7 +632,6 @@ scheme.BrowserTypeLaunchPersistentContextParams = tObject({
|
||||
height: tNumber,
|
||||
})),
|
||||
})),
|
||||
recordHar: tOptional(tType('RecordHarOptions')),
|
||||
strictSelectors: tOptional(tBoolean),
|
||||
serviceWorkers: tOptional(tEnum(['allow', 'block'])),
|
||||
selectorEngines: tOptional(tArray(tType('SelectorEngine'))),
|
||||
@ -721,7 +720,6 @@ scheme.BrowserNewContextParams = tObject({
|
||||
height: tNumber,
|
||||
})),
|
||||
})),
|
||||
recordHar: tOptional(tType('RecordHarOptions')),
|
||||
strictSelectors: tOptional(tBoolean),
|
||||
serviceWorkers: tOptional(tEnum(['allow', 'block'])),
|
||||
selectorEngines: tOptional(tArray(tType('SelectorEngine'))),
|
||||
@ -793,7 +791,6 @@ scheme.BrowserNewContextForReuseParams = tObject({
|
||||
height: tNumber,
|
||||
})),
|
||||
})),
|
||||
recordHar: tOptional(tType('RecordHarOptions')),
|
||||
strictSelectors: tOptional(tBoolean),
|
||||
serviceWorkers: tOptional(tEnum(['allow', 'block'])),
|
||||
selectorEngines: tOptional(tArray(tType('SelectorEngine'))),
|
||||
@ -2459,7 +2456,6 @@ scheme.ElectronLaunchParams = tObject({
|
||||
ignoreHTTPSErrors: tOptional(tBoolean),
|
||||
locale: tOptional(tString),
|
||||
offline: tOptional(tBoolean),
|
||||
recordHar: tOptional(tType('RecordHarOptions')),
|
||||
recordVideo: tOptional(tObject({
|
||||
dir: tString,
|
||||
size: tOptional(tObject({
|
||||
@ -2699,7 +2695,6 @@ scheme.AndroidDeviceLaunchBrowserParams = tObject({
|
||||
height: tNumber,
|
||||
})),
|
||||
})),
|
||||
recordHar: tOptional(tType('RecordHarOptions')),
|
||||
strictSelectors: tOptional(tBoolean),
|
||||
serviceWorkers: tOptional(tEnum(['allow', 'block'])),
|
||||
selectorEngines: tOptional(tArray(tType('SelectorEngine'))),
|
||||
|
||||
@ -109,10 +109,6 @@ export abstract class BrowserContext extends SdkObject {
|
||||
this._selectors = new Selectors(options.selectorEngines || [], options.testIdAttributeName);
|
||||
|
||||
this.fetchRequest = new BrowserContextAPIRequestContext(this);
|
||||
|
||||
if (this._options.recordHar)
|
||||
this._harRecorders.set('', new HarRecorder(this, null, this._options.recordHar));
|
||||
|
||||
this.tracing = new Tracing(this, browser.options.tracesDir);
|
||||
this.clock = new Clock(this);
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ export class HarRecorder implements HarTracerDelegate {
|
||||
constructor(context: BrowserContext, page: Page | null, options: channels.RecordHarOptions) {
|
||||
this._artifact = new Artifact(context, path.join(context._browser.options.artifactsDir, `${createGuid()}.har`));
|
||||
const urlFilterRe = options.urlRegexSource !== undefined && options.urlRegexFlags !== undefined ? new RegExp(options.urlRegexSource, options.urlRegexFlags) : undefined;
|
||||
const expectsZip = options.path.endsWith('.zip');
|
||||
const expectsZip = !!options.zip;
|
||||
const content = options.content || (expectsZip ? 'attach' : 'embed');
|
||||
this._tracer = new HarTracer(context, page, this, {
|
||||
content,
|
||||
|
||||
@ -106,6 +106,8 @@ export class HarTracer {
|
||||
eventsHelper.addEventListener(this._context, BrowserContext.Events.RequestFulfilled, request => this._onRequestFulfilled(request)),
|
||||
eventsHelper.addEventListener(this._context, BrowserContext.Events.RequestContinued, request => this._onRequestContinued(request)),
|
||||
);
|
||||
for (const page of this._context.pages())
|
||||
this._createPageEntryIfNeeded(page);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
12
packages/protocol/src/channels.d.ts
vendored
12
packages/protocol/src/channels.d.ts
vendored
@ -324,7 +324,7 @@ export type SerializedError = {
|
||||
};
|
||||
|
||||
export type RecordHarOptions = {
|
||||
path: string,
|
||||
zip?: boolean,
|
||||
content?: 'embed' | 'attach' | 'omit',
|
||||
mode?: 'full' | 'minimal',
|
||||
urlGlob?: string,
|
||||
@ -1045,7 +1045,6 @@ export type BrowserTypeLaunchPersistentContextParams = {
|
||||
height: number,
|
||||
},
|
||||
},
|
||||
recordHar?: RecordHarOptions,
|
||||
strictSelectors?: boolean,
|
||||
serviceWorkers?: 'allow' | 'block',
|
||||
selectorEngines?: SelectorEngine[],
|
||||
@ -1129,7 +1128,6 @@ export type BrowserTypeLaunchPersistentContextOptions = {
|
||||
height: number,
|
||||
},
|
||||
},
|
||||
recordHar?: RecordHarOptions,
|
||||
strictSelectors?: boolean,
|
||||
serviceWorkers?: 'allow' | 'block',
|
||||
selectorEngines?: SelectorEngine[],
|
||||
@ -1246,7 +1244,6 @@ export type BrowserNewContextParams = {
|
||||
height: number,
|
||||
},
|
||||
},
|
||||
recordHar?: RecordHarOptions,
|
||||
strictSelectors?: boolean,
|
||||
serviceWorkers?: 'allow' | 'block',
|
||||
selectorEngines?: SelectorEngine[],
|
||||
@ -1315,7 +1312,6 @@ export type BrowserNewContextOptions = {
|
||||
height: number,
|
||||
},
|
||||
},
|
||||
recordHar?: RecordHarOptions,
|
||||
strictSelectors?: boolean,
|
||||
serviceWorkers?: 'allow' | 'block',
|
||||
selectorEngines?: SelectorEngine[],
|
||||
@ -1387,7 +1383,6 @@ export type BrowserNewContextForReuseParams = {
|
||||
height: number,
|
||||
},
|
||||
},
|
||||
recordHar?: RecordHarOptions,
|
||||
strictSelectors?: boolean,
|
||||
serviceWorkers?: 'allow' | 'block',
|
||||
selectorEngines?: SelectorEngine[],
|
||||
@ -1456,7 +1451,6 @@ export type BrowserNewContextForReuseOptions = {
|
||||
height: number,
|
||||
},
|
||||
},
|
||||
recordHar?: RecordHarOptions,
|
||||
strictSelectors?: boolean,
|
||||
serviceWorkers?: 'allow' | 'block',
|
||||
selectorEngines?: SelectorEngine[],
|
||||
@ -4329,7 +4323,6 @@ export type ElectronLaunchParams = {
|
||||
ignoreHTTPSErrors?: boolean,
|
||||
locale?: string,
|
||||
offline?: boolean,
|
||||
recordHar?: RecordHarOptions,
|
||||
recordVideo?: {
|
||||
dir: string,
|
||||
size?: {
|
||||
@ -4363,7 +4356,6 @@ export type ElectronLaunchOptions = {
|
||||
ignoreHTTPSErrors?: boolean,
|
||||
locale?: string,
|
||||
offline?: boolean,
|
||||
recordHar?: RecordHarOptions,
|
||||
recordVideo?: {
|
||||
dir: string,
|
||||
size?: {
|
||||
@ -4755,7 +4747,6 @@ export type AndroidDeviceLaunchBrowserParams = {
|
||||
height: number,
|
||||
},
|
||||
},
|
||||
recordHar?: RecordHarOptions,
|
||||
strictSelectors?: boolean,
|
||||
serviceWorkers?: 'allow' | 'block',
|
||||
selectorEngines?: SelectorEngine[],
|
||||
@ -4822,7 +4813,6 @@ export type AndroidDeviceLaunchBrowserOptions = {
|
||||
height: number,
|
||||
},
|
||||
},
|
||||
recordHar?: RecordHarOptions,
|
||||
strictSelectors?: boolean,
|
||||
serviceWorkers?: 'allow' | 'block',
|
||||
selectorEngines?: SelectorEngine[],
|
||||
|
||||
@ -324,7 +324,7 @@ SerializedError:
|
||||
RecordHarOptions:
|
||||
type: object
|
||||
properties:
|
||||
path: string
|
||||
zip: boolean?
|
||||
content:
|
||||
type: enum?
|
||||
literals:
|
||||
@ -611,7 +611,6 @@ ContextOptions:
|
||||
properties:
|
||||
width: number
|
||||
height: number
|
||||
recordHar: RecordHarOptions?
|
||||
strictSelectors: boolean?
|
||||
serviceWorkers:
|
||||
type: enum?
|
||||
@ -3724,7 +3723,6 @@ Electron:
|
||||
ignoreHTTPSErrors: boolean?
|
||||
locale: string?
|
||||
offline: boolean?
|
||||
recordHar: RecordHarOptions?
|
||||
recordVideo:
|
||||
type: object?
|
||||
properties:
|
||||
|
||||
@ -42,11 +42,6 @@ async function pageWithHar(contextFactory: (options?: BrowserContextOptions) =>
|
||||
};
|
||||
}
|
||||
|
||||
it('should throw without path', async ({ browser }) => {
|
||||
const error = await browser.newContext({ recordHar: {} as any }).catch(e => e);
|
||||
expect(error.message).toContain('recordHar.path: expected string, got undefined');
|
||||
});
|
||||
|
||||
it('should have version and creator', async ({ contextFactory, server }, testInfo) => {
|
||||
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
@ -90,17 +85,8 @@ it('should have pages in persistent context', async ({ launchPersistent, browser
|
||||
await page.waitForLoadState('domcontentloaded');
|
||||
await context.close();
|
||||
const log = JSON.parse(fs.readFileSync(harPath).toString())['log'];
|
||||
let pageEntry;
|
||||
if (browserName === 'webkit') {
|
||||
// Explicit locale emulation forces a new page creation when
|
||||
// doing a new context.
|
||||
// See https://github.com/microsoft/playwright/blob/13dd41c2e36a63f35ddef5dc5dec322052d670c6/packages/playwright-core/src/server/browserContext.ts#L232-L242
|
||||
expect(log.pages.length).toBe(2);
|
||||
pageEntry = log.pages[1];
|
||||
} else {
|
||||
expect(log.pages.length).toBe(1);
|
||||
pageEntry = log.pages[0];
|
||||
}
|
||||
expect(log.pages.length).toBe(1);
|
||||
const pageEntry = log.pages[0];
|
||||
expect(pageEntry.id).toBeTruthy();
|
||||
expect(pageEntry.title).toBe('Hello');
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user