webdriverio: [šŸ› Bug]: isDisplayed() does not work correctly in multi-remote (multiple simultaneous) browsers (Chrome)

Have you 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)

Most upvoted comments

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:

    await browser.$("#proposeComments").waitForVisible();

to this:

    /**
     * This is added as a workaround for https://github.com/webdriverio/webdriverio/issues/7738
     */
    await thisBrowser.saveScreenshot(path.join(__dirname, "dummyFile.png"));

    await browser.$("#proposeComments").waitForVisible();

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.

Screenshot 2023-05-10 at 7 09 24 PM isDisplayed() method isn't working