webdriverio: [š Bug]: isDisplayed() does not work correctly in multi-remote (multiple simultaneous) browsers (Chrome)
Have you read the Contributing Guidelines on issues?
- I have read the Contributing Guidelines on issues.
WebdriverIO Version
7.16.9
Node.js Version
v14.18.1
Mode
Standalone Mode
Which capabilities are you using?
config.maxInstances = 2; // This is important.
const headlessChromeOptions = {
"goog:chromeOptions": {
// to run chrome the following flags are required
// (see https://developers.google.com/web/updates/2017/04/headless-chrome)
args: ["--no-sandbox",
"enable-automation", // https://stackoverflow.com/a/43840128/1689770
"--disable-infobars", // https://stackoverflow.com/a/43840128/1689770
"--disable-dev-shm-usage", // https://stackoverflow.com/a/50725918/1689770
"--disable-browser-side-navigation", // https://stackoverflow.com/a/49123152/1689770
"--disable-gpu", // https://stackoverflow.com/questions/51959986/how-to-solve-selenium-chromedriver-timed-out-receiving-message-from-renderer-exc
"--enable-blink-features=TrustedDOMTypes", // This is enabled whether you like it or not in Chrome 77
],
prefs: {
credentials_enable_service: false,
directory_upgrade: true,
prompt_for_download: false,
"download.default_directory": downloadDir,
profile: {
password_manager_enabled: false,
default_content_setting_values: {automatic_downloads: 1}
},
},
localState: {
"browser.enabled_labs_experiments": ["calculate-native-win-occlusion@2"],
},
},
};
config.capabilities = {
Ryan: {
capabilities: {
browserName: "chrome",
...headlessChromeOptions,
}
},
Kons: {
capabilities: {
browserName: "chrome",
...headlessChromeOptions,
}
}
}
What happened?
Something broke running multiple browsers simultaneously between Chrome 94 and 96 (might have been 95, Iām not sure).
The problem is with the element.waitForDisplayed() function or more likely the element.isDisplayed() function. Iāve verified that isDisplayed() returns false when the element is clearly on the screen. isDisplayed() works in the first window, but not in the second. Unless you take a screenshot. You can wait for 10 seconds for something that takes a few ms to show up, and that wonāt help (element.isDisplayed() will return false). The only workaround is to take a screenshot.
Iāve been trying to work around this issue for 7 days, unsuccessfully. I canāt seem to reproduce this unless itās running headless in a Linux docker instance.
The exact same test case worked before I rebuilt my docker container, which caused it to update to Chrome 96 and caused this bug to appear.
Iāve also checked to make sure there are not duplicate of the elements that Iām looking for. This is not the problem.
Iād like to create a reproducible test, but I donāt know how. Can somebody point me to how to a good example of a Minimal Workable Example (MWE) multiple browser test?
What is your expected behavior?
I would expect element.isDisplayed() to return true if the element is on the screen.
How to reproduce the bug.
Iāve reproduced it here: https://github.com/rsshilli/wdio-isDisplayed-multi-browser
Relevant log output
I have GBs of chrome logs, but I canāt tell whatās important in this situation. Itās not failing, itās just returning false when it shouldnāt. Hereās an example of where I believe we called $("#proposeComments").isDisplayed() and it returned false, but itās hard to tell what was returned from this.
[1637677128.406][INFO]: [61c5ec7a87bef5b5557ccf725913e54f] COMMAND ExecuteAsyncScript {
"args": [ "#proposeComments" ],
"script": "return (function(selector, callbackWhenDone) {\r\n // Uncomment for verbose logging\r\n // console.log(\"Scrolling to \" + (selector.selector ? selector.selector : selector));\r\n const jqueryElement = $(selector.selector ? selector.selector : selector);\r\n\r\n // Scroll to the item\r\n const domElement = jqueryElement[0];\r\n if (domElement) {\r\n domElement.scrollIntoView({block: \"center\"});\r\n } else {\r\n throw new Error(\"ElementNotFound: Element '\" + selector + \"' could not be found, so it couldn't be scrolled to.\");\r\n }\r\n\r\n // Some items, like tables, are so large that they take up the whole screen and then you can't see the top of the table.\r\n // So we scroll up a bit.\r\n const parentDOM = $(window);\r\n if (jqueryElement.height() > parentDOM.innerHeight()) {\r\n // Uncomment for verbose logging\r\n // console.log(`Starting Offset: ${jqueryElement.offset().top} Parent: ${parentDOM.scrollTop()}`);\r\n callWhenScrollCompleted(() => {\r\n // Uncomment for verbose logging\r\n // console.log(`Ending Offset: ${jqueryElement.offset().top} Parent: ${parentDOM.scrollTop()}`);\r\n\r\n // The element is right at the top of the screen, which is probably behind the fixed banner. Move it down.\r\n parentDOM.scrollTop(jqueryElement.offset().top - 150);\r\n callWhenScrollCompleted(() => callbackWhenDone(), 200);\r\n });\r\n } else {\r\n callbackWhenDone();\r\n }\r\n\r\n
// Wait for scrolling to stop. See https://stackoverflow.com/a/57662932/491553\r\n function callWhenScrollCompleted(callback, checkTimeout = 100, parentElement = $(window)) {\r\n
const scrollTimeoutFunction = () => {\r\n // Scrolling is complete\r\n parentElement.off(\"scroll\");\r\n callback();\r\n };\r\n let scrollTimeout = setTimeout(scrollTimeoutFunction, checkTimeout);\r\n\r\n parentElement.on(\"scroll\", () => {\r\n clearTimeout(scrollTimeout);\r\n scrollTimeout = setTimeout(scrollTimeoutFunction, checkTimeout);\r\n });\r\n }\r\n }).apply(null, arguments)"
}
[1637677128.406][INFO]: Waiting for pending navigations...
[1637677128.406][DEBUG]: DevTools WebSocket Command: Runtime.evaluate (id=4838) 183EE76213D8072D36C435CBDA114464 {
"expression": "1"
}
[1637677128.407][DEBUG]: DevTools WebSocket Response: Runtime.evaluate (id=4838) 183EE76213D8072D36C435CBDA114464 {
"result": {
"description": "1",
"type": "number",
"value": 1
}
}
[1637677128.407][INFO]: Done waiting for pending navigations. Status: ok
[1637677128.407][DEBUG]: DevTools WebSocket Command: Runtime.evaluate (id=4839) 183EE76213D8072D36C435CBDA114464 {
"awaitPromise": true,
"expression": "(function() { // Copyright (c) 2012 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n/**\n * Enum f...",
"returnByValue": true
}
[1637677128.409][DEBUG]: DevTools WebSocket Response: Runtime.evaluate (id=4839) 183EE76213D8072D36C435CBDA114464 {
"result": {
"type": "object",
"value": {
"status": 0,
"value": null
}
}
}
[1637677128.410][DEBUG]: DevTools WebSocket Command: Runtime.evaluate (id=4840) 183EE76213D8072D36C435CBDA114464 {
"awaitPromise": true,
"expression": "(function() { // Copyright (c) 2012 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n/**\n * Enum f...",
"returnByValue": true
}
[1637677128.411][DEBUG]: DevTools WebSocket Response: Runtime.evaluate (id=4840) 183EE76213D8072D36C435CBDA114464 {
"result": {
"type": "object",
"value": {
"status": 0,
"value": {
"status": 0,
"value": null
}
}
}
}
Code of Conduct
- I agree to follow this projectās Code of Conduct
Is there an existing issue for this?
- I have searched the existing issues
About this issue
- Original URL
- State: open
- Created 3 years ago
- Reactions: 1
- Comments: 16 (6 by maintainers)
I know I wrote this in the bug above, but just in case you didnāt see it, the workaround is (mysteriously) to take a screenshot first. So, change:
to this:
Also, I donāt know why, but this bug is worse somehow in Chrome 121 than before. Iām seeing it in more places now. Also, it only seems to happen with modal windows. Weāre using Bootstrap modal windows, if that matters. I donāt understand why it doesnāt happen every time though.