Protractor's isDisplayed method may return a false value for an element that is actually visible

UPDATE #4: Eureka!!

I made a breakthrough by recursively navigating through the parent nodes and returning the same values as shown below. Surprisingly, one of the parent nodes - the inner mat-drawer-container - also returned false for isDisplayed, while all others returned true which seemed peculiar.

Upon inspecting that particular node, I discovered that it was the only tag on the site with the CSS property display: contents. Removing this attribute resulted in the button in question - along with everything else below it - being identified as visible. In fact, Protractor was even able to click the button and display the expected result in the browser.

Now the lingering question is: is this behavior expected or is it a bug? It's not simply a case of an ancestor having display: contents applied; when I directly applied it to rb-container, Protractor was still able to locate the button.


I'm currently delving into end-to-end testing using Protractor for the first time, and I've hit a snag when attempting to check for the visibility of a button. Despite the button element being present in the DOM and visible, the isDisplayed method returns false causing my assertion to fail.

Here is the initial failing assertion:

expect(element(by.css("mat-drawer-content rb-container rb-fab-button[data-qaid='create-button'] > button")).isDisplayed()).toBe(true);

(Yes, I agree, the selector is quite convoluted, but unfortunately, I have no control over the HTML structure.)

To investigate further, I introduced a lengthy browser.sleep() interval to effectively pause the browser so I could use the developer tools to examine the visibly-displayed element. According to the CSS properties, it should indeed be recognized as visible.

After exhausting all avenues without success, I resorted to logging some data to the console which reinforced my belief that isDisplayed should yield a positive result:

[ UPDATES #2, #3: Logged additional information about all the direct children of rb-container; only one node appears "visible" based on Protractor's assessment. ]

  let selector = element.all(by.tagName("mat-drawer-content")).get(0).all(by.css("rb-container > *"));

  selector.count().then(function(selCount) {

    for (let match = 0; match < selCount; match ++) {

      browser.sleep(1000).then(() => {
        let elm = selector.get(match);

        console.log("\n >> " + match + "]");

        elm.getTagName().then(tag => { console.log("tag name:", tag); });
        elm.getCssValue("visibility").then(vis => { console.log("visibility:", vis); });
        elm.getCssValue("display").then(disp => { console.log("display:", disp); });
        elm.getCssValue("opacity").then(opa => { console.log("opacity:", opa); });
        elm.getCssValue("overflow").then(ov => { console.log("overflow:", ov); });
        elm.getAttribute("hidden").then(hid => { console.log("hidden:", hid); });
        elm.getAttribute("class").then(c => { console.log("class:", c)});
        elm.getSize().then(size => { console.log("size:", size); });
        elm.getCssValue("position").then(ov => { console.log("position:", ov); });
        elm.getLocation().then(loc => { console.log("location:", loc); });
        elm.isPresent().then(pres => { console.log("isPresent:", pres); });
        elm.isDisplayed().then(disp => { console.log("isDisplayed:", disp); });
      });

    }

  });

The logged information reveals the following details:

 >> 0]
tag name: div
visibility: visible
display: block
opacity: 1
...
isPresent: true
isDisplayed: false

 >> 1]
tag name: div
visibility: visible
display: block
opacity: 1
...
isPresent: true
isDisplayed: false

 >> 2]
tag name: rb-fab-button
visibility: visible
display: block
opacity: 1
...
isPresent: true
isDisplayed: false
 ...

<p>Node 4, the only child element where isDisplayed returns true, appears to be a key example to compare against node 2, the rb-fab-button element I am trying to access. The noticeable difference seems to be that rb-fab-button is absolutely positioned; however, other statically-positioned elements also return false for isDisplayed.</p>

<p>Could I be overlooking something here? I would settle for checking the CSS visibility instead, but my next task involves clicking that button, which will throw an error if the element is not deemed visible.</p>

