Skip to content

Commit

Permalink
api(popups): move Page.setOfflineMode -> BrowserContext.setOffline (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
dgozman authored Mar 5, 2020
1 parent 3bedc60 commit 7f9df94
Show file tree
Hide file tree
Showing 14 changed files with 79 additions and 51 deletions.
13 changes: 8 additions & 5 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ Indicates that the browser is connected.
- `locale` <?[string]> Specify user locale, for example `en-GB`, `de-DE`, etc. Locale will affect `navigator.language` value, `Accept-Language` request header value as well as number and date formatting rules.
- `permissions` <[Object]> A map from origin keys to permissions values. See [browserContext.setPermissions](#browsercontextsetpermissionsorigin-permissions) for more details.
- `extraHTTPHeaders` <[Object]> An object containing additional HTTP headers to be sent with every request. All header values must be strings.
- `offline` <[boolean]> Whether to emulate network being offline for the browser context.
- returns: <[Promise]<[BrowserContext]>>

Creates a new browser context. It won't share cookies/cache with other browser contexts.
Expand Down Expand Up @@ -243,6 +244,7 @@ Creates a new browser context. It won't share cookies/cache with other browser c
- `locale` <?[string]> Specify user locale, for example `en-GB`, `de-DE`, etc. Locale will affect `navigator.language` value, `Accept-Language` request header value as well as number and date formatting rules.
- `permissions` <[Object]> A map from origin keys to permissions values. See [browserContext.setPermissions](#browsercontextsetpermissionsorigin-permissions) for more details.
- `extraHTTPHeaders` <[Object]> An object containing additional HTTP headers to be sent with every request. All header values must be strings.
- `offline` <[boolean]> Whether to emulate network being offline for the browser context.
- returns: <[Promise]<[Page]>>

Creates a new page in a new browser context. Closing this page will close the context as well.
Expand Down Expand Up @@ -287,6 +289,7 @@ await context.close();
- [browserContext.setDefaultTimeout(timeout)](#browsercontextsetdefaulttimeouttimeout)
- [browserContext.setExtraHTTPHeaders(headers)](#browsercontextsetextrahttpheadersheaders)
- [browserContext.setGeolocation(geolocation)](#browsercontextsetgeolocationgeolocation)
- [browserContext.setOffline(offline)](#browsercontextsetofflineoffline)
- [browserContext.setPermissions(origin, permissions[])](#browsercontextsetpermissionsorigin-permissions)
<!-- GEN:stop -->

Expand Down Expand Up @@ -509,6 +512,10 @@ await browserContext.setGeolocation({latitude: 59.95, longitude: 30.31667});

> **NOTE** Consider using [browserContext.setPermissions](#browsercontextsetpermissions-permissions) to grant permissions for the page to read its geolocation.
#### browserContext.setOffline(offline)
- `offline` <[boolean]> Whether to emulate network being offline for the browser context.
- returns: <[Promise]>

#### browserContext.setPermissions(origin, permissions[])
- `origin` <[string]> The [origin] to grant permissions to, e.g. "https://example.com".
- `permissions` <[Array]<[string]>> An array of permissions to grant. All permissions that are not listed here will be automatically denied. Permissions can be one of the following values:
Expand Down Expand Up @@ -635,7 +642,6 @@ page.removeListener('request', logRequest);
- [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout)
- [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout)
- [page.setExtraHTTPHeaders(headers)](#pagesetextrahttpheadersheaders)
- [page.setOfflineMode(enabled)](#pagesetofflinemodeenabled)
- [page.setViewportSize(viewportSize)](#pagesetviewportsizeviewportsize)
- [page.title()](#pagetitle)
- [page.tripleclick(selector[, options])](#pagetripleclickselector-options)
Expand Down Expand Up @@ -1475,10 +1481,6 @@ The extra HTTP headers will be sent with every request the page initiates.

> **NOTE** page.setExtraHTTPHeaders does not guarantee the order of headers in the outgoing requests.
#### page.setOfflineMode(enabled)
- `enabled` <[boolean]> When `true`, enables offline mode for the page.
- returns: <[Promise]>

#### page.setViewportSize(viewportSize)
- `viewportSize` <[Object]>
- `width` <[number]> page width in pixels. **required**
Expand Down Expand Up @@ -3723,6 +3725,7 @@ const backgroundPage = await backroundPageTarget.page();
- [browserContext.setDefaultTimeout(timeout)](#browsercontextsetdefaulttimeouttimeout)
- [browserContext.setExtraHTTPHeaders(headers)](#browsercontextsetextrahttpheadersheaders)
- [browserContext.setGeolocation(geolocation)](#browsercontextsetgeolocationgeolocation)
- [browserContext.setOffline(offline)](#browsercontextsetofflineoffline)
- [browserContext.setPermissions(origin, permissions[])](#browsercontextsetpermissionsorigin-permissions)
<!-- GEN:stop -->

Expand Down
2 changes: 2 additions & 0 deletions src/browserContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export type BrowserContextOptions = {
geolocation?: types.Geolocation,
permissions?: { [key: string]: string[] },
extraHTTPHeaders?: network.Headers,
offline?: boolean,
};

export interface BrowserContext {
Expand All @@ -46,6 +47,7 @@ export interface BrowserContext {
clearPermissions(): Promise<void>;
setGeolocation(geolocation: types.Geolocation | null): Promise<void>;
setExtraHTTPHeaders(headers: network.Headers): Promise<void>;
setOffline(offline: boolean): Promise<void>;
addInitScript(script: Function | string | { path?: string, content?: string }, ...args: any[]): Promise<void>;
exposeFunction(name: string, playwrightFunction: Function): Promise<void>;
close(): Promise<void>;
Expand Down
8 changes: 8 additions & 0 deletions src/chromium/crBrowser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ export class CRBrowserContext extends platform.EventEmitter implements BrowserCo
await Promise.all(entries.map(entry => this.setPermissions(entry[0], entry[1])));
if (this._options.geolocation)
await this.setGeolocation(this._options.geolocation);
if (this._options.offline)
await this.setOffline(this._options.offline);
}

_existingPages(): Page[] {
Expand Down Expand Up @@ -319,6 +321,12 @@ export class CRBrowserContext extends platform.EventEmitter implements BrowserCo
await (page._delegate as CRPage).updateExtraHTTPHeaders();
}

async setOffline(offline: boolean): Promise<void> {
this._options.offline = offline;
for (const page of this._existingPages())
await (page._delegate as CRPage)._networkManager.setOffline(offline);
}

async addInitScript(script: Function | string | { path?: string, content?: string }, ...args: any[]) {
const source = await helper.evaluationScript(script, args);
this._evaluateOnNewDocumentSources.push(source);
Expand Down
6 changes: 2 additions & 4 deletions src/chromium/crNetworkManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ export class CRNetworkManager {
private _page: Page;
private _requestIdToRequest = new Map<string, InterceptableRequest>();
private _requestIdToRequestWillBeSentEvent = new Map<string, Protocol.Network.requestWillBeSentPayload>();
private _offline = false;
private _credentials: {username: string, password: string} | null = null;
private _attemptedAuthentications = new Set<string>();
private _userRequestInterceptionEnabled = false;
Expand Down Expand Up @@ -68,10 +67,9 @@ export class CRNetworkManager {
await this._updateProtocolRequestInterception();
}

async setOfflineMode(value: boolean) {
this._offline = value;
async setOffline(offline: boolean) {
await this._client.send('Network.emulateNetworkConditions', {
offline: this._offline,
offline,
// values of 0 remove any active throttling. crbug.com/456324#c9
latency: 0,
downloadThroughput: -1,
Expand Down
6 changes: 2 additions & 4 deletions src/chromium/crPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ export class CRPage implements PageDelegate {
if (options.geolocation)
promises.push(this._client.send('Emulation.setGeolocationOverride', options.geolocation));
promises.push(this.updateExtraHTTPHeaders());
if (options.offline)
promises.push(this._networkManager.setOffline(options.offline));
for (const binding of this._browserContext._pageBindings.values())
promises.push(this._initBinding(binding));
for (const source of this._browserContext._evaluateOnNewDocumentSources)
Expand Down Expand Up @@ -373,10 +375,6 @@ export class CRPage implements PageDelegate {
await this._networkManager.setRequestInterception(enabled);
}

async setOfflineMode(value: boolean) {
await this._networkManager.setOfflineMode(value);
}

async authenticate(credentials: types.Credentials | null) {
await this._networkManager.authenticate(credentials);
}
Expand Down
8 changes: 8 additions & 0 deletions src/firefox/ffBrowser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,8 @@ export class FFBrowserContext extends platform.EventEmitter implements BrowserCo
await this.setGeolocation(this._options.geolocation);
if (this._options.extraHTTPHeaders)
await this.setExtraHTTPHeaders(this._options.extraHTTPHeaders);
if (this._options.offline)
await this.setOffline(this._options.offline);
}

_existingPages(): Page[] {
Expand Down Expand Up @@ -366,6 +368,12 @@ export class FFBrowserContext extends platform.EventEmitter implements BrowserCo
await this._browser._connection.send('Browser.setExtraHTTPHeaders', { browserContextId: this._browserContextId || undefined, headers: headersArray(this._options.extraHTTPHeaders) });
}

async setOffline(offline: boolean): Promise<void> {
if (offline)
throw new Error('Offline mode is not implemented in Firefox');
this._options.offline = offline;
}

async addInitScript(script: Function | string | { path?: string, content?: string }, ...args: any[]) {
const source = await helper.evaluationScript(script, args);
this._evaluateOnNewDocumentSources.push(source);
Expand Down
4 changes: 0 additions & 4 deletions src/firefox/ffPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,10 +279,6 @@ export class FFPage implements PageDelegate {
await this._networkManager.setRequestInterception(enabled);
}

async setOfflineMode(enabled: boolean): Promise<void> {
throw new Error('Offline mode not implemented in Firefox');
}

async authenticate(credentials: types.Credentials | null): Promise<void> {
await this._session.send('Network.setAuthCredentials', credentials || { username: null, password: null });
}
Expand Down
10 changes: 0 additions & 10 deletions src/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ export interface PageDelegate {
setEmulateMedia(mediaType: types.MediaType | null, colorScheme: types.ColorScheme | null): Promise<void>;
setCacheEnabled(enabled: boolean): Promise<void>;
setRequestInterception(enabled: boolean): Promise<void>;
setOfflineMode(enabled: boolean): Promise<void>;
authenticate(credentials: types.Credentials | null): Promise<void>;
setFileChooserIntercepted(enabled: boolean): Promise<void>;

Expand Down Expand Up @@ -82,7 +81,6 @@ type PageState = {
extraHTTPHeaders: network.Headers | null;
cacheEnabled: boolean | null;
interceptNetwork: boolean | null;
offlineMode: boolean | null;
credentials: types.Credentials | null;
hasTouch: boolean | null;
};
Expand Down Expand Up @@ -149,7 +147,6 @@ export class Page extends platform.EventEmitter {
extraHTTPHeaders: null,
cacheEnabled: null,
interceptNetwork: null,
offlineMode: null,
credentials: null,
hasTouch: null,
};
Expand Down Expand Up @@ -421,13 +418,6 @@ export class Page extends platform.EventEmitter {
request.continue();
}

async setOfflineMode(enabled: boolean) {
if (this._state.offlineMode === enabled)
return;
this._state.offlineMode = enabled;
await this._delegate.setOfflineMode(enabled);
}

async authenticate(credentials: types.Credentials | null) {
this._state.credentials = credentials;
await this._delegate.authenticate(credentials);
Expand Down
8 changes: 8 additions & 0 deletions src/webkit/wkBrowser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ export class WKBrowserContext extends platform.EventEmitter implements BrowserCo
await Promise.all(entries.map(entry => this.setPermissions(entry[0], entry[1])));
if (this._options.geolocation)
await this.setGeolocation(this._options.geolocation);
if (this._options.offline)
await this.setOffline(this._options.offline);
}

_existingPages(): Page[] {
Expand Down Expand Up @@ -291,6 +293,12 @@ export class WKBrowserContext extends platform.EventEmitter implements BrowserCo
await (page._delegate as WKPage).updateExtraHTTPHeaders();
}

async setOffline(offline: boolean): Promise<void> {
this._options.offline = offline;
for (const page of this._existingPages())
await (page._delegate as WKPage).updateOffline();
}

async addInitScript(script: Function | string | { path?: string, content?: string }, ...args: any[]) {
const source = await helper.evaluationScript(script, args);
this._evaluateOnNewDocumentSources.push(source);
Expand Down
8 changes: 4 additions & 4 deletions src/webkit/wkPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,6 @@ export class WKPage implements PageDelegate {

if (this._page._state.interceptNetwork)
promises.push(session.send('Network.setInterceptionEnabled', { enabled: true, interceptRequests: true }));
if (this._page._state.offlineMode)
promises.push(session.send('Network.setEmulateOfflineState', { offline: true }));
if (this._page._state.cacheEnabled === false)
promises.push(session.send('Network.setResourceCachingDisabled', { disabled: true }));

Expand All @@ -145,6 +143,8 @@ export class WKPage implements PageDelegate {
if (contextOptions.bypassCSP)
promises.push(session.send('Page.setBypassCSP', { enabled: true }));
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 }));
if (contextOptions.timezoneId) {
Expand Down Expand Up @@ -426,8 +426,8 @@ export class WKPage implements PageDelegate {
await this._updateState('Network.setInterceptionEnabled', { enabled, interceptRequests: enabled });
}

async setOfflineMode(offline: boolean) {
await this._updateState('Network.setEmulateOfflineState', { offline });
async updateOffline() {
await this._updateState('Network.setEmulateOfflineState', { offline: !!this._page.context()._options.offline });
}

async authenticate(credentials: types.Credentials | null) {
Expand Down
24 changes: 24 additions & 0 deletions test/browsercontext.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,30 @@ module.exports.describe = function({testRunner, expect, playwright, CHROMIUM, FF
});
});

describe.fail(FFOX)('BrowserContext.setOffline', function() {
it('should work with initial option', async({browser, server}) => {
const context = await browser.newContext({offline: true});
const page = await context.newPage();
let error = null;
await page.goto(server.EMPTY_PAGE).catch(e => error = e);
expect(error).toBeTruthy();
await context.setOffline(false);
const response = await page.goto(server.EMPTY_PAGE);
expect(response.status()).toBe(200);
await context.close();
});
it('should emulate navigator.onLine', async({browser, server}) => {
const context = await browser.newContext();
const page = await context.newPage();
expect(await page.evaluate(() => window.navigator.onLine)).toBe(true);
await context.setOffline(true);
expect(await page.evaluate(() => window.navigator.onLine)).toBe(false);
await context.setOffline(false);
expect(await page.evaluate(() => window.navigator.onLine)).toBe(true);
await context.close();
});
});

describe('Events.BrowserContext.Page', function() {
it('should report when a new page is created and closed', async({browser, server}) => {
const context = await browser.newContext();
Expand Down
19 changes: 0 additions & 19 deletions test/interception.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -524,25 +524,6 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
});
});

describe.fail(FFOX)('Interception.setOfflineMode', function() {
it('should work', async({page, server}) => {
await page.setOfflineMode(true);
let error = null;
await page.goto(server.EMPTY_PAGE).catch(e => error = e);
expect(error).toBeTruthy();
await page.setOfflineMode(false);
const response = await page.goto(server.EMPTY_PAGE);
expect(response.status()).toBe(200);
});
it('should emulate navigator.onLine', async({page, server}) => {
expect(await page.evaluate(() => window.navigator.onLine)).toBe(true);
await page.setOfflineMode(true);
expect(await page.evaluate(() => window.navigator.onLine)).toBe(false);
await page.setOfflineMode(false);
expect(await page.evaluate(() => window.navigator.onLine)).toBe(true);
});
});

describe('Interception vs isNavigationRequest', () => {
it('should work with request interception', async({page, server}) => {
const requests = new Map();
Expand Down
12 changes: 12 additions & 0 deletions test/popup.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ module.exports.describe = function({testRunner, expect, playwright, CHROMIUM, WE
await context.close();
expect(request.headers['foo']).toBe('bar');
});
it.fail(FFOX)('should inherit offline from browser context', async function({browser, server}) {
const context = await browser.newContext();
const page = await context.newPage();
await page.goto(server.EMPTY_PAGE);
await context.setOffline(true);
const online = await page.evaluate(url => {
const win = window.open(url);
return win.navigator.onLine;
}, server.PREFIX + '/dummy.html');
await context.close();
expect(online).toBe(false);
});
it.skip(FFOX).fail(CHROMIUM)('should inherit touch support from browser context', async function({browser, server}) {
const context = await browser.newContext({
viewport: { width: 400, height: 500, isMobile: true }
Expand Down
2 changes: 1 addition & 1 deletion test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ if (process.env.BROWSER === 'firefox') {
...require('../lib/events').Events,
...require('../lib/chromium/events').Events,
};
missingCoverage = ['browserContext.setGeolocation', 'page.setOfflineMode'];
missingCoverage = ['browserContext.setGeolocation', 'browserContext.setOffline'];
} else if (process.env.BROWSER === 'webkit') {
product = 'WebKit';
events = require('../lib/events').Events;
Expand Down

0 comments on commit 7f9df94

Please sign in to comment.