diff --git a/javascript/node/selenium-webdriver/bidi/browsingContext.js b/javascript/node/selenium-webdriver/bidi/browsingContext.js index 232766680c266..87a0e420073e5 100644 --- a/javascript/node/selenium-webdriver/bidi/browsingContext.js +++ b/javascript/node/selenium-webdriver/bidi/browsingContext.js @@ -15,6 +15,7 @@ // specific language governing permissions and limitations // under the License. +const { BrowsingContextInfo } = require('./browsingContextTypes') class BrowsingContext { constructor(driver) { this._driver = driver @@ -145,31 +146,6 @@ class NavigateResult { } } -class BrowsingContextInfo { - constructor(id, url, children, parentBrowsingContext) { - this._id = id - this._url = url - this._children = children - this._parentBrowsingContext = parentBrowsingContext - } - - get id() { - return this._id - } - - get url() { - return this._url - } - - get children() { - return this._children - } - - get parentBrowsingContext() { - return this._parentBrowsingContext - } -} - /** * initiate browsing context instance and return * @param driver diff --git a/javascript/node/selenium-webdriver/bidi/browsingContextInspector.js b/javascript/node/selenium-webdriver/bidi/browsingContextInspector.js new file mode 100644 index 0000000000000..a2f9b654506f4 --- /dev/null +++ b/javascript/node/selenium-webdriver/bidi/browsingContextInspector.js @@ -0,0 +1,95 @@ +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +const { + BrowsingContextInfo, + NavigationInfo, +} = require('./browsingContextTypes') + +class BrowsingContextInspector { + constructor(driver, browsingContextIds) { + this._driver = driver + this._browsingContextIds = browsingContextIds + } + + async init() { + this.bidi = await this._driver.getBidi() + } + + async onBrowsingContextCreated(callback) { + await this.subscribeAndHandleEvent( + 'browsingContext.contextCreated', + callback + ) + } + + async onDomContentLoaded(callback) { + await this.subscribeAndHandleEvent( + 'browsingContext.domContentLoaded', + callback + ) + } + + async onBrowsingContextLoaded(callback) { + await this.subscribeAndHandleEvent('browsingContext.load', callback) + } + + async subscribeAndHandleEvent(eventType, callback) { + if (this._browsingContextIds != null) { + await this.bidi.subscribe(eventType, this._browsingContextIds) + } else { + await this.bidi.subscribe(eventType) + } + this._on(callback) + } + + async _on(callback) { + this.ws = await this.bidi.socket + this.ws.on('message', (event) => { + const { params } = JSON.parse(Buffer.from(event.toString())) + if (params) { + let response = null + if ('navigation' in params) { + response = new NavigationInfo( + params.context, + params.navigation, + params.timestamp, + params.url + ) + } else if ('accepted' in params) { + /* Needs to be updated when browsers implement other events */ + } else { + response = new BrowsingContextInfo( + params.context, + params.url, + params.children, + params.parent + ) + } + callback(response) + } + }) + } +} + +async function getBrowsingContextInstance(driver, browsingContextIds = null) { + let instance = new BrowsingContextInspector(driver, browsingContextIds) + await instance.init() + return instance +} + +module.exports = getBrowsingContextInstance diff --git a/javascript/node/selenium-webdriver/bidi/browsingContextTypes.js b/javascript/node/selenium-webdriver/bidi/browsingContextTypes.js new file mode 100644 index 0000000000000..0ce3ded6595bd --- /dev/null +++ b/javascript/node/selenium-webdriver/bidi/browsingContextTypes.js @@ -0,0 +1,52 @@ +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +class BrowsingContextInfo { + constructor(id, url, children, parentBrowsingContext) { + this._id = id + this._url = url + this._children = children + this._parentBrowsingContext = parentBrowsingContext + } + + get id() { + return this._id + } + + get url() { + return this._url + } + + get children() { + return this._children + } + + get parentBrowsingContext() { + return this._parentBrowsingContext + } +} + +class NavigationInfo { + constructor(browsingContextId, navigationId, timestamp, url) { + this.browsingContextId = browsingContextId + this.navigationId = navigationId + this.timestamp = timestamp + this.url = url + } +} + +module.exports = { BrowsingContextInfo, NavigationInfo } diff --git a/javascript/node/selenium-webdriver/index.js b/javascript/node/selenium-webdriver/index.js index 4fb0e60c210d1..e14f2a6f031ac 100644 --- a/javascript/node/selenium-webdriver/index.js +++ b/javascript/node/selenium-webdriver/index.js @@ -41,6 +41,7 @@ const webdriver = require('./lib/webdriver') const select = require('./lib/select') const LogInspector = require('./bidi/logInspector') const BrowsingContext = require('./bidi/browsingContext') +const BrowsingConextInspector = require('./bidi/browsingContextInspector') const ScriptManager = require('./bidi/scriptManager') const Browser = capabilities.Browser @@ -800,4 +801,5 @@ exports.until = until exports.Select = select.Select exports.LogInspector = LogInspector exports.BrowsingContext = BrowsingContext +exports.BrowsingConextInspector = BrowsingConextInspector exports.ScriptManager = ScriptManager diff --git a/javascript/node/selenium-webdriver/test/bidi/bidi_test.js b/javascript/node/selenium-webdriver/test/bidi/bidi_test.js index 6bb50b799268a..0cc830ed237ad 100644 --- a/javascript/node/selenium-webdriver/test/bidi/bidi_test.js +++ b/javascript/node/selenium-webdriver/test/bidi/bidi_test.js @@ -24,6 +24,7 @@ const { Browser } = require('../../') const { Pages, suite } = require('../../lib/test') const logInspector = require('../../bidi/logInspector') const BrowsingContext = require('../../bidi/browsingContext') +const BrowsingConextInspector = require('../../bidi/browsingContextInspector') const filterBy = require('../../bidi/filterBy') const until = require('../../lib/until') @@ -398,6 +399,71 @@ suite( }) }) + describe('Browsing Context Inspector', function () { + it('can listen to window browsing context created event', async function () { + let contextInfo = null + const browsingConextInspector = await BrowsingConextInspector(driver) + await browsingConextInspector.onBrowsingContextCreated((entry) => { + contextInfo = entry + }) + + await driver.switchTo().newWindow('window') + const windowHandle = await driver.getWindowHandle() + assert.equal(contextInfo.id, windowHandle) + assert.equal(contextInfo.url, 'about:blank') + assert.equal(contextInfo.children, null) + assert.equal(contextInfo.parentBrowsingContext, null) + }) + + it('can listen to tab browsing context created event', async function () { + let contextInfo = null + const browsingConextInspector = await BrowsingConextInspector(driver) + await browsingConextInspector.onBrowsingContextCreated((entry) => { + contextInfo = entry + }) + + await driver.switchTo().newWindow('tab') + const tabHandle = await driver.getWindowHandle() + + assert.equal(contextInfo.id, tabHandle) + assert.equal(contextInfo.url, 'about:blank') + assert.equal(contextInfo.children, null) + assert.equal(contextInfo.parentBrowsingContext, null) + }) + + it('can listen to dom content loaded event', async function () { + const browsingConextInspector = await BrowsingConextInspector(driver) + let navigationInfo = null + await browsingConextInspector.onDomContentLoaded((entry) => { + navigationInfo = entry + }) + + const browsingContext = await BrowsingContext(driver, { + browsingContextId: await driver.getWindowHandle(), + }) + await browsingContext.navigate(Pages.logEntryAdded, 'complete') + + assert.equal(navigationInfo.browsingContextId, browsingContext.id) + assert(navigationInfo.url.includes('/bidi/logEntryAdded.html')) + }) + + it('can listen to browsing context loaded event', async function () { + let navigationInfo = null + const browsingConextInspector = await BrowsingConextInspector(driver) + + await browsingConextInspector.onBrowsingContextLoaded((entry) => { + navigationInfo = entry + }) + const browsingContext = await BrowsingContext(driver, { + browsingContextId: await driver.getWindowHandle(), + }) + await browsingContext.navigate(Pages.logEntryAdded, 'complete') + + assert.equal(navigationInfo.browsingContextId, browsingContext.id) + assert(navigationInfo.url.includes('/bidi/logEntryAdded.html')) + }) + }) + describe('Local Value', function () { it('can call function with undefined argument', async function () { const id = await driver.getWindowHandle()