Protractor: Implement elementNotToBeCovered for ExpectedConditions library

Created on 7 Jul 2015  ·  48Comments  ·  Source: angular/protractor

PRs plz! easy untriaged user experience feature request

Most helpful comment

+1

All 48 comments

Really need this. It would solve a big problem

This is exaclty our issue in globaleaks dealing with application loader and asyncronous operations.

+1

Really need this for pop ups and overlays that appear on top of the page, the ExpectedConditions.elementToBeClickable does not help in this case...

Yes this! I am constantly running into _"Element is not clickable at point (x,y). Other element would receive the click:"_ errors after scrolling and trying to click an element.. but only like ~14% of the time.. frustrating. Even waiting for elementVisible or elementToBeClickable doesn't always work.

+1

+1

+1

I'd like to see this functionality released ASAP. This issue is so annoying. Is there any workaround for it?

+1

+1

+1

+1

@sjelin you mention that this could be done in another thread, right?

We would address this using document.elementFromPoint and element.getBoundingClientRect pretty easily actually. elementFromPoint isn't totally standard at this point, though it appears to be supported by all browsers. The consistency issue is real though. Donno if we should leave this the way it is or "fix" it

+1000000000

+999

+2000000

+2000000

+999

+1

+1

+1

+1
EDIT: Sorry then. I've seen it as pretty common practice elsewhere to vote on issues with a +1 and this is a problem I've run a lot writing protractor tests so I'd be interested in seeing it implemented. I'll remember that for the future though.

Please stop +{number} this PR. This doesn't help...

Any update on this?
For my use case, I'm using the following to scroll the element into view, but I know this isn't a solution for all use cases such as modals and such.

var el = $('.myElement');
browser.executeScript('arguments[0].scrollIntoView()', el.getWebElement());

