chore: migrate component testing to server-side page reuse (#15477)
This commit is contained in:
parent
e4debd0bf6
commit
3939b9f36e
|
|
@ -244,23 +244,11 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
||||||
await this._channel.addInitScript({ source });
|
await this._channel.addInitScript({ source });
|
||||||
}
|
}
|
||||||
|
|
||||||
async _removeInitScripts() {
|
|
||||||
await this._channel.removeInitScripts();
|
|
||||||
}
|
|
||||||
|
|
||||||
async exposeBinding(name: string, callback: (source: structs.BindingSource, ...args: any[]) => any, options: { handle?: boolean } = {}): Promise<void> {
|
async exposeBinding(name: string, callback: (source: structs.BindingSource, ...args: any[]) => any, options: { handle?: boolean } = {}): Promise<void> {
|
||||||
await this._channel.exposeBinding({ name, needsHandle: options.handle });
|
await this._channel.exposeBinding({ name, needsHandle: options.handle });
|
||||||
this._bindings.set(name, callback);
|
this._bindings.set(name, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _removeExposedBindings() {
|
|
||||||
for (const key of this._bindings.keys()) {
|
|
||||||
if (!key.startsWith('__pw_'))
|
|
||||||
this._bindings.delete(key);
|
|
||||||
}
|
|
||||||
await this._channel.removeExposedBindings();
|
|
||||||
}
|
|
||||||
|
|
||||||
async exposeFunction(name: string, callback: Function): Promise<void> {
|
async exposeFunction(name: string, callback: Function): Promise<void> {
|
||||||
await this._channel.exposeBinding({ name });
|
await this._channel.exposeBinding({ name });
|
||||||
const binding = (source: structs.BindingSource, ...args: any[]) => callback(...args);
|
const binding = (source: structs.BindingSource, ...args: any[]) => callback(...args);
|
||||||
|
|
@ -301,11 +289,6 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
||||||
await this._disableInterception();
|
await this._disableInterception();
|
||||||
}
|
}
|
||||||
|
|
||||||
async _unrouteAll() {
|
|
||||||
this._routes = [];
|
|
||||||
await this._disableInterception();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _disableInterception() {
|
private async _disableInterception() {
|
||||||
await this._channel.setNetworkInterceptionEnabled({ enabled: false });
|
await this._channel.setNetworkInterceptionEnabled({ enabled: false });
|
||||||
}
|
}
|
||||||
|
|
@ -395,12 +378,6 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
||||||
}) {
|
}) {
|
||||||
await this._channel.recorderSupplementEnable(params);
|
await this._channel.recorderSupplementEnable(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _resetForReuse() {
|
|
||||||
await this._unrouteAll();
|
|
||||||
await this._removeInitScripts();
|
|
||||||
await this._removeExposedBindings();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function prepareStorageState(options: BrowserContextOptions): Promise<channels.BrowserNewContextParams['storageState']> {
|
async function prepareStorageState(options: BrowserContextOptions): Promise<channels.BrowserNewContextParams['storageState']> {
|
||||||
|
|
|
||||||
|
|
@ -329,14 +329,6 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
||||||
this._bindings.set(name, callback);
|
this._bindings.set(name, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _removeExposedBindings() {
|
|
||||||
for (const key of this._bindings.keys()) {
|
|
||||||
if (!key.startsWith('__pw_'))
|
|
||||||
this._bindings.delete(key);
|
|
||||||
}
|
|
||||||
await this._channel.removeExposedBindings();
|
|
||||||
}
|
|
||||||
|
|
||||||
async setExtraHTTPHeaders(headers: Headers) {
|
async setExtraHTTPHeaders(headers: Headers) {
|
||||||
validateHeaders(headers);
|
validateHeaders(headers);
|
||||||
await this._channel.setExtraHTTPHeaders({ headers: headersObjectToArray(headers) });
|
await this._channel.setExtraHTTPHeaders({ headers: headersObjectToArray(headers) });
|
||||||
|
|
@ -457,10 +449,6 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
||||||
await this._channel.addInitScript({ source });
|
await this._channel.addInitScript({ source });
|
||||||
}
|
}
|
||||||
|
|
||||||
async _removeInitScripts() {
|
|
||||||
await this._channel.removeInitScripts();
|
|
||||||
}
|
|
||||||
|
|
||||||
async route(url: URLMatch, handler: RouteHandlerCallback, options: { times?: number } = {}): Promise<void> {
|
async route(url: URLMatch, handler: RouteHandlerCallback, options: { times?: number } = {}): Promise<void> {
|
||||||
this._routes.unshift(new RouteHandler(this._browserContext._options.baseURL, url, handler, options.times));
|
this._routes.unshift(new RouteHandler(this._browserContext._options.baseURL, url, handler, options.times));
|
||||||
if (this._routes.length === 1)
|
if (this._routes.length === 1)
|
||||||
|
|
@ -482,11 +470,6 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
||||||
await this._disableInterception();
|
await this._disableInterception();
|
||||||
}
|
}
|
||||||
|
|
||||||
async _unrouteAll() {
|
|
||||||
this._routes = [];
|
|
||||||
await this._disableInterception();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _disableInterception() {
|
private async _disableInterception() {
|
||||||
await this._channel.setNetworkInterceptionEnabled({ enabled: false });
|
await this._channel.setNetworkInterceptionEnabled({ enabled: false });
|
||||||
}
|
}
|
||||||
|
|
@ -736,12 +719,6 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
||||||
}
|
}
|
||||||
return result.pdf;
|
return result.pdf;
|
||||||
}
|
}
|
||||||
|
|
||||||
async _resetForReuse() {
|
|
||||||
await this._unrouteAll();
|
|
||||||
await this._removeInitScripts();
|
|
||||||
await this._removeExposedBindings();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class BindingCall extends ChannelOwner<channels.BindingCallChannel> {
|
export class BindingCall extends ChannelOwner<channels.BindingCallChannel> {
|
||||||
|
|
|
||||||
|
|
@ -1227,13 +1227,11 @@ export interface BrowserContextChannel extends BrowserContextEventTarget, EventT
|
||||||
_type_BrowserContext: boolean;
|
_type_BrowserContext: boolean;
|
||||||
addCookies(params: BrowserContextAddCookiesParams, metadata?: Metadata): Promise<BrowserContextAddCookiesResult>;
|
addCookies(params: BrowserContextAddCookiesParams, metadata?: Metadata): Promise<BrowserContextAddCookiesResult>;
|
||||||
addInitScript(params: BrowserContextAddInitScriptParams, metadata?: Metadata): Promise<BrowserContextAddInitScriptResult>;
|
addInitScript(params: BrowserContextAddInitScriptParams, metadata?: Metadata): Promise<BrowserContextAddInitScriptResult>;
|
||||||
removeInitScripts(params?: BrowserContextRemoveInitScriptsParams, metadata?: Metadata): Promise<BrowserContextRemoveInitScriptsResult>;
|
|
||||||
clearCookies(params?: BrowserContextClearCookiesParams, metadata?: Metadata): Promise<BrowserContextClearCookiesResult>;
|
clearCookies(params?: BrowserContextClearCookiesParams, metadata?: Metadata): Promise<BrowserContextClearCookiesResult>;
|
||||||
clearPermissions(params?: BrowserContextClearPermissionsParams, metadata?: Metadata): Promise<BrowserContextClearPermissionsResult>;
|
clearPermissions(params?: BrowserContextClearPermissionsParams, metadata?: Metadata): Promise<BrowserContextClearPermissionsResult>;
|
||||||
close(params?: BrowserContextCloseParams, metadata?: Metadata): Promise<BrowserContextCloseResult>;
|
close(params?: BrowserContextCloseParams, metadata?: Metadata): Promise<BrowserContextCloseResult>;
|
||||||
cookies(params: BrowserContextCookiesParams, metadata?: Metadata): Promise<BrowserContextCookiesResult>;
|
cookies(params: BrowserContextCookiesParams, metadata?: Metadata): Promise<BrowserContextCookiesResult>;
|
||||||
exposeBinding(params: BrowserContextExposeBindingParams, metadata?: Metadata): Promise<BrowserContextExposeBindingResult>;
|
exposeBinding(params: BrowserContextExposeBindingParams, metadata?: Metadata): Promise<BrowserContextExposeBindingResult>;
|
||||||
removeExposedBindings(params?: BrowserContextRemoveExposedBindingsParams, metadata?: Metadata): Promise<BrowserContextRemoveExposedBindingsResult>;
|
|
||||||
grantPermissions(params: BrowserContextGrantPermissionsParams, metadata?: Metadata): Promise<BrowserContextGrantPermissionsResult>;
|
grantPermissions(params: BrowserContextGrantPermissionsParams, metadata?: Metadata): Promise<BrowserContextGrantPermissionsResult>;
|
||||||
newPage(params?: BrowserContextNewPageParams, metadata?: Metadata): Promise<BrowserContextNewPageResult>;
|
newPage(params?: BrowserContextNewPageParams, metadata?: Metadata): Promise<BrowserContextNewPageResult>;
|
||||||
setDefaultNavigationTimeoutNoReply(params: BrowserContextSetDefaultNavigationTimeoutNoReplyParams, metadata?: Metadata): Promise<BrowserContextSetDefaultNavigationTimeoutNoReplyResult>;
|
setDefaultNavigationTimeoutNoReply(params: BrowserContextSetDefaultNavigationTimeoutNoReplyParams, metadata?: Metadata): Promise<BrowserContextSetDefaultNavigationTimeoutNoReplyResult>;
|
||||||
|
|
@ -1305,9 +1303,6 @@ export type BrowserContextAddInitScriptOptions = {
|
||||||
|
|
||||||
};
|
};
|
||||||
export type BrowserContextAddInitScriptResult = void;
|
export type BrowserContextAddInitScriptResult = void;
|
||||||
export type BrowserContextRemoveInitScriptsParams = {};
|
|
||||||
export type BrowserContextRemoveInitScriptsOptions = {};
|
|
||||||
export type BrowserContextRemoveInitScriptsResult = void;
|
|
||||||
export type BrowserContextClearCookiesParams = {};
|
export type BrowserContextClearCookiesParams = {};
|
||||||
export type BrowserContextClearCookiesOptions = {};
|
export type BrowserContextClearCookiesOptions = {};
|
||||||
export type BrowserContextClearCookiesResult = void;
|
export type BrowserContextClearCookiesResult = void;
|
||||||
|
|
@ -1334,9 +1329,6 @@ export type BrowserContextExposeBindingOptions = {
|
||||||
needsHandle?: boolean,
|
needsHandle?: boolean,
|
||||||
};
|
};
|
||||||
export type BrowserContextExposeBindingResult = void;
|
export type BrowserContextExposeBindingResult = void;
|
||||||
export type BrowserContextRemoveExposedBindingsParams = {};
|
|
||||||
export type BrowserContextRemoveExposedBindingsOptions = {};
|
|
||||||
export type BrowserContextRemoveExposedBindingsResult = void;
|
|
||||||
export type BrowserContextGrantPermissionsParams = {
|
export type BrowserContextGrantPermissionsParams = {
|
||||||
permissions: string[],
|
permissions: string[],
|
||||||
origin?: string,
|
origin?: string,
|
||||||
|
|
@ -1529,11 +1521,9 @@ export interface PageChannel extends PageEventTarget, EventTargetChannel {
|
||||||
setDefaultTimeoutNoReply(params: PageSetDefaultTimeoutNoReplyParams, metadata?: Metadata): Promise<PageSetDefaultTimeoutNoReplyResult>;
|
setDefaultTimeoutNoReply(params: PageSetDefaultTimeoutNoReplyParams, metadata?: Metadata): Promise<PageSetDefaultTimeoutNoReplyResult>;
|
||||||
setFileChooserInterceptedNoReply(params: PageSetFileChooserInterceptedNoReplyParams, metadata?: Metadata): Promise<PageSetFileChooserInterceptedNoReplyResult>;
|
setFileChooserInterceptedNoReply(params: PageSetFileChooserInterceptedNoReplyParams, metadata?: Metadata): Promise<PageSetFileChooserInterceptedNoReplyResult>;
|
||||||
addInitScript(params: PageAddInitScriptParams, metadata?: Metadata): Promise<PageAddInitScriptResult>;
|
addInitScript(params: PageAddInitScriptParams, metadata?: Metadata): Promise<PageAddInitScriptResult>;
|
||||||
removeInitScripts(params?: PageRemoveInitScriptsParams, metadata?: Metadata): Promise<PageRemoveInitScriptsResult>;
|
|
||||||
close(params: PageCloseParams, metadata?: Metadata): Promise<PageCloseResult>;
|
close(params: PageCloseParams, metadata?: Metadata): Promise<PageCloseResult>;
|
||||||
emulateMedia(params: PageEmulateMediaParams, metadata?: Metadata): Promise<PageEmulateMediaResult>;
|
emulateMedia(params: PageEmulateMediaParams, metadata?: Metadata): Promise<PageEmulateMediaResult>;
|
||||||
exposeBinding(params: PageExposeBindingParams, metadata?: Metadata): Promise<PageExposeBindingResult>;
|
exposeBinding(params: PageExposeBindingParams, metadata?: Metadata): Promise<PageExposeBindingResult>;
|
||||||
removeExposedBindings(params?: PageRemoveExposedBindingsParams, metadata?: Metadata): Promise<PageRemoveExposedBindingsResult>;
|
|
||||||
goBack(params: PageGoBackParams, metadata?: Metadata): Promise<PageGoBackResult>;
|
goBack(params: PageGoBackParams, metadata?: Metadata): Promise<PageGoBackResult>;
|
||||||
goForward(params: PageGoForwardParams, metadata?: Metadata): Promise<PageGoForwardResult>;
|
goForward(params: PageGoForwardParams, metadata?: Metadata): Promise<PageGoForwardResult>;
|
||||||
reload(params: PageReloadParams, metadata?: Metadata): Promise<PageReloadResult>;
|
reload(params: PageReloadParams, metadata?: Metadata): Promise<PageReloadResult>;
|
||||||
|
|
@ -1631,9 +1621,6 @@ export type PageAddInitScriptOptions = {
|
||||||
|
|
||||||
};
|
};
|
||||||
export type PageAddInitScriptResult = void;
|
export type PageAddInitScriptResult = void;
|
||||||
export type PageRemoveInitScriptsParams = {};
|
|
||||||
export type PageRemoveInitScriptsOptions = {};
|
|
||||||
export type PageRemoveInitScriptsResult = void;
|
|
||||||
export type PageCloseParams = {
|
export type PageCloseParams = {
|
||||||
runBeforeUnload?: boolean,
|
runBeforeUnload?: boolean,
|
||||||
};
|
};
|
||||||
|
|
@ -1662,9 +1649,6 @@ export type PageExposeBindingOptions = {
|
||||||
needsHandle?: boolean,
|
needsHandle?: boolean,
|
||||||
};
|
};
|
||||||
export type PageExposeBindingResult = void;
|
export type PageExposeBindingResult = void;
|
||||||
export type PageRemoveExposedBindingsParams = {};
|
|
||||||
export type PageRemoveExposedBindingsOptions = {};
|
|
||||||
export type PageRemoveExposedBindingsResult = void;
|
|
||||||
export type PageGoBackParams = {
|
export type PageGoBackParams = {
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
waitUntil?: LifecycleEvent,
|
waitUntil?: LifecycleEvent,
|
||||||
|
|
|
||||||
|
|
@ -850,8 +850,6 @@ BrowserContext:
|
||||||
parameters:
|
parameters:
|
||||||
source: string
|
source: string
|
||||||
|
|
||||||
removeInitScripts:
|
|
||||||
|
|
||||||
clearCookies:
|
clearCookies:
|
||||||
|
|
||||||
clearPermissions:
|
clearPermissions:
|
||||||
|
|
@ -873,8 +871,6 @@ BrowserContext:
|
||||||
name: string
|
name: string
|
||||||
needsHandle: boolean?
|
needsHandle: boolean?
|
||||||
|
|
||||||
removeExposedBindings:
|
|
||||||
|
|
||||||
grantPermissions:
|
grantPermissions:
|
||||||
parameters:
|
parameters:
|
||||||
permissions:
|
permissions:
|
||||||
|
|
@ -1061,8 +1057,6 @@ Page:
|
||||||
parameters:
|
parameters:
|
||||||
source: string
|
source: string
|
||||||
|
|
||||||
removeInitScripts:
|
|
||||||
|
|
||||||
close:
|
close:
|
||||||
parameters:
|
parameters:
|
||||||
runBeforeUnload: boolean?
|
runBeforeUnload: boolean?
|
||||||
|
|
@ -1104,8 +1098,6 @@ Page:
|
||||||
name: string
|
name: string
|
||||||
needsHandle: boolean?
|
needsHandle: boolean?
|
||||||
|
|
||||||
removeExposedBindings:
|
|
||||||
|
|
||||||
goBack:
|
goBack:
|
||||||
parameters:
|
parameters:
|
||||||
timeout: number?
|
timeout: number?
|
||||||
|
|
|
||||||
|
|
@ -695,8 +695,6 @@ scheme.BrowserContextAddInitScriptParams = tObject({
|
||||||
source: tString,
|
source: tString,
|
||||||
});
|
});
|
||||||
scheme.BrowserContextAddInitScriptResult = tOptional(tObject({}));
|
scheme.BrowserContextAddInitScriptResult = tOptional(tObject({}));
|
||||||
scheme.BrowserContextRemoveInitScriptsParams = tOptional(tObject({}));
|
|
||||||
scheme.BrowserContextRemoveInitScriptsResult = tOptional(tObject({}));
|
|
||||||
scheme.BrowserContextClearCookiesParams = tOptional(tObject({}));
|
scheme.BrowserContextClearCookiesParams = tOptional(tObject({}));
|
||||||
scheme.BrowserContextClearCookiesResult = tOptional(tObject({}));
|
scheme.BrowserContextClearCookiesResult = tOptional(tObject({}));
|
||||||
scheme.BrowserContextClearPermissionsParams = tOptional(tObject({}));
|
scheme.BrowserContextClearPermissionsParams = tOptional(tObject({}));
|
||||||
|
|
@ -714,8 +712,6 @@ scheme.BrowserContextExposeBindingParams = tObject({
|
||||||
needsHandle: tOptional(tBoolean),
|
needsHandle: tOptional(tBoolean),
|
||||||
});
|
});
|
||||||
scheme.BrowserContextExposeBindingResult = tOptional(tObject({}));
|
scheme.BrowserContextExposeBindingResult = tOptional(tObject({}));
|
||||||
scheme.BrowserContextRemoveExposedBindingsParams = tOptional(tObject({}));
|
|
||||||
scheme.BrowserContextRemoveExposedBindingsResult = tOptional(tObject({}));
|
|
||||||
scheme.BrowserContextGrantPermissionsParams = tObject({
|
scheme.BrowserContextGrantPermissionsParams = tObject({
|
||||||
permissions: tArray(tString),
|
permissions: tArray(tString),
|
||||||
origin: tOptional(tString),
|
origin: tOptional(tString),
|
||||||
|
|
@ -871,8 +867,6 @@ scheme.PageAddInitScriptParams = tObject({
|
||||||
source: tString,
|
source: tString,
|
||||||
});
|
});
|
||||||
scheme.PageAddInitScriptResult = tOptional(tObject({}));
|
scheme.PageAddInitScriptResult = tOptional(tObject({}));
|
||||||
scheme.PageRemoveInitScriptsParams = tOptional(tObject({}));
|
|
||||||
scheme.PageRemoveInitScriptsResult = tOptional(tObject({}));
|
|
||||||
scheme.PageCloseParams = tObject({
|
scheme.PageCloseParams = tObject({
|
||||||
runBeforeUnload: tOptional(tBoolean),
|
runBeforeUnload: tOptional(tBoolean),
|
||||||
});
|
});
|
||||||
|
|
@ -889,8 +883,6 @@ scheme.PageExposeBindingParams = tObject({
|
||||||
needsHandle: tOptional(tBoolean),
|
needsHandle: tOptional(tBoolean),
|
||||||
});
|
});
|
||||||
scheme.PageExposeBindingResult = tOptional(tObject({}));
|
scheme.PageExposeBindingResult = tOptional(tObject({}));
|
||||||
scheme.PageRemoveExposedBindingsParams = tOptional(tObject({}));
|
|
||||||
scheme.PageRemoveExposedBindingsResult = tOptional(tObject({}));
|
|
||||||
scheme.PageGoBackParams = tObject({
|
scheme.PageGoBackParams = tObject({
|
||||||
timeout: tOptional(tNumber),
|
timeout: tOptional(tNumber),
|
||||||
waitUntil: tOptional(tType('LifecycleEvent')),
|
waitUntil: tOptional(tType('LifecycleEvent')),
|
||||||
|
|
|
||||||
|
|
@ -140,25 +140,33 @@ export abstract class BrowserContext extends SdkObject {
|
||||||
canResetForReuse(): boolean {
|
canResetForReuse(): boolean {
|
||||||
if (this._closedStatus !== 'open')
|
if (this._closedStatus !== 'open')
|
||||||
return false;
|
return false;
|
||||||
if (this.pages().length < 1)
|
|
||||||
return false;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async resetForReuse(metadata: CallMetadata) {
|
static reusableContextHash(params: channels.BrowserNewContextForReuseParams): string {
|
||||||
|
const paramsCopy = { ...params };
|
||||||
|
for (const key of paramsThatAllowContextReuse)
|
||||||
|
delete paramsCopy[key];
|
||||||
|
return JSON.stringify(paramsCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
async resetForReuse(metadata: CallMetadata, params: channels.BrowserNewContextForReuseParams) {
|
||||||
this.setDefaultNavigationTimeout(undefined);
|
this.setDefaultNavigationTimeout(undefined);
|
||||||
this.setDefaultTimeout(undefined);
|
this.setDefaultTimeout(undefined);
|
||||||
|
|
||||||
|
for (const key of paramsThatAllowContextReuse)
|
||||||
|
(this._options as any)[key] = params[key];
|
||||||
|
|
||||||
await this._cancelAllRoutesInFlight();
|
await this._cancelAllRoutesInFlight();
|
||||||
|
|
||||||
const [page, ...otherPages] = this.pages();
|
const [page, ...otherPages] = this.pages();
|
||||||
for (const page of otherPages)
|
for (const page of otherPages)
|
||||||
await page.close(metadata);
|
await page.close(metadata);
|
||||||
// Unless I do this early, setting extra http headers below does not respond.
|
// Unless I do this early, setting extra http headers below does not respond.
|
||||||
await page._frameManager.closeOpenDialogs();
|
await page?._frameManager.closeOpenDialogs();
|
||||||
await page.mainFrame().goto(metadata, 'about:blank', { timeout: 0 });
|
await page?.mainFrame().goto(metadata, 'about:blank', { timeout: 0 });
|
||||||
await this.removeExposedBindings();
|
await this._removeExposedBindings();
|
||||||
await this.removeInitScripts();
|
await this._removeInitScripts();
|
||||||
// TODO: following can be optimized to not perform noops.
|
// TODO: following can be optimized to not perform noops.
|
||||||
if (this._options.permissions)
|
if (this._options.permissions)
|
||||||
await this.grantPermissions(this._options.permissions);
|
await this.grantPermissions(this._options.permissions);
|
||||||
|
|
@ -168,7 +176,7 @@ export abstract class BrowserContext extends SdkObject {
|
||||||
await this.setGeolocation(this._options.geolocation);
|
await this.setGeolocation(this._options.geolocation);
|
||||||
await this.setOffline(!!this._options.offline);
|
await this.setOffline(!!this._options.offline);
|
||||||
|
|
||||||
await page.resetForReuse(metadata);
|
await page?.resetForReuse(metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
_browserClosed() {
|
_browserClosed() {
|
||||||
|
|
@ -236,7 +244,7 @@ export abstract class BrowserContext extends SdkObject {
|
||||||
await this.doExposeBinding(binding);
|
await this.doExposeBinding(binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeExposedBindings() {
|
async _removeExposedBindings() {
|
||||||
for (const key of this._pageBindings.keys()) {
|
for (const key of this._pageBindings.keys()) {
|
||||||
if (!key.startsWith('__pw'))
|
if (!key.startsWith('__pw'))
|
||||||
this._pageBindings.delete(key);
|
this._pageBindings.delete(key);
|
||||||
|
|
@ -324,7 +332,7 @@ export abstract class BrowserContext extends SdkObject {
|
||||||
await this.doAddInitScript(script);
|
await this.doAddInitScript(script);
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeInitScripts(): Promise<void> {
|
async _removeInitScripts(): Promise<void> {
|
||||||
this.initScripts.splice(0, this.initScripts.length);
|
this.initScripts.splice(0, this.initScripts.length);
|
||||||
await this.doRemoveInitScripts();
|
await this.doRemoveInitScripts();
|
||||||
}
|
}
|
||||||
|
|
@ -586,3 +594,11 @@ export function normalizeProxySettings(proxy: types.ProxySettings): types.ProxyS
|
||||||
bypass = bypass.split(',').map(t => t.trim()).join(',');
|
bypass = bypass.split(',').map(t => t.trim()).join(',');
|
||||||
return { ...proxy, server, bypass };
|
return { ...proxy, server, bypass };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const paramsThatAllowContextReuse: (keyof channels.BrowserNewContextForReuseParams)[] = [
|
||||||
|
'colorScheme',
|
||||||
|
'forcedColors',
|
||||||
|
'reducedMotion',
|
||||||
|
'screen',
|
||||||
|
'viewport'
|
||||||
|
];
|
||||||
|
|
|
||||||
|
|
@ -126,10 +126,6 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeExposedBindings() {
|
|
||||||
await this._context.removeExposedBindings();
|
|
||||||
}
|
|
||||||
|
|
||||||
async newPage(params: channels.BrowserContextNewPageParams, metadata: CallMetadata): Promise<channels.BrowserContextNewPageResult> {
|
async newPage(params: channels.BrowserContextNewPageParams, metadata: CallMetadata): Promise<channels.BrowserContextNewPageResult> {
|
||||||
return { page: lookupDispatcher<PageDispatcher>(await this._context.newPage(metadata)) };
|
return { page: lookupDispatcher<PageDispatcher>(await this._context.newPage(metadata)) };
|
||||||
}
|
}
|
||||||
|
|
@ -174,10 +170,6 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
|
||||||
await this._context.addInitScript(params.source);
|
await this._context.addInitScript(params.source);
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeInitScripts(): Promise<void> {
|
|
||||||
await this._context.removeInitScripts();
|
|
||||||
}
|
|
||||||
|
|
||||||
async setNetworkInterceptionEnabled(params: channels.BrowserContextSetNetworkInterceptionEnabledParams): Promise<void> {
|
async setNetworkInterceptionEnabled(params: channels.BrowserContextSetNetworkInterceptionEnabledParams): Promise<void> {
|
||||||
if (!params.enabled) {
|
if (!params.enabled) {
|
||||||
await this._context.setRequestInterceptor(undefined);
|
await this._context.setRequestInterceptor(undefined);
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ export class BrowserDispatcher extends Dispatcher<Browser, channels.BrowserChann
|
||||||
* Used for inner loop scenarios where user would like to preserve the browser window, opened page and devtools instance.
|
* Used for inner loop scenarios where user would like to preserve the browser window, opened page and devtools instance.
|
||||||
*/
|
*/
|
||||||
async newContextForReuse(params: channels.BrowserNewContextForReuseParams, metadata: CallMetadata): Promise<channels.BrowserNewContextForReuseResult> {
|
async newContextForReuse(params: channels.BrowserNewContextForReuseParams, metadata: CallMetadata): Promise<channels.BrowserNewContextForReuseResult> {
|
||||||
const hash = JSON.stringify(params);
|
const hash = BrowserContext.reusableContextHash(params);
|
||||||
if (!this._contextForReuse || hash !== this._contextForReuse.hash || !this._contextForReuse.context.canResetForReuse()) {
|
if (!this._contextForReuse || hash !== this._contextForReuse.hash || !this._contextForReuse.context.canResetForReuse()) {
|
||||||
if (this._contextForReuse)
|
if (this._contextForReuse)
|
||||||
await this._contextForReuse.context.close(metadata);
|
await this._contextForReuse.context.close(metadata);
|
||||||
|
|
@ -59,7 +59,7 @@ export class BrowserDispatcher extends Dispatcher<Browser, channels.BrowserChann
|
||||||
} else {
|
} else {
|
||||||
const oldContextDispatcher = existingDispatcher<BrowserContextDispatcher>(this._contextForReuse.context);
|
const oldContextDispatcher = existingDispatcher<BrowserContextDispatcher>(this._contextForReuse.context);
|
||||||
oldContextDispatcher._dispose();
|
oldContextDispatcher._dispose();
|
||||||
await this._contextForReuse.context.resetForReuse(metadata);
|
await this._contextForReuse.context.resetForReuse(metadata, params);
|
||||||
}
|
}
|
||||||
const context = new BrowserContextDispatcher(this._scope, this._contextForReuse.context);
|
const context = new BrowserContextDispatcher(this._scope, this._contextForReuse.context);
|
||||||
return { context };
|
return { context };
|
||||||
|
|
|
||||||
|
|
@ -107,10 +107,6 @@ export class PageDispatcher extends Dispatcher<Page, channels.PageChannel> imple
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeExposedBindings() {
|
|
||||||
await this._page.removeExposedBindings();
|
|
||||||
}
|
|
||||||
|
|
||||||
async setExtraHTTPHeaders(params: channels.PageSetExtraHTTPHeadersParams, metadata: CallMetadata): Promise<void> {
|
async setExtraHTTPHeaders(params: channels.PageSetExtraHTTPHeadersParams, metadata: CallMetadata): Promise<void> {
|
||||||
await this._page.setExtraHTTPHeaders(params.headers);
|
await this._page.setExtraHTTPHeaders(params.headers);
|
||||||
}
|
}
|
||||||
|
|
@ -144,10 +140,6 @@ export class PageDispatcher extends Dispatcher<Page, channels.PageChannel> imple
|
||||||
await this._page.addInitScript(params.source);
|
await this._page.addInitScript(params.source);
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeInitScripts(): Promise<void> {
|
|
||||||
await this._page.removeInitScripts();
|
|
||||||
}
|
|
||||||
|
|
||||||
async setNetworkInterceptionEnabled(params: channels.PageSetNetworkInterceptionEnabledParams, metadata: CallMetadata): Promise<void> {
|
async setNetworkInterceptionEnabled(params: channels.PageSetNetworkInterceptionEnabledParams, metadata: CallMetadata): Promise<void> {
|
||||||
if (!params.enabled) {
|
if (!params.enabled) {
|
||||||
await this._page.setClientRequestInterceptor(undefined);
|
await this._page.setClientRequestInterceptor(undefined);
|
||||||
|
|
|
||||||
|
|
@ -231,11 +231,14 @@ export class Page extends SdkObject {
|
||||||
this.setDefaultNavigationTimeout(undefined);
|
this.setDefaultNavigationTimeout(undefined);
|
||||||
this.setDefaultTimeout(undefined);
|
this.setDefaultTimeout(undefined);
|
||||||
|
|
||||||
// To this first in order to unfreeze evaluates.
|
// Do this first in order to unfreeze evaluates.
|
||||||
await this._frameManager.closeOpenDialogs();
|
await this._frameManager.closeOpenDialogs();
|
||||||
|
|
||||||
await this.removeExposedBindings();
|
await this._removeExposedBindings();
|
||||||
await this.removeInitScripts();
|
await this._removeInitScripts();
|
||||||
|
|
||||||
|
// TODO: handle pending routes.
|
||||||
|
await this.setClientRequestInterceptor(undefined);
|
||||||
await this._setServerRequestInterceptor(undefined);
|
await this._setServerRequestInterceptor(undefined);
|
||||||
await this.setFileChooserIntercepted(false);
|
await this.setFileChooserIntercepted(false);
|
||||||
await this.mainFrame().goto(metadata, 'about:blank');
|
await this.mainFrame().goto(metadata, 'about:blank');
|
||||||
|
|
@ -334,7 +337,7 @@ export class Page extends SdkObject {
|
||||||
await this._delegate.exposeBinding(binding);
|
await this._delegate.exposeBinding(binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeExposedBindings() {
|
async _removeExposedBindings() {
|
||||||
for (const key of this._pageBindings.keys()) {
|
for (const key of this._pageBindings.keys()) {
|
||||||
if (!key.startsWith('__pw'))
|
if (!key.startsWith('__pw'))
|
||||||
this._pageBindings.delete(key);
|
this._pageBindings.delete(key);
|
||||||
|
|
@ -431,6 +434,7 @@ export class Page extends SdkObject {
|
||||||
this._emulatedMedia.reducedMotion = options.reducedMotion;
|
this._emulatedMedia.reducedMotion = options.reducedMotion;
|
||||||
if (options.forcedColors !== undefined)
|
if (options.forcedColors !== undefined)
|
||||||
this._emulatedMedia.forcedColors = options.forcedColors;
|
this._emulatedMedia.forcedColors = options.forcedColors;
|
||||||
|
|
||||||
await this._delegate.updateEmulateMedia();
|
await this._delegate.updateEmulateMedia();
|
||||||
await this._doSlowMo();
|
await this._doSlowMo();
|
||||||
}
|
}
|
||||||
|
|
@ -471,7 +475,7 @@ export class Page extends SdkObject {
|
||||||
await this._delegate.addInitScript(source);
|
await this._delegate.addInitScript(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeInitScripts() {
|
async _removeInitScripts() {
|
||||||
this.initScripts.splice(0, this.initScripts.length);
|
this.initScripts.splice(0, this.initScripts.length);
|
||||||
await this._delegate.removeInitScripts();
|
await this._delegate.removeInitScripts();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ if ((process as any)['__pw_initiator__']) {
|
||||||
type TestFixtures = PlaywrightTestArgs & PlaywrightTestOptions & {
|
type TestFixtures = PlaywrightTestArgs & PlaywrightTestOptions & {
|
||||||
_combinedContextOptions: BrowserContextOptions,
|
_combinedContextOptions: BrowserContextOptions,
|
||||||
_contextReuseEnabled: boolean,
|
_contextReuseEnabled: boolean,
|
||||||
|
_reuseContext: boolean,
|
||||||
_setupContextOptionsAndArtifacts: void;
|
_setupContextOptionsAndArtifacts: void;
|
||||||
_contextFactory: (options?: BrowserContextOptions) => Promise<BrowserContext>;
|
_contextFactory: (options?: BrowserContextOptions) => Promise<BrowserContext>;
|
||||||
};
|
};
|
||||||
|
|
@ -506,13 +507,15 @@ export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
|
||||||
testInfo.errors.push({ message: prependToError });
|
testInfo.errors.push({ message: prependToError });
|
||||||
}, { scope: 'test', _title: 'context' } as any],
|
}, { scope: 'test', _title: 'context' } as any],
|
||||||
|
|
||||||
_contextReuseEnabled: async ({ video, trace }, use, testInfo) => {
|
_contextReuseEnabled: !!process.env.PW_REUSE_CONTEXT,
|
||||||
const reuse = !!process.env.PW_REUSE_CONTEXT && !shouldCaptureVideo(normalizeVideoMode(video), testInfo) && !shouldCaptureTrace(normalizeTraceMode(trace), testInfo);
|
|
||||||
|
_reuseContext: async ({ video, trace, _contextReuseEnabled }, use, testInfo) => {
|
||||||
|
const reuse = _contextReuseEnabled && !shouldCaptureVideo(normalizeVideoMode(video), testInfo) && !shouldCaptureTrace(normalizeTraceMode(trace), testInfo);
|
||||||
await use(reuse);
|
await use(reuse);
|
||||||
},
|
},
|
||||||
|
|
||||||
context: async ({ playwright, browser, _contextReuseEnabled, _contextFactory }, use, testInfo) => {
|
context: async ({ playwright, browser, _reuseContext, _contextFactory }, use, testInfo) => {
|
||||||
if (!_contextReuseEnabled) {
|
if (!_reuseContext) {
|
||||||
await use(await _contextFactory());
|
await use(await _contextFactory());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -522,8 +525,8 @@ export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
|
||||||
await use(context);
|
await use(context);
|
||||||
},
|
},
|
||||||
|
|
||||||
page: async ({ context, _contextReuseEnabled }, use) => {
|
page: async ({ context, _reuseContext }, use) => {
|
||||||
if (!_contextReuseEnabled) {
|
if (!_reuseContext) {
|
||||||
await use(await context.newPage());
|
await use(await context.newPage());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { normalizeTraceMode, normalizeVideoMode, shouldCaptureTrace, shouldCaptureVideo } from './index';
|
|
||||||
import type { Fixtures, Locator, Page, BrowserContextOptions, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, BrowserContext } from './types';
|
import type { Fixtures, Locator, Page, BrowserContextOptions, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, BrowserContext } from './types';
|
||||||
import type { Component, JsxComponent, ObjectComponentOptions } from '../types/component';
|
import type { Component, JsxComponent, ObjectComponentOptions } from '../types/component';
|
||||||
|
|
||||||
|
|
@ -23,43 +22,19 @@ let boundCallbacksForMount: Function[] = [];
|
||||||
export const fixtures: Fixtures<
|
export const fixtures: Fixtures<
|
||||||
PlaywrightTestArgs & PlaywrightTestOptions & { mount: (component: any, options: any) => Promise<Locator> },
|
PlaywrightTestArgs & PlaywrightTestOptions & { mount: (component: any, options: any) => Promise<Locator> },
|
||||||
PlaywrightWorkerArgs & PlaywrightWorkerOptions & { _ctWorker: { context: BrowserContext | undefined, hash: string } },
|
PlaywrightWorkerArgs & PlaywrightWorkerOptions & { _ctWorker: { context: BrowserContext | undefined, hash: string } },
|
||||||
{ _contextFactory: (options?: BrowserContextOptions) => Promise<BrowserContext> }> = {
|
{ _contextFactory: (options?: BrowserContextOptions) => Promise<BrowserContext>, _contextReuseEnabled: boolean }> = {
|
||||||
|
|
||||||
|
_contextReuseEnabled: true,
|
||||||
|
|
||||||
|
serviceWorkers: 'block',
|
||||||
|
|
||||||
_ctWorker: [{ context: undefined, hash: '' }, { scope: 'worker' }],
|
_ctWorker: [{ context: undefined, hash: '' }, { scope: 'worker' }],
|
||||||
|
|
||||||
context: async ({ playwright, browser, _ctWorker, _contextFactory, video, trace }, use, testInfo) => {
|
page: async ({ page }, use) => {
|
||||||
const isolateTests = shouldCaptureVideo(normalizeVideoMode(video), testInfo) || shouldCaptureTrace(normalizeTraceMode(trace), testInfo);
|
await (page as any)._wrapApiCall(async () => {
|
||||||
const defaultContextOptions = (playwright.chromium as any)._defaultContextOptions as BrowserContextOptions;
|
await page.exposeFunction('__ct_dispatch', (ordinal: number, args: any[]) => {
|
||||||
const hash = contextHash(defaultContextOptions);
|
|
||||||
|
|
||||||
if (!_ctWorker.context || _ctWorker.hash !== hash || isolateTests) {
|
|
||||||
if (_ctWorker.context)
|
|
||||||
await _ctWorker.context.close();
|
|
||||||
// Context factory sets up video so we want to use that for isolated contexts.
|
|
||||||
// However, it closes the context after the test, so we don't want to use it
|
|
||||||
// for shared contexts.
|
|
||||||
_ctWorker.context = isolateTests ? await _contextFactory() : await browser.newContext();
|
|
||||||
_ctWorker.hash = hash;
|
|
||||||
await _ctWorker.context.addInitScript('navigator.serviceWorker.register = () => {}');
|
|
||||||
await _ctWorker.context.exposeFunction('__pw_dispatch', (ordinal: number, args: any[]) => {
|
|
||||||
boundCallbacksForMount[ordinal](...args);
|
boundCallbacksForMount[ordinal](...args);
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
await (_ctWorker.context as any)._resetForReuse();
|
|
||||||
}
|
|
||||||
await use(_ctWorker.context);
|
|
||||||
},
|
|
||||||
|
|
||||||
page: async ({ context, viewport }, use) => {
|
|
||||||
let page = context.pages()[0];
|
|
||||||
await (context as any)._wrapApiCall(async () => {
|
|
||||||
if (!page) {
|
|
||||||
page = await context.newPage();
|
|
||||||
} else {
|
|
||||||
await (page as any)._resetForReuse();
|
|
||||||
await page.goto('about:blank');
|
|
||||||
await page.setViewportSize(viewport || { width: 1280, height: 800 });
|
|
||||||
}
|
|
||||||
await page.goto(process.env.PLAYWRIGHT_VITE_COMPONENTS_BASE_URL!);
|
await page.goto(process.env.PLAYWRIGHT_VITE_COMPONENTS_BASE_URL!);
|
||||||
}, true);
|
}, true);
|
||||||
await use(page);
|
await use(page);
|
||||||
|
|
@ -94,7 +69,7 @@ async function innerMount(page: Page, jsxOrType: JsxComponent | string, options:
|
||||||
if (typeof value === 'string' && (value as string).startsWith('__pw_func_')) {
|
if (typeof value === 'string' && (value as string).startsWith('__pw_func_')) {
|
||||||
const ordinal = +value.substring('__pw_func_'.length);
|
const ordinal = +value.substring('__pw_func_'.length);
|
||||||
object[key] = (...args: any[]) => {
|
object[key] = (...args: any[]) => {
|
||||||
(window as any)['__pw_dispatch'](ordinal, args);
|
(window as any)['__ct_dispatch'](ordinal, args);
|
||||||
};
|
};
|
||||||
} else if (typeof value === 'object' && value) {
|
} else if (typeof value === 'object' && value) {
|
||||||
unwrapFunctions(value);
|
unwrapFunctions(value);
|
||||||
|
|
@ -130,29 +105,3 @@ function wrapFunctions(object: any, page: Page, callbacks: Function[]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function contextHash(context: BrowserContextOptions): string {
|
|
||||||
const hash = {
|
|
||||||
acceptDownloads: context.acceptDownloads,
|
|
||||||
bypassCSP: context.bypassCSP,
|
|
||||||
colorScheme: context.colorScheme,
|
|
||||||
extraHTTPHeaders: context.extraHTTPHeaders,
|
|
||||||
forcedColors: context.forcedColors,
|
|
||||||
geolocation: context.geolocation,
|
|
||||||
hasTouch: context.hasTouch,
|
|
||||||
httpCredentials: context.httpCredentials,
|
|
||||||
ignoreHTTPSErrors: context.ignoreHTTPSErrors,
|
|
||||||
isMobile: context.isMobile,
|
|
||||||
javaScriptEnabled: context.javaScriptEnabled,
|
|
||||||
locale: context.locale,
|
|
||||||
offline: context.offline,
|
|
||||||
permissions: context.permissions,
|
|
||||||
proxy: context.proxy,
|
|
||||||
storageState: context.storageState,
|
|
||||||
timezoneId: context.timezoneId,
|
|
||||||
userAgent: context.userAgent,
|
|
||||||
deviceScaleFactor: context.deviceScaleFactor,
|
|
||||||
serviceWorkers: context.serviceWorkers,
|
|
||||||
};
|
|
||||||
return JSON.stringify(hash);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import type { BrowserContext } from '@playwright/test';
|
||||||
import { contextTest as it, expect } from '../config/browserTest';
|
import { contextTest as it, expect } from '../config/browserTest';
|
||||||
|
|
||||||
it('expose binding should work', async ({ context }) => {
|
it('expose binding should work', async ({ context }) => {
|
||||||
|
|
@ -95,25 +96,23 @@ it('should work with CSP', async ({ page, context, server }) => {
|
||||||
expect(called).toBe(true);
|
expect(called).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should re-add binding after reset', async ({ page, context }) => {
|
it('should re-add binding after reset', async ({ browserType, browser }) => {
|
||||||
|
const defaultContextOptions = (browserType as any)._defaultContextOptions;
|
||||||
|
let context: BrowserContext = await (browser as any)._newContextForReuse(defaultContextOptions);
|
||||||
|
|
||||||
await context.exposeFunction('add', function(a, b) {
|
await context.exposeFunction('add', function(a, b) {
|
||||||
return Promise.resolve(a - b);
|
return Promise.resolve(a - b);
|
||||||
});
|
});
|
||||||
|
let page = await context.newPage();
|
||||||
expect(await page.evaluate('add(7, 6)')).toBe(1);
|
expect(await page.evaluate('add(7, 6)')).toBe(1);
|
||||||
|
|
||||||
await (context as any)._removeExposedBindings();
|
context = await (browser as any)._newContextForReuse(defaultContextOptions);
|
||||||
await context.exposeFunction('add', function(a, b) {
|
await context.exposeFunction('add', function(a, b) {
|
||||||
return Promise.resolve(a + b);
|
return Promise.resolve(a + b);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
page = context.pages()[0];
|
||||||
expect(await page.evaluate('add(5, 6)')).toBe(11);
|
expect(await page.evaluate('add(5, 6)')).toBe(11);
|
||||||
await page.reload();
|
await page.reload();
|
||||||
expect(await page.evaluate('add(5, 6)')).toBe(11);
|
expect(await page.evaluate('add(5, 6)')).toBe(11);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should retain internal binding after reset', async ({ page, context }) => {
|
|
||||||
await context.exposeFunction('__pw_add', function(a, b) {
|
|
||||||
return Promise.resolve(a + b);
|
|
||||||
});
|
|
||||||
await (context as any)._removeExposedBindings();
|
|
||||||
expect(await page.evaluate('__pw_add(5, 6)')).toBe(11);
|
|
||||||
});
|
|
||||||
|
|
|
||||||
|
|
@ -262,29 +262,6 @@ it('should work with setContent', async ({ page, server }) => {
|
||||||
expect(await page.evaluate('window.result')).toBe(6);
|
expect(await page.evaluate('window.result')).toBe(6);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should re-add binding after reset', async ({ page }) => {
|
|
||||||
await page.exposeFunction('add', function(a, b) {
|
|
||||||
return Promise.resolve(a - b);
|
|
||||||
});
|
|
||||||
expect(await page.evaluate('add(7, 6)')).toBe(1);
|
|
||||||
|
|
||||||
await (page as any)._removeExposedBindings();
|
|
||||||
await page.exposeFunction('add', function(a, b) {
|
|
||||||
return Promise.resolve(a + b);
|
|
||||||
});
|
|
||||||
expect(await page.evaluate('add(5, 6)')).toBe(11);
|
|
||||||
await page.reload();
|
|
||||||
expect(await page.evaluate('add(5, 6)')).toBe(11);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should retain internal binding after reset', async ({ page }) => {
|
|
||||||
await page.exposeFunction('__pw_add', function(a, b) {
|
|
||||||
return Promise.resolve(a + b);
|
|
||||||
});
|
|
||||||
await (page as any)._removeExposedBindings();
|
|
||||||
expect(await page.evaluate('__pw_add(5, 6)')).toBe(11);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should alias Window, Document and Node', async ({ page }) => {
|
it('should alias Window, Document and Node', async ({ page }) => {
|
||||||
let object: any;
|
let object: any;
|
||||||
await page.exposeBinding('log', (source, obj) => object = obj);
|
await page.exposeBinding('log', (source, obj) => object = obj);
|
||||||
|
|
|
||||||
|
|
@ -26,21 +26,21 @@ test('should reuse context', async ({ runInlineTest }) => {
|
||||||
'src/reuse.test.tsx': `
|
'src/reuse.test.tsx': `
|
||||||
//@no-header
|
//@no-header
|
||||||
import { test, expect } from '@playwright/experimental-ct-react';
|
import { test, expect } from '@playwright/experimental-ct-react';
|
||||||
let lastContext;
|
let lastContextGuid;
|
||||||
|
|
||||||
test('one', async ({ context }) => {
|
test('one', async ({ context }) => {
|
||||||
lastContext = context;
|
lastContextGuid = context._guid;
|
||||||
});
|
});
|
||||||
|
|
||||||
test('two', async ({ context }) => {
|
test('two', async ({ context }) => {
|
||||||
expect(context).toBe(lastContext);
|
expect(context._guid).toBe(lastContextGuid);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.describe('Dark', () => {
|
test.describe('Dark', () => {
|
||||||
test.use({ colorScheme: 'dark' });
|
test.use({ userAgent: 'dark' });
|
||||||
|
|
||||||
test('three', async ({ context }) => {
|
test('three', async ({ context }) => {
|
||||||
expect(context).not.toBe(lastContext);
|
expect(context._guid).not.toBe(lastContextGuid);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
`,
|
`,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue