diff --git a/browsers.json b/browsers.json
index 2d9fc67c8b..4cef872285 100644
--- a/browsers.json
+++ b/browsers.json
@@ -7,7 +7,7 @@
},
{
"name": "firefox",
- "revision": "1128"
+ "revision": "1134"
},
{
"name": "webkit",
diff --git a/docs/api.md b/docs/api.md
index f69cc7ba87..99095ae440 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -702,6 +702,7 @@ page.removeListener('request', logRequest);
- [page.addInitScript(script[, arg])](#pageaddinitscriptscript-arg)
- [page.addScriptTag(options)](#pageaddscripttagoptions)
- [page.addStyleTag(options)](#pageaddstyletagoptions)
+- [page.bringToFront()](#pagebringtofront)
- [page.check(selector, [options])](#pagecheckselector-options)
- [page.click(selector[, options])](#pageclickselector-options)
- [page.close([options])](#pagecloseoptions)
@@ -1007,6 +1008,14 @@ Adds a `` tag into the page with the desired url or a `
+
+Brings page to front (activates tab).
+
+
#### page.check(selector, [options])
- `selector` <[string]> A selector to search for checkbox or radio button to check. If there are multiple elements satisfying the selector, the first will be checked. See [working with selectors](#working-with-selectors) for more details.
- `options` <[Object]>
diff --git a/src/chromium/crPage.ts b/src/chromium/crPage.ts
index d9b5084142..96eb895831 100644
--- a/src/chromium/crPage.ts
+++ b/src/chromium/crPage.ts
@@ -143,6 +143,10 @@ export class CRPage implements PageDelegate {
await this._mainFrameSession._updateViewport();
}
+ async bringToFront(): Promise {
+ await this._mainFrameSession._client.send('Page.bringToFront');
+ }
+
async updateEmulateMedia(): Promise {
await this._forAllFrameSessions(frame => frame._updateEmulateMedia());
}
diff --git a/src/firefox/ffPage.ts b/src/firefox/ffPage.ts
index 444a655fc4..4855609745 100644
--- a/src/firefox/ffPage.ts
+++ b/src/firefox/ffPage.ts
@@ -286,6 +286,10 @@ export class FFPage implements PageDelegate {
});
}
+ async bringToFront(): Promise {
+ await this._session.send('Page.bringToFront', {});
+ }
+
async updateEmulateMedia(): Promise {
const colorScheme = this._page._state.colorScheme || this._browserContext._options.colorScheme || 'light';
await this._session.send('Page.setEmulatedMedia', {
diff --git a/src/firefox/protocol.ts b/src/firefox/protocol.ts
index 60af6f935d..6b8a88a354 100644
--- a/src/firefox/protocol.ts
+++ b/src/firefox/protocol.ts
@@ -409,6 +409,9 @@ export module Protocol {
}|null;
};
export type setViewportSizeReturnValue = void;
+ export type bringToFrontParameters = {
+ };
+ export type bringToFrontReturnValue = void;
export type setEmulatedMediaParameters = {
type?: ("screen"|"print"|"");
colorScheme?: ("dark"|"light"|"no-preference");
@@ -963,6 +966,7 @@ export module Protocol {
"Page.setFileInputFiles": Page.setFileInputFilesParameters;
"Page.addBinding": Page.addBindingParameters;
"Page.setViewportSize": Page.setViewportSizeParameters;
+ "Page.bringToFront": Page.bringToFrontParameters;
"Page.setEmulatedMedia": Page.setEmulatedMediaParameters;
"Page.setCacheDisabled": Page.setCacheDisabledParameters;
"Page.describeNode": Page.describeNodeParameters;
@@ -1033,6 +1037,7 @@ export module Protocol {
"Page.setFileInputFiles": Page.setFileInputFilesReturnValue;
"Page.addBinding": Page.addBindingReturnValue;
"Page.setViewportSize": Page.setViewportSizeReturnValue;
+ "Page.bringToFront": Page.bringToFrontReturnValue;
"Page.setEmulatedMedia": Page.setEmulatedMediaReturnValue;
"Page.setCacheDisabled": Page.setCacheDisabledReturnValue;
"Page.describeNode": Page.describeNodeReturnValue;
diff --git a/src/page.ts b/src/page.ts
index aa476a76db..803c2a44ee 100644
--- a/src/page.ts
+++ b/src/page.ts
@@ -53,6 +53,7 @@ export interface PageDelegate {
updateEmulateMedia(): Promise;
updateRequestInterception(): Promise;
setFileChooserIntercepted(enabled: boolean): Promise;
+ bringToFront(): Promise;
canScreenshotOutsideViewport(): boolean;
resetViewport(): Promise; // Only called if canScreenshotOutsideViewport() returns false.
@@ -403,6 +404,10 @@ export class Page extends EventEmitter {
return this._state.viewportSize;
}
+ async bringToFront(): Promise {
+ await this._delegate.bringToFront();
+ }
+
async evaluate(pageFunction: js.Func1, arg: Arg): Promise;
async evaluate(pageFunction: js.Func1, arg?: any): Promise;
async evaluate(pageFunction: js.Func1, arg: Arg): Promise {
diff --git a/src/rpc/channels.ts b/src/rpc/channels.ts
index 1e3054deb9..46f522777a 100644
--- a/src/rpc/channels.ts
+++ b/src/rpc/channels.ts
@@ -544,6 +544,7 @@ export interface PageChannel extends Channel {
crStopJSCoverage(params?: PageCrStopJSCoverageParams): Promise;
crStartCSSCoverage(params: PageCrStartCSSCoverageParams): Promise;
crStopCSSCoverage(params?: PageCrStopCSSCoverageParams): Promise;
+ bringToFront(params?: PageBringToFrontParams): Promise;
}
export type PageBindingCallEvent = {
binding: BindingCallChannel,
@@ -798,6 +799,8 @@ export type PageCrStopCSSCoverageResult = {
}[],
}[],
};
+export type PageBringToFrontParams = {};
+export type PageBringToFrontResult = void;
// ----------- Frame -----------
export type FrameInitializer = {
diff --git a/src/rpc/client/page.ts b/src/rpc/client/page.ts
index 4ac3ac35e1..dce4f1983f 100644
--- a/src/rpc/client/page.ts
+++ b/src/rpc/client/page.ts
@@ -414,6 +414,12 @@ export class Page extends ChannelOwner {
return this._attributeToPage(() => this._mainFrame.title());
}
+ async bringToFront(): Promise {
+ return this._wrapApiCall('page.bringToFront', async () => {
+ await this._channel.bringToFront();
+ });
+ }
+
async close(options: { runBeforeUnload?: boolean } = {runBeforeUnload: undefined}) {
return this._wrapApiCall('page.close', async () => {
await this._channel.close(options);
diff --git a/src/rpc/protocol.pdl b/src/rpc/protocol.pdl
index 665c858de1..b2bdb403eb 100644
--- a/src/rpc/protocol.pdl
+++ b/src/rpc/protocol.pdl
@@ -718,6 +718,8 @@ interface Page
start: number
end: number
+ command bringToFront
+
interface Frame
initializer
url: string
diff --git a/src/rpc/server/pageDispatcher.ts b/src/rpc/server/pageDispatcher.ts
index a0f68f59b5..50a9e398bf 100644
--- a/src/rpc/server/pageDispatcher.ts
+++ b/src/rpc/server/pageDispatcher.ts
@@ -195,6 +195,10 @@ export class PageDispatcher extends Dispatcher implements
return { pdf: buffer.toString('base64') };
}
+ async bringToFront(): Promise {
+ await this._page.bringToFront();
+ }
+
async crStartJSCoverage(params: types.JSCoverageOptions): Promise {
const coverage = this._page.coverage as CRCoverage;
await coverage.startJSCoverage(params);
diff --git a/src/webkit/wkPage.ts b/src/webkit/wkPage.ts
index 6726195831..0e20f19f6e 100644
--- a/src/webkit/wkPage.ts
+++ b/src/webkit/wkPage.ts
@@ -576,6 +576,12 @@ export class WKPage implements PageDelegate {
await this._updateViewport();
}
+ async bringToFront(): Promise {
+ this._pageProxySession.send('Target.activate', {
+ targetId: this._session.sessionId
+ });
+ }
+
async _updateViewport(): Promise {
const options = this._browserContext._options;
const viewportSize = this._page._state.viewportSize;
diff --git a/test/headful.jest.js b/test/headful.jest.js
index 1612139587..0f0c863174 100644
--- a/test/headful.jest.js
+++ b/test/headful.jest.js
@@ -143,4 +143,22 @@ describe('Headful', function() {
await context.close();
await browser.close();
});
+ it('Page.bringToFront should work', async ({browserType, defaultBrowserOptions}) => {
+ const browser = await browserType.launch({...defaultBrowserOptions, headless: false });
+ const page1 = await browser.newPage();
+ await page1.setContent('Page1')
+ const page2 = await browser.newPage();
+ await page2.setContent('Page2')
+
+ await page1.bringToFront();
+ expect(await page1.evaluate('document.visibilityState')).toBe('visible');
+ expect(await page2.evaluate('document.visibilityState')).toBe('visible');
+
+ await page2.bringToFront();
+ expect(await page1.evaluate('document.visibilityState')).toBe('visible');
+ expect(await page2.evaluate('document.visibilityState')).toBe(
+ 'visible'
+ );
+ await browser.close();
+ });
});