geckodriver
geckodriver copied to clipboard
Each executed script has a different global scope
It appears that scripts executed through WebDriver are being executed in a different global scope than Firefox's main window. Not only that, it appears each script is executed in a different global scope from each other.
I am writing a cross-browser test suite, and this makes it very difficult to interact with JavaScript code loaded in the main browser window, since I can't rely on things like array.constructor === Uint8Array to be true in browser code for Uint8Arrays that I pass in through WebDriver.
I believe that this goes against the W3C WebDriver spec: https://www.w3.org/TR/webdriver/#dfn-execute-a-function-body. The section "The rules to execute a function body are as follows" indicates that the global scope for script execution should be the same as the current browsing context's active document. Additionally, the test case below produces the expected output when ran against Chrome and Safari.
Let me know if there is a better place to report this.
System
- Version: 0.27.0 (7b8c4f32cdde 2020-07-28 18:16 +0000)
- Platform: macOS 10.15.7
- Firefox: 82.0 (64-bit)
- Selenium: npm package [email protected]
- Node: v12.17.0
Testcase
const webdriver = require('selenium-webdriver');
async function run() {
const builder = new webdriver.Builder()
.forBrowser('firefox')
.usingServer('http://localhost:4444');
const driver = await builder.build();
// check if global context is the same as window's
console.log(await driver.executeScript("return window === globalThis;"));
// check if this script's Uint8Array is the same as globalThis's
console.log(await driver.executeScript("return globalThis.Uint8Array === Uint8Array;"));
// check if this script's Uint8Array is the same as window's
console.log(await driver.executeScript("return window.Uint8Array === Uint8Array;"));
// check if two different scripts' Uint8Arrays are the same
// saves a Uint8Array in window to be accessed by the next script
console.log(await driver.executeScript("window.array = new Uint8Array(); return window.array.constructor === Uint8Array;"));
console.log(await driver.executeScript("return window.array.constructor === Uint8Array;"));
await driver.quit();
}
run();
Expected output:
true
true
true
true
true
Actual output:
false
true
false
true
false
Stacktrace
No errors occur.
Trace-level log
Same problem here. In my case, I'm trying to inject code that I do not own: a UMD-formatted JavaScript file. It attaches its exported value to the globalThis object where available. Geckodriver's current behavior makes the value inaccessible to subsequent scripts.
A workaround:
const workaroundSource = `(function(globalThis) {
${source};
)(window));`
driver.executeScript(workaroundSource);
- Version: 0.28.0 (c00d2b6acd3f 2020-11-03 16:29 +0200)
- Platform: Ubuntu 18.04.5 LTS
- Firefox: 84.0 (64-bit)
- Selenium: npm package [email protected]
- Node: v12.16.1