Search code examples
node.jsecmascript-6cross-browserbrowserstacktestcafe

Selector Exists but Cannot obtain information about the node because the specified selector does not match any node in the DOM tree


I am using NodeJS and TestCafe to build an E2E test.

We have started using BrowserStack to execute cross-browser tests, and I am trying to run scripts against Windows7:firefox & Windows10:firefox.

When I execute TestCafe with these options then and only then do I get this failure. So I do not see this failure when I execute on Samsung Galaxy S9:chrome or Samsung Galaxy S9:firefox or Windows 10:edge or Windows 7:chrome.

Our site is designed to adapt to the browser window size. So if the window is small then we see a hamburger menu button that expands to give options like Login, Logout, Projects, etc... If the window is large or (wide) then everything is displayed on a header bar.

As I said, this all works fine on many different browsers, but not Firefox on Windows 7 or 10. I have tried to adapt my script code to work with the more complex scenario of catching the hamburger menu button if it is present and ignore it if it is not found in the DOM. I do NOT want to have any code in my solution that would check highly dynamic test scenario parameters/properties like screen resolution or specific browser or browser version, OS or OS version, etc... So NOTHING like:

if (OperatingSystem === 'Windows' && Browser === 'firefox')

--UGGG it is painful to even write that above line of code.

So this very well could be a browser specific scenario, but then again it worked fine with Samsung Galaxy Tab 4:firefox and Samsung Galaxy S9:firefox.

Here is what is happening: Since I am running the script on Windows 7 & 10 desktop with firefox, the hambuger menu is not found on the screen. However the condition:

if (await navbar.hamburgerMenu.exists === true) {
    // Execution gets here, even though there is NO hamburgerMenu button.
    // The next line triggers an error that kills the script.
    if (await navbar.hamburgerMenu.visible) {
        // The above line of code returns an error:
// Cannot obtain information about the node because the specified selector does not match any node in the DOM tree.
// Then how come it passed the hamburgerMenu.exists === true condition?!

I should also add that the hamburgerMenu selector is defined with a visibilityCheck: true

Although I know that it doesn't affect the results in this case, because

if (Selector('blablabla', {( visibilityCheck: true )})

is different then

if (Selector('blablabla').visible === true)

I already know that the first one doesn't resolve in a filter-if-condition as it is used above, and the recommended filter-if-condition is the second one, which is why I have used it.

However, the first if-condition in the code block should have prevented the code from ever getting to the second if-condition in the code block, since in-fact the hamburger menu button is not actually shown for this OS-browser combination.

The only other thing I can think of is that perhaps the .visible option on web elements in Windows Desktop:Firefox is somehow returning a different result or behavior then it would if it was Android:firefox or Desktop:chrome or Android:chrome.

I do not want to use a document.getElementByID method as this is not technically a CSS selector, and our entire enterprise is standardized on CSS selector so anything that walks the DOM other then a CSS selector won't make it past our code review process anyway.

So again, I am looking for a general purpose solution that will work in all these scenarios/situations. Any thoughts or ideas? Thanks in advance!!

Related (But different) question: TestCafe - How to check if a web element exists or does not exist without failing the test? TestCafe - How to check if a web element exists or does not exist without failing the test?


Solution

  • We ended up having to write a client function that would query a computed style by using a querySelector, and getting it's property value.

    The solution code ended up looking like this:

    const getHamburgerDisplayValue = ClientFunction(() => {
         var hamburgerDisplayValue;
    
         hamburgerDisplayValue = window.getComputedStyle(document.querySelector('span.navbar-burger')).getPropertyValue('display');
    
         return hamburgerDisplayValue;
     });
    

    Than the caller code just looked like this:

     var hamburgerDisplayValue = await Common.getHamburgerDisplayValue();
    
     // Act
     if (hamburgerDisplayValue === 'block') {
          await t.click(navbar.hamburgerMenu);
     }
     await t.click(navbar.login);