api(popups): expose BrowserContext.route() (#1295)
This commit is contained in:
parent
adee9a9bd3
commit
ea6978a3d8
41
docs/api.md
41
docs/api.md
|
|
@ -290,6 +290,7 @@ await context.close();
|
|||
- [browserContext.exposeFunction(name, playwrightFunction)](#browsercontextexposefunctionname-playwrightfunction)
|
||||
- [browserContext.newPage()](#browsercontextnewpage)
|
||||
- [browserContext.pages()](#browsercontextpages)
|
||||
- [browserContext.route(url, handler)](#browsercontextrouteurl-handler)
|
||||
- [browserContext.setCookies(cookies)](#browsercontextsetcookiescookies)
|
||||
- [browserContext.setDefaultNavigationTimeout(timeout)](#browsercontextsetdefaultnavigationtimeouttimeout)
|
||||
- [browserContext.setDefaultTimeout(timeout)](#browsercontextsetdefaulttimeouttimeout)
|
||||
|
|
@ -466,6 +467,38 @@ Creates a new page in the browser context.
|
|||
|
||||
An array of all pages inside the browser context.
|
||||
|
||||
#### browserContext.route(url, handler)
|
||||
- `url` <[string]|[RegExp]|[function]\([string]\):[boolean]> A glob pattern, regex pattern or predicate receiving [URL] to match while routing.
|
||||
- `handler` <[function]\([Request]\)> handler function to route the request.
|
||||
- returns: <[Promise]>.
|
||||
|
||||
Routing activates the request interception and enables `request.abort`, `request.continue` and `request.fulfill` methods on the request. This provides the capability to modify network requests that are made by any page in the browser context.
|
||||
|
||||
Once request interception is enabled, every request matching the url pattern will stall unless it's continued, fulfilled or aborted.
|
||||
An example of a naïve request interceptor that aborts all image requests:
|
||||
|
||||
```js
|
||||
const context = await browser.newContext();
|
||||
await context.route('**/*.{png,jpg,jpeg}', request => request.abort());
|
||||
const page = await context.newPage();
|
||||
await page.goto('https://example.com');
|
||||
await browser.close();
|
||||
```
|
||||
|
||||
or the same snippet using a regex pattern instead:
|
||||
|
||||
```js
|
||||
const context = await browser.newContext();
|
||||
await context.route(/(\.png$)|(\.jpg$)/, request => request.abort());
|
||||
const page = await context.newPage();
|
||||
await page.goto('https://example.com');
|
||||
await browser.close();
|
||||
```
|
||||
|
||||
Page routes (set up with [page.route(url, handler)](#pagerouteurl-handler)) take precedence over browser context routes when request matches both handlers.
|
||||
|
||||
> **NOTE** Enabling request interception disables http cache.
|
||||
|
||||
#### browserContext.setCookies(cookies)
|
||||
- `cookies` <[Array]<[Object]>>
|
||||
- `name` <[string]> **required**
|
||||
|
|
@ -1433,7 +1466,7 @@ If `key` is a single character and no modifier keys besides `Shift` are being he
|
|||
|
||||
#### page.route(url, handler)
|
||||
- `url` <[string]|[RegExp]|[function]\([string]\):[boolean]> A glob pattern, regex pattern or predicate receiving [URL] to match while routing.
|
||||
- `handler` <[function]\([Request]\)> handler function to router the request.
|
||||
- `handler` <[function]\([Request]\)> handler function to route the request.
|
||||
- returns: <[Promise]>.
|
||||
|
||||
Routing activates the request interception and enables `request.abort`, `request.continue` and
|
||||
|
|
@ -1445,7 +1478,6 @@ An example of a naïve request interceptor that aborts all image requests:
|
|||
```js
|
||||
const page = await browser.newPage();
|
||||
await page.route('**/*.{png,jpg,jpeg}', request => request.abort());
|
||||
// await page.route(/\.(png|jpeg|jpg)$/, request => request.abort()); // <-- same thing
|
||||
await page.goto('https://example.com');
|
||||
await browser.close();
|
||||
```
|
||||
|
|
@ -1459,7 +1491,9 @@ await page.goto('https://example.com');
|
|||
await browser.close();
|
||||
```
|
||||
|
||||
> **NOTE** Enabling request interception disables page caching.
|
||||
Page routes take precedence over browser context routes (set up with [browserContext.route(url, handler)](#browsercontextrouteurl-handler)) when request matches both handlers.
|
||||
|
||||
> **NOTE** Enabling request interception disables http cache.
|
||||
|
||||
#### page.screenshot([options])
|
||||
- `options` <[Object]> Options object which might have the following properties:
|
||||
|
|
@ -3987,6 +4021,7 @@ const backgroundPage = await backroundPageTarget.page();
|
|||
- [browserContext.exposeFunction(name, playwrightFunction)](#browsercontextexposefunctionname-playwrightfunction)
|
||||
- [browserContext.newPage()](#browsercontextnewpage)
|
||||
- [browserContext.pages()](#browsercontextpages)
|
||||
- [browserContext.route(url, handler)](#browsercontextrouteurl-handler)
|
||||
- [browserContext.setCookies(cookies)](#browsercontextsetcookiescookies)
|
||||
- [browserContext.setDefaultNavigationTimeout(timeout)](#browsercontextsetdefaultnavigationtimeouttimeout)
|
||||
- [browserContext.setDefaultTimeout(timeout)](#browsercontextsetdefaulttimeouttimeout)
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ export interface BrowserContext {
|
|||
setHTTPCredentials(httpCredentials: types.Credentials | null): Promise<void>;
|
||||
addInitScript(script: Function | string | { path?: string, content?: string }, ...args: any[]): Promise<void>;
|
||||
exposeFunction(name: string, playwrightFunction: Function): Promise<void>;
|
||||
route(url: types.URLMatch, handler: network.RouteHandler): Promise<void>;
|
||||
waitForEvent(event: string, optionsOrPredicate?: Function | (types.TimeoutOptions & { predicate?: Function })): Promise<any>;
|
||||
close(): Promise<void>;
|
||||
}
|
||||
|
|
@ -62,6 +63,7 @@ export abstract class BrowserContextBase extends platform.EventEmitter implement
|
|||
readonly _timeoutSettings = new TimeoutSettings();
|
||||
readonly _pageBindings = new Map<string, PageBinding>();
|
||||
readonly _options: BrowserContextOptions;
|
||||
readonly _routes: { url: types.URLMatch, handler: (request: network.Request) => any }[] = [];
|
||||
_closed = false;
|
||||
private readonly _closePromise: Promise<Error>;
|
||||
private _closePromiseFulfill: ((error: Error) => void) | undefined;
|
||||
|
|
@ -100,6 +102,7 @@ export abstract class BrowserContextBase extends platform.EventEmitter implement
|
|||
abstract setOffline(offline: boolean): Promise<void>;
|
||||
abstract addInitScript(script: string | Function | { path?: string | undefined; content?: string | undefined; }, ...args: any[]): Promise<void>;
|
||||
abstract exposeFunction(name: string, playwrightFunction: Function): Promise<void>;
|
||||
abstract route(url: types.URLMatch, handler: network.RouteHandler): Promise<void>;
|
||||
abstract close(): Promise<void>;
|
||||
|
||||
setDefaultNavigationTimeout(timeout: number) {
|
||||
|
|
|
|||
|
|
@ -393,6 +393,12 @@ export class CRBrowserContext extends BrowserContextBase {
|
|||
await (page._delegate as CRPage).exposeBinding(binding);
|
||||
}
|
||||
|
||||
async route(url: types.URLMatch, handler: network.RouteHandler): Promise<void> {
|
||||
this._routes.push({ url, handler });
|
||||
for (const page of this._existingPages())
|
||||
await (page._delegate as CRPage).updateRequestInterception();
|
||||
}
|
||||
|
||||
async close() {
|
||||
if (this._closed)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ export class CRPage implements PageDelegate {
|
|||
if (options.geolocation)
|
||||
promises.push(this._client.send('Emulation.setGeolocationOverride', options.geolocation));
|
||||
promises.push(this.updateExtraHTTPHeaders());
|
||||
promises.push(this.updateRequestInterception());
|
||||
if (options.offline)
|
||||
promises.push(this._networkManager.setOffline(options.offline));
|
||||
if (options.httpCredentials)
|
||||
|
|
@ -376,8 +377,8 @@ export class CRPage implements PageDelegate {
|
|||
await this._client.send('Emulation.setEmulatedMedia', { media: mediaType || '', features });
|
||||
}
|
||||
|
||||
async setRequestInterception(enabled: boolean): Promise<void> {
|
||||
await this._networkManager.setRequestInterception(enabled);
|
||||
async updateRequestInterception(): Promise<void> {
|
||||
await this._networkManager.setRequestInterception(this._page._needsRequestInterception());
|
||||
}
|
||||
|
||||
async setFileChooserIntercepted(enabled: boolean) {
|
||||
|
|
|
|||
|
|
@ -290,6 +290,12 @@ export class FFBrowserContext extends BrowserContextBase {
|
|||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
async route(url: types.URLMatch, handler: network.RouteHandler): Promise<void> {
|
||||
this._routes.push({ url, handler });
|
||||
throw new Error('Not implemented');
|
||||
// TODO: update interception on the context if this is a first route.
|
||||
}
|
||||
|
||||
async close() {
|
||||
if (this._closed)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -303,8 +303,8 @@ export class FFPage implements PageDelegate {
|
|||
});
|
||||
}
|
||||
|
||||
async setRequestInterception(enabled: boolean): Promise<void> {
|
||||
await this._networkManager.setRequestInterception(enabled);
|
||||
async updateRequestInterception(): Promise<void> {
|
||||
await this._networkManager.setRequestInterception(this._page._needsRequestInterception());
|
||||
}
|
||||
|
||||
async setFileChooserIntercepted(enabled: boolean) {
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ export type SetNetworkCookieParam = {
|
|||
sameSite?: 'Strict' | 'Lax' | 'None'
|
||||
};
|
||||
|
||||
export type RouteHandler = (request: Request) => void;
|
||||
|
||||
export function filterCookies(cookies: NetworkCookie[], urls: string | string[] = []): NetworkCookie[] {
|
||||
if (!Array.isArray(urls))
|
||||
urls = [ urls ];
|
||||
|
|
|
|||
29
src/page.ts
29
src/page.ts
|
|
@ -48,7 +48,7 @@ export interface PageDelegate {
|
|||
updateExtraHTTPHeaders(): Promise<void>;
|
||||
setViewportSize(viewportSize: types.Size): Promise<void>;
|
||||
setEmulateMedia(mediaType: types.MediaType | null, colorScheme: types.ColorScheme | null): Promise<void>;
|
||||
setRequestInterception(enabled: boolean): Promise<void>;
|
||||
updateRequestInterception(): Promise<void>;
|
||||
setFileChooserIntercepted(enabled: boolean): Promise<void>;
|
||||
|
||||
canScreenshotOutsideViewport(): boolean;
|
||||
|
|
@ -80,8 +80,6 @@ type PageState = {
|
|||
mediaType: types.MediaType | null;
|
||||
colorScheme: types.ColorScheme | null;
|
||||
extraHTTPHeaders: network.Headers | null;
|
||||
interceptNetwork: boolean | null;
|
||||
hasTouch: boolean | null;
|
||||
};
|
||||
|
||||
export type FileChooser = {
|
||||
|
|
@ -127,7 +125,7 @@ export class Page extends platform.EventEmitter {
|
|||
private _workers = new Map<string, Worker>();
|
||||
readonly pdf: ((options?: types.PDFOptions) => Promise<platform.BufferType>) | undefined;
|
||||
readonly coverage: any;
|
||||
readonly _requestHandlers: { url: types.URLMatch, handler: (request: network.Request) => void }[] = [];
|
||||
readonly _routes: { url: types.URLMatch, handler: (request: network.Request) => any }[] = [];
|
||||
_ownedContext: BrowserContext | undefined;
|
||||
|
||||
constructor(delegate: PageDelegate, browserContext: BrowserContextBase) {
|
||||
|
|
@ -150,8 +148,6 @@ export class Page extends platform.EventEmitter {
|
|||
mediaType: null,
|
||||
colorScheme: null,
|
||||
extraHTTPHeaders: null,
|
||||
interceptNetwork: null,
|
||||
hasTouch: null,
|
||||
};
|
||||
this.accessibility = new accessibility.Accessibility(delegate.getAccessibilityTree.bind(delegate));
|
||||
this.keyboard = new input.Keyboard(delegate.rawKeyboard);
|
||||
|
|
@ -391,19 +387,26 @@ export class Page extends platform.EventEmitter {
|
|||
await this._delegate.evaluateOnNewDocument(await helper.evaluationScript(script, args));
|
||||
}
|
||||
|
||||
async route(url: types.URLMatch, handler: (request: network.Request) => void) {
|
||||
if (!this._state.interceptNetwork) {
|
||||
this._state.interceptNetwork = true;
|
||||
await this._delegate.setRequestInterception(true);
|
||||
}
|
||||
this._requestHandlers.push({ url, handler });
|
||||
_needsRequestInterception(): boolean {
|
||||
return this._routes.length > 0 || this._browserContext._routes.length > 0;
|
||||
}
|
||||
|
||||
async route(url: types.URLMatch, handler: network.RouteHandler): Promise<void> {
|
||||
this._routes.push({ url, handler });
|
||||
await this._delegate.updateRequestInterception();
|
||||
}
|
||||
|
||||
_requestStarted(request: network.Request) {
|
||||
this.emit(Events.Page.Request, request);
|
||||
if (!request._isIntercepted())
|
||||
return;
|
||||
for (const { url, handler } of this._requestHandlers) {
|
||||
for (const { url, handler } of this._routes) {
|
||||
if (platform.urlMatches(request.url(), url)) {
|
||||
handler(request);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (const { url, handler } of this._browserContext._routes) {
|
||||
if (platform.urlMatches(request.url(), url)) {
|
||||
handler(request);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -315,6 +315,12 @@ export class WKBrowserContext extends BrowserContextBase {
|
|||
await (page._delegate as WKPage).exposeBinding(binding);
|
||||
}
|
||||
|
||||
async route(url: types.URLMatch, handler: network.RouteHandler): Promise<void> {
|
||||
this._routes.push({ url, handler });
|
||||
for (const page of this._existingPages())
|
||||
await (page._delegate as WKPage).updateRequestInterception();
|
||||
}
|
||||
|
||||
async close() {
|
||||
if (this._closed)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ export class WKPage implements PageDelegate {
|
|||
if (contextOptions.javaScriptEnabled === false)
|
||||
promises.push(this._pageProxySession.send('Emulation.setJavaScriptEnabled', { enabled: false }));
|
||||
if (this._page._state.viewportSize || contextOptions.viewport)
|
||||
promises.push(this._updateViewport(true /* updateTouch */));
|
||||
promises.push(this._updateViewport());
|
||||
promises.push(this.updateHttpCredentials());
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
|
@ -132,8 +132,7 @@ export class WKPage implements PageDelegate {
|
|||
session.send('Network.enable'),
|
||||
this._workers.initializeSession(session)
|
||||
];
|
||||
|
||||
if (this._page._state.interceptNetwork)
|
||||
if (this._page._needsRequestInterception())
|
||||
promises.push(session.send('Network.setInterceptionEnabled', { enabled: true, interceptRequests: true }));
|
||||
|
||||
const contextOptions = this._browserContext._options;
|
||||
|
|
@ -149,8 +148,7 @@ export class WKPage implements PageDelegate {
|
|||
promises.push(session.send('Network.setExtraHTTPHeaders', { headers: this._calculateExtraHTTPHeaders() }));
|
||||
if (contextOptions.offline)
|
||||
promises.push(session.send('Network.setEmulateOfflineState', { offline: true }));
|
||||
if (this._page._state.hasTouch)
|
||||
promises.push(session.send('Page.setTouchEmulationEnabled', { enabled: true }));
|
||||
promises.push(session.send('Page.setTouchEmulationEnabled', { enabled: contextOptions.viewport ? !!contextOptions.viewport.isMobile : false }));
|
||||
if (contextOptions.timezoneId) {
|
||||
promises.push(session.send('Page.setTimeZone', { timeZone: contextOptions.timezoneId }).
|
||||
catch(e => { throw new Error(`Invalid timezone ID: ${contextOptions.timezoneId}`); }));
|
||||
|
|
@ -476,10 +474,10 @@ export class WKPage implements PageDelegate {
|
|||
|
||||
async setViewportSize(viewportSize: types.Size): Promise<void> {
|
||||
assert(this._page._state.viewportSize === viewportSize);
|
||||
await this._updateViewport(false /* updateTouch */);
|
||||
await this._updateViewport();
|
||||
}
|
||||
|
||||
async _updateViewport(updateTouch: boolean): Promise<void> {
|
||||
async _updateViewport(): Promise<void> {
|
||||
let viewport = this._browserContext._options.viewport || { width: 0, height: 0 };
|
||||
const viewportSize = this._page._state.viewportSize;
|
||||
if (viewportSize)
|
||||
|
|
@ -492,12 +490,11 @@ export class WKPage implements PageDelegate {
|
|||
deviceScaleFactor: viewport.deviceScaleFactor || 1
|
||||
}),
|
||||
];
|
||||
if (updateTouch)
|
||||
promises.push(this._updateState('Page.setTouchEmulationEnabled', { enabled: !!viewport.isMobile }));
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
||||
async setRequestInterception(enabled: boolean): Promise<void> {
|
||||
async updateRequestInterception(): Promise<void> {
|
||||
const enabled = this._page._needsRequestInterception();
|
||||
await this._updateState('Network.setInterceptionEnabled', { enabled, interceptRequests: enabled });
|
||||
}
|
||||
|
||||
|
|
@ -735,7 +732,7 @@ export class WKPage implements PageDelegate {
|
|||
// TODO(einbinder) this will fail if we are an XHR document request
|
||||
const isNavigationRequest = event.type === 'Document';
|
||||
const documentId = isNavigationRequest ? event.loaderId : undefined;
|
||||
const request = new WKInterceptableRequest(session, !!this._page._state.interceptNetwork, frame, event, redirectChain, documentId);
|
||||
const request = new WKInterceptableRequest(session, this._page._needsRequestInterception(), frame, event, redirectChain, documentId);
|
||||
this._requestIdToRequest.set(event.requestId, request);
|
||||
this._page._frameManager.requestStarted(request.request);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -367,6 +367,44 @@ module.exports.describe = function({testRunner, expect, playwright, CHROMIUM, FF
|
|||
});
|
||||
});
|
||||
|
||||
describe.fail(FFOX)('BrowserContext.route', () => {
|
||||
it('should intercept', async({browser, server}) => {
|
||||
const context = await browser.newContext();
|
||||
let intercepted = false;
|
||||
await context.route('**/empty.html', request => {
|
||||
intercepted = true;
|
||||
expect(request.url()).toContain('empty.html');
|
||||
expect(request.headers()['user-agent']).toBeTruthy();
|
||||
expect(request.method()).toBe('GET');
|
||||
expect(request.postData()).toBe(undefined);
|
||||
expect(request.isNavigationRequest()).toBe(true);
|
||||
expect(request.resourceType()).toBe('document');
|
||||
expect(request.frame() === page.mainFrame()).toBe(true);
|
||||
expect(request.frame().url()).toBe('about:blank');
|
||||
request.continue();
|
||||
});
|
||||
const page = await context.newPage();
|
||||
const response = await page.goto(server.EMPTY_PAGE);
|
||||
expect(response.ok()).toBe(true);
|
||||
expect(intercepted).toBe(true);
|
||||
await context.close();
|
||||
});
|
||||
it('should yield to page.route', async({browser, server}) => {
|
||||
const context = await browser.newContext();
|
||||
await context.route('**/empty.html', request => {
|
||||
request.fulfill({ status: 200, body: 'context' });
|
||||
});
|
||||
const page = await context.newPage();
|
||||
await page.route('**/empty.html', request => {
|
||||
request.fulfill({ status: 200, body: 'page' });
|
||||
});
|
||||
const response = await page.goto(server.EMPTY_PAGE);
|
||||
expect(response.ok()).toBe(true);
|
||||
expect(await response.text()).toBe('page');
|
||||
await context.close();
|
||||
});
|
||||
});
|
||||
|
||||
describe('BrowserContext.setHTTPCredentials', function() {
|
||||
it('should work', async({browser, server}) => {
|
||||
server.setAuth('/empty.html', 'user', 'pass');
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
|||
|
||||
describe('Page.route', function() {
|
||||
it('should intercept', async({page, server}) => {
|
||||
await page.route('/empty.html', request => {
|
||||
let intercepted = false;
|
||||
await page.route('**/empty.html', request => {
|
||||
expect(request.url()).toContain('empty.html');
|
||||
expect(request.headers()['user-agent']).toBeTruthy();
|
||||
expect(request.method()).toBe('GET');
|
||||
|
|
@ -41,9 +42,11 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
|||
expect(request.frame() === page.mainFrame()).toBe(true);
|
||||
expect(request.frame().url()).toBe('about:blank');
|
||||
request.continue();
|
||||
intercepted = true;
|
||||
});
|
||||
const response = await page.goto(server.EMPTY_PAGE);
|
||||
expect(response.ok()).toBe(true);
|
||||
expect(intercepted).toBe(true);
|
||||
});
|
||||
it('should work when POST is redirected with 302', async({page, server}) => {
|
||||
server.setRedirect('/rredirect', '/empty.html');
|
||||
|
|
@ -516,7 +519,7 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
|||
|
||||
describe('ignoreHTTPSErrors', function() {
|
||||
it('should work with request interception', async({browser, httpsServer}) => {
|
||||
const context = await browser.newContext({ ignoreHTTPSErrors: true, interceptNetwork: true });
|
||||
const context = await browser.newContext({ ignoreHTTPSErrors: true });
|
||||
const page = await context.newPage();
|
||||
|
||||
await page.route('**/*', request => request.continue());
|
||||
|
|
|
|||
|
|
@ -39,6 +39,24 @@ module.exports.describe = function({testRunner, expect, playwright, CHROMIUM, WE
|
|||
expect(userAgent).toBe('hey');
|
||||
expect(request.headers['user-agent']).toBe('hey');
|
||||
});
|
||||
it.fail(CHROMIUM || FFOX)('should respect routes from browser context', async function({browser, server}) {
|
||||
const context = await browser.newContext();
|
||||
const page = await context.newPage();
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setContent('<a target=_blank rel=noopener href="empty.html">link</a>');
|
||||
let intercepted = false;
|
||||
await context.route('**/empty.html', request => {
|
||||
request.continue();
|
||||
intercepted = true;
|
||||
});
|
||||
const [popup] = await Promise.all([
|
||||
context.waitForEvent('page').then(pageEvent => pageEvent.page()),
|
||||
page.click('a'),
|
||||
]);
|
||||
await popup.waitForLoadState();
|
||||
await context.close();
|
||||
expect(intercepted).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('window.open', function() {
|
||||
|
|
@ -122,6 +140,19 @@ module.exports.describe = function({testRunner, expect, playwright, CHROMIUM, WE
|
|||
await context.close();
|
||||
expect(size).toEqual({width: 400, height: 500});
|
||||
});
|
||||
it.fail(FFOX)('should respect routes from browser context', async function({browser, server}) {
|
||||
const context = await browser.newContext();
|
||||
const page = await context.newPage();
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
let intercepted = false;
|
||||
await context.route('**/empty.html', request => {
|
||||
request.continue();
|
||||
intercepted = true;
|
||||
});
|
||||
await page.evaluate(url => window.__popup = window.open(url), server.EMPTY_PAGE);
|
||||
await context.close();
|
||||
expect(intercepted).toBe(true);
|
||||
});
|
||||
it('should apply addInitScript from browser context', async function({browser, server}) {
|
||||
const context = await browser.newContext();
|
||||
await context.addInitScript(() => window.injected = 123);
|
||||
|
|
|
|||
Loading…
Reference in a new issue