Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

api(popups): move Page.setOfflineMode -> BrowserContext.setOffline #1223

Merged
merged 1 commit into from
Mar 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -634,7 +641,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 @@ -1466,10 +1472,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 @@ -3710,6 +3712,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 @@ -412,13 +409,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