UNPKG

selenium-webdriver

Version:

The official WebDriver JavaScript bindings from the Selenium project

143 lines (113 loc) 4.23 kB
// 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 logInspector = require('../bidi/logInspector') const scriptManager = require('../bidi//scriptManager') const { LocalValue, ChannelValue } = require('../bidi/protocolValue') const fs = require('node:fs') const path = require('node:path') const by = require('./by') class Script { #driver #logInspector #script constructor(driver) { this.#driver = driver } // This should be done in the constructor. // But since it needs to call async methods we cannot do that in the constructor. // We can have a separate async method that initialises the Script instance. // However, that pattern does not allow chaining the methods as we would like the user to use it. // Since it involves awaiting to get the instance and then another await to call the method. // Using this allows the user to do this "await driver.script().addJavaScriptErrorHandler(callback)" async #init() { if (this.#logInspector !== undefined) { return } this.#logInspector = await logInspector(this.#driver) } async #initScript() { if (this.#script !== undefined) { return } this.#script = await scriptManager([], this.#driver) } async addJavaScriptErrorHandler(callback) { await this.#init() return await this.#logInspector.onJavascriptException(callback) } async removeJavaScriptErrorHandler(id) { await this.#init() await this.#logInspector.removeCallback(id) } async addConsoleMessageHandler(callback) { await this.#init() return this.#logInspector.onConsoleEntry(callback) } async removeConsoleMessageHandler(id) { await this.#init() await this.#logInspector.removeCallback(id) } async addDomMutationHandler(callback) { await this.#initScript() let argumentValues = [] let value = LocalValue.createChannelValue(new ChannelValue('channel_name')) argumentValues.push(value) const filePath = path.join(__dirname, 'atoms', 'bidi-mutation-listener.js') let mutationListener = fs.readFileSync(filePath, 'utf-8').toString() await this.#script.addPreloadScript(mutationListener, argumentValues) let id = await this.#script.onMessage(async (message) => { let payload = JSON.parse(message['data']['value']) let elements = await this.#driver.findElements({ css: '*[data-__webdriver_id=' + by.escapeCss(payload['target']) + ']', }) if (elements.length === 0) { return } let event = { element: elements[0], attribute_name: payload['name'], current_value: payload['value'], old_value: payload['oldValue'], } callback(event) }) return id } async removeDomMutationHandler(id) { await this.#initScript() await this.#script.removeCallback(id) } async pin(script) { await this.#initScript() return await this.#script.addPreloadScript(script) } async unpin(id) { await this.#initScript() await this.#script.removePreloadScript(id) } async execute(script, ...args) { await this.#initScript() const browsingContextId = await this.#driver.getWindowHandle() const argumentList = [] args.forEach((arg) => { argumentList.push(LocalValue.getArgument(arg)) }) const response = await this.#script.callFunctionInBrowsingContext(browsingContextId, script, true, argumentList) return response.result } } module.exports = Script