diff --git a/docs/api.md b/docs/api.md index a8bc9ba5fe8d2..410cfe8c303d5 100644 --- a/docs/api.md +++ b/docs/api.md @@ -155,6 +155,7 @@ See [ChromiumBrowser], [FirefoxBrowser] and [WebKitBrowser] for browser-specific - [browser.isConnected()](#browserisconnected) - [browser.newContext([options])](#browsernewcontextoptions) - [browser.newPage([options])](#browsernewpageoptions) +- [browser.version()](#browserversion) #### event: 'disconnected' @@ -266,6 +267,12 @@ Creates a new page in a new browser context. Closing this page will close the co This is a convenience API that should only be used for the single-page scenarios and short snippets. Production code and testing frameworks should explicitly create [browser.newContext](#browsernewcontextoptions) followed by the [browserContext.newPage](#browsercontextnewpage) to control their exact life times. +#### browser.version() + +- returns: <[string]> + +Returns the browser version. + ### class: BrowserContext * extends: [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter) @@ -4180,6 +4187,7 @@ await browser.stopTracing(); - [browser.isConnected()](#browserisconnected) - [browser.newContext([options])](#browsernewcontextoptions) - [browser.newPage([options])](#browsernewpageoptions) +- [browser.version()](#browserversion) #### chromiumBrowser.newBrowserCDPSession() @@ -4387,6 +4395,7 @@ Firefox browser instance does not expose Firefox-specific features. - [browser.isConnected()](#browserisconnected) - [browser.newContext([options])](#browsernewcontextoptions) - [browser.newPage([options])](#browsernewpageoptions) +- [browser.version()](#browserversion) ### class: WebKitBrowser @@ -4402,6 +4411,7 @@ WebKit browser instance does not expose WebKit-specific features. - [browser.isConnected()](#browserisconnected) - [browser.newContext([options])](#browsernewcontextoptions) - [browser.newPage([options])](#browsernewpageoptions) +- [browser.version()](#browserversion) ### Environment Variables diff --git a/src/browser.ts b/src/browser.ts index 3907f453ae075..c9b153b9988d8 100644 --- a/src/browser.ts +++ b/src/browser.ts @@ -44,6 +44,7 @@ export interface Browser extends EventEmitter { newPage(options?: BrowserContextOptions): Promise; isConnected(): boolean; close(): Promise; + version(): string; } export abstract class BrowserBase extends EventEmitter implements Browser { @@ -61,6 +62,7 @@ export abstract class BrowserBase extends EventEmitter implements Browser { abstract contexts(): BrowserContext[]; abstract isConnected(): boolean; abstract _disconnect(): void; + abstract version(): string; async newPage(options?: BrowserContextOptions): Promise { const context = await this.newContext(options); diff --git a/src/chromium/crBrowser.ts b/src/chromium/crBrowser.ts index df35f6bfae007..98ee9e74d4625 100644 --- a/src/chromium/crBrowser.ts +++ b/src/chromium/crBrowser.ts @@ -41,6 +41,7 @@ export class CRBrowser extends BrowserBase { _serviceWorkers = new Map(); _devtools?: CRDevTools; _isMac = false; + private _version = ''; private _tracingRecording = false; private _tracingPath: string | null = ''; @@ -53,6 +54,7 @@ export class CRBrowser extends BrowserBase { const session = connection.rootSession; const version = await session.send('Browser.getVersion'); browser._isMac = version.userAgent.includes('Macintosh'); + browser._version = version.product.substring(version.product.indexOf('/') + 1); if (!options.persistent) { await session.send('Target.setAutoAttach', { autoAttach: true, waitForDebuggerOnStart: true, flatten: true }); return browser; @@ -110,6 +112,10 @@ export class CRBrowser extends BrowserBase { return Array.from(this._contexts.values()); } + version(): string { + return this._version; + } + _onAttachedToTarget({targetInfo, sessionId, waitingForDebugger}: Protocol.Target.attachedToTargetPayload) { if (targetInfo.type === 'browser') return; diff --git a/src/firefox/ffBrowser.ts b/src/firefox/ffBrowser.ts index 23dfd40f26f6a..bbda5f963e461 100644 --- a/src/firefox/ffBrowser.ts +++ b/src/firefox/ffBrowser.ts @@ -33,12 +33,14 @@ export class FFBrowser extends BrowserBase { readonly _ffPages: Map; readonly _contexts: Map; private _eventListeners: RegisteredListener[]; + private _version = ''; static async connect(transport: ConnectionTransport, options: BrowserOptions): Promise { const connection = new FFConnection(SlowMoTransport.wrap(transport, options.slowMo), options.loggers); const browser = new FFBrowser(connection, options); const promises: Promise[] = [ connection.send('Browser.enable', { attachToDefaultContext: !!options.persistent }), + browser._initVersion(), ]; if (options.persistent) { browser._defaultContext = new FFBrowserContext(browser, null, options.persistent); @@ -62,6 +64,11 @@ export class FFBrowser extends BrowserBase { ]; } + async _initVersion() { + const result = await this._connection.send('Browser.getInfo'); + this._version = result.version.substring(result.version.indexOf('/') + 1); + } + isConnected(): boolean { return !this._connection._closed; } @@ -81,6 +88,10 @@ export class FFBrowser extends BrowserBase { return Array.from(this._contexts.values()); } + version(): string { + return this._version; + } + _onDetachedFromTarget(payload: Protocol.Browser.detachedFromTargetPayload) { const ffPage = this._ffPages.get(payload.targetId)!; this._ffPages.delete(payload.targetId); diff --git a/src/rpc/channels.ts b/src/rpc/channels.ts index 10df89b2576c1..31cef8206508c 100644 --- a/src/rpc/channels.ts +++ b/src/rpc/channels.ts @@ -284,7 +284,9 @@ export type BrowserServerKillParams = {}; export type BrowserServerKillResult = void; // ----------- Browser ----------- -export type BrowserInitializer = {}; +export type BrowserInitializer = { + version: string, +}; export interface BrowserChannel extends Channel { on(event: 'close', callback: (params: BrowserCloseEvent) => void): this; close(params?: BrowserCloseParams): Promise; diff --git a/src/rpc/client/browser.ts b/src/rpc/client/browser.ts index b45e3dd52d699..942ed2b12d9d8 100644 --- a/src/rpc/client/browser.ts +++ b/src/rpc/client/browser.ts @@ -71,6 +71,10 @@ export class Browser extends ChannelOwner { return [...this._contexts]; } + version(): string { + return this._initializer.version; + } + async newPage(options: types.BrowserContextOptions & { logger?: LoggerSink } = {}): Promise { const context = await this.newContext(options); const page = await context.newPage(); diff --git a/src/rpc/protocol.yml b/src/rpc/protocol.yml index d189262fbc1ee..8fbd2bdd743ab 100644 --- a/src/rpc/protocol.yml +++ b/src/rpc/protocol.yml @@ -362,6 +362,9 @@ BrowserServer: Browser: type: interface + initializer: + version: string + commands: close: diff --git a/src/rpc/server/browserDispatcher.ts b/src/rpc/server/browserDispatcher.ts index 9de6f59e49ac1..de7d0cf3b0f70 100644 --- a/src/rpc/server/browserDispatcher.ts +++ b/src/rpc/server/browserDispatcher.ts @@ -27,7 +27,7 @@ import { headersArrayToObject } from '../serializers'; export class BrowserDispatcher extends Dispatcher implements BrowserChannel { constructor(scope: DispatcherScope, browser: BrowserBase) { - super(scope, browser, 'Browser', {}, true); + super(scope, browser, 'Browser', { version: browser.version() }, true); browser.on(Events.Browser.Disconnected, () => { this._dispatchEvent('close'); this._dispose(); diff --git a/src/webkit/wkBrowser.ts b/src/webkit/wkBrowser.ts index 95f93543e5cec..d93d3f4625e6f 100644 --- a/src/webkit/wkBrowser.ts +++ b/src/webkit/wkBrowser.ts @@ -28,6 +28,7 @@ import { kPageProxyMessageReceived, PageProxyMessageReceivedPayload, WKConnectio import { WKPage } from './wkPage'; const DEFAULT_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Safari/605.1.15'; +const BROWSER_VERSION = '14.0'; export class WKBrowser extends BrowserBase { private readonly _connection: WKConnection; @@ -85,6 +86,10 @@ export class WKBrowser extends BrowserBase { return Array.from(this._contexts.values()); } + version(): string { + return BROWSER_VERSION; + } + _onDownloadCreated(payload: Protocol.Playwright.downloadCreatedPayload) { const page = this._wkPages.get(payload.pageProxyId); if (!page) diff --git a/test/browser.jest.js b/test/browser.jest.js index 445fc22347eac..53853f9fc89f5 100644 --- a/test/browser.jest.js +++ b/test/browser.jest.js @@ -38,3 +38,13 @@ describe('Browser.newPage', function() { expect(error.message).toContain('Please use browser.newContext()'); }); }); + +describe('Browser.version', function() { + it('should work', async function({browser}) { + const version = browser.version(); + if (CHROMIUM) + expect(version.match(/^\d+\.\d+\.\d+\.\d+$/)).toBeTruthy(); + else + expect(version.match(/^\d+\.\d+$/)).toBeTruthy(); + }); +});