We've developed a workaround for now. We identify the element (id="spinner") that is "blocking" the element that we actually want to click and simply just wait for the blocking element to be invisible like so:
broswer.wait(EC.invisibilityOf($(‘#spinner’)), 5000)

EC.invisibilityOf isn't always enough. Sometimes Protractor reports an element as being covered by another element that shouldn't be invisible.

For instance, in one of my tests, a link is reported as being covered by its parent div, and invisibilityOf will wait forever. Seconding the desire for toNotBeCoveredBy

This issue is 2 years old. Is there any solution for this already, because I cannot find it and I am still encountering this problem? In my situation I cannot wait for element to be invisible, because the covering element is not going to be invisible at any point and it is not visually covering the element, but I still get the error for not clickable at point, because another element would receive the click.

+1 for the "toNotBeCoveredBy"

I have solved such issue in one case with the following:

"use strict";

function elementWithAttributeHasNotValue(htmlElement, attribute, value) {
    return htmlElement.getAttribute(attribute).then((elementAttribute) => {
        return !elementAttribute.includes(value);
    });
}

class Helper {
    waitForAngularInRoomAnimationToBeDone() {
        const inRoomElement = element(by.className("in-room"));

        browser.wait(elementWithAttributeHasNotValue(inRoomElement, "class", "ng-animate"), browser.params.DEFAULT_TIMEOUT_MS);
    }
}

module.exports = Helper;

The name of the method and of the constant are specific from my use case, but I think the rest could be used in a more generic way.

Then in my test I use it like this:

helper.waitForAngularInRoomAnimationToBeDone();

The thing is that in my situation, when I look at the screenshot of the error, which is capturing the state of the browser screen at the moment of the error, everything looks fine and the element I want to click is visible, but Protractor is still reporting that the element is not clickable, because another would receive the click and waiting for element to be visible or enabled doesn't work as the element is already visible on the screen and is enabled. I have this issue in Chrome and it is not appearing every time, only like 20% of the time. I tried the code above, but it does not work for me.

@MihailSeykov I have found that if there is an animation, the screenshot might be taken towards the end of the animation and so it looks like the element is not visible when in fact it is. You can use EC.and to wait for invisibilityOf multiple elements that might be covering that element

Sometimes the element will still be visible, but in another place after the animation

I appreciate all the hard work developers give to open source projects (I try and do when I can).

But,... I really can't see why this isn't the most important default/block/problem to be resolved. I can't write any tests whatsoever without a bunch of sleeps to wait for items to be hidden or visible in the dom. I have tried many combinations of wait for invisibility or wait for visibility... but can't write tests that aren't hacky hacky hack hacks.

I don't understand why everyone doesn't have this visibility problem.

This is more than 2 years old and still not fixed??! It is really IMPORTANT for testing w/t hacks, please fix ASAP!

Is there any progress on that :)
I though, I finally had a cure for my problem

Can we please have some feedback on this. Is someone looking at it or it will never be fixed? It is causing a lot of problems for a lot of people...

As far as I know it's not on the roadmap. But to be able to try to find a solution for this issue it would be nice if we have an example project and example Protractor Code to "proof" where the real issue is. Is that possible?

I'm also reading a lot in the comments about the problem with scrolling to the element and that in some cases it still fails. This could have to do with the fact that scrolling itself also takes time, but having said that, an example project would be very nice!

Who can provide us with that?

I'd like to add that for me, this too is the no.1 problem I have with Selenium. Very annoying that you have to build in waits, etc. to account for animations.

I have wrote small check utility method, keep in mind it will click on element immediately when it become clickable:

import { ElementFinder, promise } from 'protractor';
export let testHelpers = {
  isClickable(el: ElementFinder): promise.Promise<boolean> {
    return new promise.Promise(resolve => {
      let interval = setInterval(() => {
        el.click().then(() => {
          clearInterval(interval);
          setTimeout(() => {
            resolve(true);
          }, 500);
        }, () => { });
      }, 100);
    });
  }
}

In your test code:

import { testHelpers } from '../src/core/e2e/helpers';
describe('App', () => {
  it('should do something', () {
    let btn = $('.cls');
    browser.wait(testHelpers.isClickable(btn), 3000);
  });
});

My workaround has been, before clicking on the element, removing from the DOM the element that is covering the element that I want to click.
await browser.executeScript("arguments[0].remove();", coverElement);

We're almost at 3 years in ... is this requested feature not solvable from within _Protractor_?
Our tests have sleep all over to account for the animations that block element clickability 😞

@nmfernandes I think it might be a little less dramatic but still work to use arguments[0].style.visibility='hidden';. But in any case, your idea was helpful. Thanks for sharing.

Almost 4 years in, can we please have this? It's very inconvenient to create short sleeps between interactions just to work around this issue. In addition, the sleeps accumulate a lot of time which I (and I believe many people also) would like to avoid.

Does anyone have a code where I can simulate this problem? If possible pass me the github repository to only clone and execute.

I highly doubt that the Protractor team can do anything about this. To me it looks like an issue with either Selenium or Chromedriver.

  • 1

Unassigning myself because I no longer work for Google

I created a helper function usinc async / await for myself that takes 1 or 2 arguments as input, elem and
retryCount. What it does it tries to click on an element every .5 sec and if any error is thrown it tries to click again until the retryCount runs out or the button is clicked.

export const clickOnElementWithRetry = async (elem: ElementFinder, retryCount: number = 5) => {

    while (retryCount) {
        try {
            await elem.click();
            retryCount = 0;
        }
        catch (e) {
            if(retryCount === 0)
                throw "Couldn't click element";
            await browser.sleep(500);
            retryCount--;   
        }
    }

}

In the spec file or wherever you want to use it:

import { clickOnElementWithRetry } from './helpers/';
it('Clicks on some element', async () => {

    const someButton = element(by.id("someElementId"));
    clickOnElementWithRetry(someButton)
})
Was this page helpful?
0 / 5 - 0 ratings