<p>[ <em><strong>UPDATE #1:</strong> Included some HTML snippets:</em> ]</p>

<p><div>
<div>
<pre><code><mat-drawer-container _ngcontent-c0="" class="root-container w-100 mat-drawer-container mat-drawer-container-explicit-backdrop" hasbackdrop="true" ng-reflect-has-backdrop="true">
    <div class="mat-drawer-backdrop ng-star-inserted"></div>
    ...
</mat-drawer-container>

Answer №1

My approach involved recursively traversing through the parent nodes and returning consistent values. An interesting discovery was made regarding one particular parent node—the inner mat-drawer-container—which unexpectedly returned false for isDisplayed unlike the others.

Upon closer inspection, it was revealed that this specific element was the only tag on the website styled with display: contents. Upon removing this styling, the previously problematic button and other elements displayed correctly when queried by Protractor.

Now the question that arises is whether this behavior is intentional or a bug. It was observed that directly applying display: contents to rb-container did not hinder Protractor's ability to locate the button.

To further investigate this issue, I have created an entry on the Protractor GitHub page, which can be viewed here.


[UPDATE: Following additional research, I have identified that the issue stems from a combination of two CSS declarations: display: contents along with overflow: hidden.

In theory, it may seem counterintuitive to use these styles together as they attempt to hide overflow within a container element that does not physically exist. However, if a child element within this structure is visibly rendered by the browser—as demonstrated in this scenario—it should logically be considered visible by Protractor.

The provided HTML/CSS snippet illustrates this concept:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8>
    <title>isDisplayed() issue</title>
    <style>

    .not-displayed .display-contents {
        overflow: hidden;
        display: contents; 
    }

    </style>
</head>
<body>

<div class="not-displayed">
    <div class="display-contents">
        <div class="wrong">isDisplayed() returns false</div>
    </div>
</div>

<div class="displayed">
    <div class="display-contents">
        <div class="right">isDisplayed() returns true</div>
    </div>
</div>

</body>
</html>

The corresponding Spec file excerpt is provided below:

import { browser, by, element } from 'protractor';

describe('Testing the Protractor Bug', () => {

    it('should display debugging info', () => {

        browser.waitForAngularEnabled(false);
        browser.get('_[file location]_');

        element(by.css('.wrong')).isDisplayed().then(disp => { console.log('"wrong" isDisplayed:', disp); });
        element(by.css('.right')).isDisplayed().then(disp => { console.log('"right" isDisplayed:', disp); });

    });
});

The resultant output from running the test is as follows:

[17:04:50] I/launcher - Running 1 instances of WebDriver
[17:04:50] I/direct - Using ChromeDriver directly...

DevTools listening on ws://127.0.0.1:59412/devtools/browser/3f76f1a9-25f5-4497-8ae3-6933d01d0c7e
Jasmine started
"wrong" isDisplayed: false
"right" isDisplayed: true

  Testing the Protractor Bug
    √ should display debugging info

Executed 1 of 1 spec SUCCESS in 0.202 sec.
[17:04:53] I/launcher - 0 instance(s) of WebDriver still running
[17:04:53] I/launcher - chrome #01 passed

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using AngularJS translation capabilities with UI Router

I am working on an AngularJS application that utilizes the AngularJS Translate library from . The setup includes UI router to maintain the existing URL structure of the website, which has been indexed by Google with various language versions such as www.do ...

Transferring time for streaming MP3 files from server to HTML5 audio

Currently, my node.js server is set up to convert and stream mp3 files in real-time. I have integrated an HTML5 audio tag to play this stream, but I am encountering a problem - the audio element is unable to determine the duration of the mp3 until it has c ...

What is the best way to retrieve a document element in React when utilizing an external script?

In my React project, I have successfully implemented a chat button using an external script. However, I encountered an issue where I needed to hide the chat button on specific pages. Since I couldn't access the button's element using a ref, I res ...

What to do when a JWT token expires and how to generate a fresh token?

I am currently dealing with a problem regarding JWT (JSON Web Token) authentication in my application. At times, when I make API requests, I encounter the following error response: { "success": false, "message": "jwt expired" } I am aware that this er ...

Acquiring the assigned class attribute

I have an image that triggers ajax requests when clicked. To pass a variable from $_GET[] to my onclick function, I came up with the following solution: <img id="img1" class="<?=$_GET['value']"?> /> and using jQue ...

TinyMCE - Utilizing selection.setContent along with getContent for the Warp Button

I am looking to implement a button that will wrap content with all tags. Snippet of Code: editor.addButton('MobileToggleArea', { text: '<M>', icon: false, onclick: function (){ editor.selection. ...

Two vertical divs stacked on top of each other, each expanding to the entire height and width of the browser window

Is there a way to set the width and height of two divs on a webpage to match the dimensions of the browser window, requiring scrolling to view the second div? In addition, how can I ensure that the content within these divs is vertically centered? To ach ...

Navigating within an ionic framework

I am facing an issue with a simple form in my application. When I try to enter user details, the Android keyboard hides the email field and mobile number field, making it impossible for me to scroll the page upwards. Can anyone suggest a solution? <i ...

Regular expression in JavaScript that specifically matches numbers formatted in the style of JavaScript

My goal is to develop a javascript regular expression that specifically identifies valid Javascript-style numbers. The requirements entail accommodating an optional minus or plus sign before the number, recognizing the decimal dot, and supporting exponent ...

Unable to add a string to a http get request in Angular

When a specific ID is typed into the input field, it will be saved as searchText: <form class="input-group" ng-submit="getMainData()"> <input type="text" class="form-control" ng-model="searchText" placeholder=" Type KvK-nummer and Press Enter" ...

Encoding a two-dimensional array into JSON format

In my PHP script, I am querying a database and formatting the results as JSON: $query = mysql_query($sql); $rows = mysql_num_rows($query); $data['course_num']=$rows; $data['course_data'] = array(); while ($fetch = mysql_fetch_assoc($q ...

Is it advantageous to employ several wrapper-divs inside section elements when working with HTML5 and CSS?

Back in the day, I learned how to create a website by enclosing all content below the body tag within a div with the class "wrapper." This approach made sense as it allowed for easy vertical and horizontal alignment of the entire content. Just yesterday, ...

Incorporate custom JavaScript files that contain classes within a Vue component

i am encountering an issue with a js file that contains classes with functions. i have a vue component and i want to create an instance of that class within it. (when directly copying the file into my <script> tag, everything works smoothly) myfile. ...

Is there a way for me to align my div with my header on the same line?

HTML: <h2> RAN shares false news story about Hershey's Oil Commitment</h2> <div class="date"> <div class="number">27</div> <div class="month">Oct</div> </div> <p>The Rainforest Action Netwo ...

``A problem with the background image of the left panel in Framework 7

After setting a background image for the side panel and blurring it using CSS, I encountered an issue where the text and icons within the side panel also became blurred. Despite attempting to isolate the background image in a separate class, the problem ...

Struggling to populate a dropdown list with HTML, PHP, and MySQL

Here is the code snippet for creating a payment form: Everything seems to be working fine, but there is an issue with the supplier-ID dropdown. The dropdown is being created but it is not fetching data from the mysql table and no errors are being display ...

A discrepancy has arisen as the value within the array structure is being altered

I am facing an issue with the array structure of an object in my Angular front-end code. When I add values to the array based on selection, the object looks like this: todayRates: 10 yesterdayRates: 5 to: Array(1) 0: [3] length: 1 __proto__: Array(0) __pro ...

What are the steps for integrating an external API into a React project?

Apologies for any potential repetition, as this question may be commonly asked. I am currently working with React, Express, CORS, node, and postgres databases. My objective is to utilize the following API to retrieve real-time prices for metals: https://me ...

Despite having both React and Firebase enabled, the "sign-in provider" feature appears to be disabled

Within my Authentication settings, the Sign-in Method is configured to use Email and Password as enabled. I've set up a handler for form submission that looks like this: createUser(e){ e.preventDefault(); const email = this.createEmail.value ...

Receive the deleted entry upon clicking the thead | Error发

Is there a way to permanently delete a row in a datatable? If I delete all the rows, I would like the datatable to display the default message of "No data available". I have attempted some POST requests : But with no success. DataTables remove row butto ...