diff --git a/docs/api/puppeteer.page.isserviceworkerbypassed.md b/docs/api/puppeteer.page.isserviceworkerbypassed.md new file mode 100644 index 00000000000..78f9d0fe6d0 --- /dev/null +++ b/docs/api/puppeteer.page.isserviceworkerbypassed.md @@ -0,0 +1,19 @@ +--- +sidebar_label: Page.isServiceWorkerBypassed +--- + +# Page.isServiceWorkerBypassed() method + +`true` if the service worker are being bypassed, `false` otherwise. + +#### Signature: + +```typescript +class Page { + isServiceWorkerBypassed(): boolean; +} +``` + +**Returns:** + +boolean diff --git a/docs/api/puppeteer.page.md b/docs/api/puppeteer.page.md index d84f8090bd0..55bc3f3b90c 100644 --- a/docs/api/puppeteer.page.md +++ b/docs/api/puppeteer.page.md @@ -117,6 +117,7 @@ page.off('request', logRequest); | [isClosed()](./puppeteer.page.isclosed.md) | | Indicates that the page has been closed. | | [isDragInterceptionEnabled()](./puppeteer.page.isdraginterceptionenabled.md) | | true if drag events are being intercepted, false otherwise. | | [isJavaScriptEnabled()](./puppeteer.page.isjavascriptenabled.md) | | true if the page has JavaScript enabled, false otherwise. | +| [isServiceWorkerBypassed()](./puppeteer.page.isserviceworkerbypassed.md) | | true if the service worker are being bypassed, false otherwise. | | [mainFrame()](./puppeteer.page.mainframe.md) | | The page's main frame. | | [metrics()](./puppeteer.page.metrics.md) | | Object containing metrics as key/value pairs. | | [off(eventName, handler)](./puppeteer.page.off.md) | | | @@ -130,6 +131,7 @@ page.off('request', logRequest); | [screenshot(options)](./puppeteer.page.screenshot_2.md) | | | | [select(selector, values)](./puppeteer.page.select.md) | | Triggers a change and input event once all the provided options have been selected. If there's no <select> element matching selector, the method throws an error. | | [setBypassCSP(enabled)](./puppeteer.page.setbypasscsp.md) | | Toggles bypassing page's Content-Security-Policy. | +| [setBypassServiceWorker(bypass)](./puppeteer.page.setbypassserviceworker.md) | | Toggles ignoring of service worker for each request. | | [setCacheEnabled(enabled)](./puppeteer.page.setcacheenabled.md) | | Toggles ignoring cache for each request based on the enabled state. By default, caching is enabled. | | [setContent(html, options)](./puppeteer.page.setcontent.md) | | Set the content of the page. | | [setCookie(cookies)](./puppeteer.page.setcookie.md) | | | diff --git a/docs/api/puppeteer.page.setbypassserviceworker.md b/docs/api/puppeteer.page.setbypassserviceworker.md new file mode 100644 index 00000000000..34fbd40ce30 --- /dev/null +++ b/docs/api/puppeteer.page.setbypassserviceworker.md @@ -0,0 +1,25 @@ +--- +sidebar_label: Page.setBypassServiceWorker +--- + +# Page.setBypassServiceWorker() method + +Toggles ignoring of service worker for each request. + +#### Signature: + +```typescript +class Page { + setBypassServiceWorker(bypass: boolean): Promise; +} +``` + +## Parameters + +| Parameter | Type | Description | +| --------- | ------- | ------------------------------------------------------- | +| bypass | boolean | Whether to bypass service worker and load from network. | + +**Returns:** + +Promise<void> diff --git a/packages/puppeteer-core/src/api/Page.ts b/packages/puppeteer-core/src/api/Page.ts index f18a25d767f..f60b2da0044 100644 --- a/packages/puppeteer-core/src/api/Page.ts +++ b/packages/puppeteer-core/src/api/Page.ts @@ -445,6 +445,13 @@ export class Page extends EventEmitter { super(); } + /** + * `true` if the service worker are being bypassed, `false` otherwise. + */ + isServiceWorkerBypassed(): boolean { + throw new Error('Not implemented'); + } + /** * `true` if drag events are being intercepted, `false` otherwise. */ @@ -687,6 +694,16 @@ export class Page extends EventEmitter { throw new Error('Not implemented'); } + /** + * Toggles ignoring of service worker for each request. + * + * @param bypass - Whether to bypass service worker and load from network. + */ + async setBypassServiceWorker(bypass: boolean): Promise; + async setBypassServiceWorker(): Promise { + throw new Error('Not implemented'); + } + /** * @param enabled - Whether to enable drag interception. * diff --git a/packages/puppeteer-core/src/common/Page.ts b/packages/puppeteer-core/src/common/Page.ts index 31157b0f69e..193133dba15 100644 --- a/packages/puppeteer-core/src/common/Page.ts +++ b/packages/puppeteer-core/src/common/Page.ts @@ -157,6 +157,7 @@ export class CDPPage extends Page { #fileChooserPromises = new Set>(); #disconnectPromise?: Promise; + #serviceWorkerBypassed = false; #userDragInterceptionEnabled = false; /** @@ -347,6 +348,10 @@ export class CDPPage extends Page { return this.#client; } + override isServiceWorkerBypassed(): boolean { + return this.#serviceWorkerBypassed; + } + override isDragInterceptionEnabled(): boolean { return this.#userDragInterceptionEnabled; } @@ -472,6 +477,11 @@ export class CDPPage extends Page { return this.#frameManager.networkManager.setRequestInterception(value); } + override async setBypassServiceWorker(bypass: boolean): Promise { + this.#serviceWorkerBypassed = bypass; + return this.#client.send('Network.setBypassServiceWorker', {bypass}); + } + override async setDragInterception(enabled: boolean): Promise { this.#userDragInterceptionEnabled = enabled; return this.#client.send('Input.setInterceptDrags', {enabled}); diff --git a/test/TestExpectations.json b/test/TestExpectations.json index 8dd05fe0787..9f802997124 100644 --- a/test/TestExpectations.json +++ b/test/TestExpectations.json @@ -521,6 +521,18 @@ "parameters": ["webDriverBiDi"], "expectations": ["FAIL"] }, + { + "testIdPattern": "[network.spec] network Page.setBypassServiceWorker *", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["webDriverBiDi"], + "expectations": ["FAIL"] + }, + { + "testIdPattern": "[network.spec] network Page.setBypassServiceWorker *", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox"], + "expectations": ["FAIL", "TIMEOUT"] + }, { "testIdPattern": "[oopif.spec] *", "platforms": ["darwin", "linux", "win32"], diff --git a/test/src/network.spec.ts b/test/src/network.spec.ts index b195f33bd8a..a6d5c817d54 100644 --- a/test/src/network.spec.ts +++ b/test/src/network.spec.ts @@ -855,4 +855,44 @@ describe('network', function () { } }); }); + + describe('Page.setBypassServiceWorker', async () => { + it('bypass for network', async () => { + const {page, server} = getTestState(); + + const responses = new Map(); + page.on('response', r => { + return !isFavicon(r) && responses.set(r.url().split('/').pop(), r); + }); + + // Load and re-load to make sure serviceworker is installed and running. + await page.goto(server.PREFIX + '/serviceworkers/fetch/sw.html', { + waitUntil: 'networkidle2', + }); + await page.evaluate(async () => { + return await (globalThis as any).activationPromise; + }); + await page.reload({ + waitUntil: 'networkidle2', + }); + + expect(page.isServiceWorkerBypassed()).toBe(false); + expect(responses.size).toBe(2); + expect(responses.get('sw.html').status()).toBe(200); + expect(responses.get('sw.html').fromServiceWorker()).toBe(true); + expect(responses.get('style.css').status()).toBe(200); + expect(responses.get('style.css').fromServiceWorker()).toBe(true); + + await page.setBypassServiceWorker(true); + await page.reload({ + waitUntil: 'networkidle2', + }); + + expect(page.isServiceWorkerBypassed()).toBe(true); + expect(responses.get('sw.html').status()).toBe(200); + expect(responses.get('sw.html').fromServiceWorker()).toBe(false); + expect(responses.get('style.css').status()).toBe(200); + expect(responses.get('style.css').fromServiceWorker()).toBe(false); + }); + }); });