Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cy.click algorithm may incorrectly calculate elements with display: inline #210

Closed
brian-mann opened this issue Sep 6, 2016 · 6 comments · Fixed by #2981
Closed

cy.click algorithm may incorrectly calculate elements with display: inline #210

brian-mann opened this issue Sep 6, 2016 · 6 comments · Fixed by #2981
Assignees
Labels
pkg/driver This is due to an issue in the packages/driver directory topic: actionability topic: cy.click 🖱 type: bug

Comments

@brian-mann
Copy link
Member

brian-mann commented Sep 6, 2016

In this screenshot Cypress is failing with the following error:

CypressError: Timed out retrying: cy.click() failed because this element is being covered by another element:

<td class="highlight" data-reactid=".0.0.2.1.2.0.0.0.0.2.0.2.1:$0.$0">...</td>

Fix this problem, or use {force: true} to disable error checking.

https://on.cypress.io/element-cannot-be-interacted-with

virtualbox_cypress-app_desktop_1442616554908_97986_05_09_2016_14_54_51

The reason this is happening is because the <a> subject attempting to be clicked has CSS display: inline.

Display inline causes elements not to displace contents between the text.

When Cypress calculates the elements position to ensure it is not being covered by another element it uses document.elementFromPoint(x, y) to return the lowest descendent in the DOM.

If an inline element's exact center is calculated to be between the text, then this will return the element underneath the target (which is correct).

Unfortunately since Cypress was returned a non-descendent it believes the element is currently being covered and therefore displays the error.

To fix this, Cypress will need to take this situation into account by applying some fallback logic for this specific condition. I'm not sure what it should do yet, perhaps change the CSS to display: inline-block, calculate the center coordinates again, and if the element is found, revert to the original CSS and then click the element.

@brian-mann brian-mann added this to the 0.17.x milestone Sep 6, 2016
@brian-mann brian-mann self-assigned this Sep 6, 2016
@paulirish
Copy link

the plural document.elementsFromPoint does exist, in case the stack of elements underneath would be more useful to you.

@brian-mann
Copy link
Member Author

brian-mann commented Sep 6, 2016

That won't help because essentially that's the same thing as document.elementFromPoint except you receive an array of other ancestors beyond just the initial element.

Cypress's algorithm basically works like this: when attempting to interact with an element, first determine if its being "covered" by another element. After we determine the center of the element (or another position if you've passed that as an option), we then determine using document.elementFromPoint to see if it's "covered".

If a non-descendent element is returned then we assume it to be covered. document.elementsFromPoint would just return us array of all ancestors, none of which would be descendents and the same error would be thrown.

We talked as a team and likely the best solution for this is starting from the center and then expanding out in a square based on some interpolated step value until both the x and y boundaries are met. This would create resilience against an element being "partially" covered by finding the sliver of space that isn't covered (as likely a real user would do).

However that's way too much work for the time being, so we're just going to flip the elements CSS to inline-block (which only would mess up the CSS if the element has width + height) which it shouldn't anyway since it's inline.

Once it's inline-block we can re-run the check, determine the element isn't being covered by anything, and then swap back to inline and just fire the event at the center coordinates.

@brian-mann
Copy link
Member Author

Released in 3.1.4.

@robert-king
Copy link

robert-king commented Jan 19, 2019

I'm having a similar problem:

let stuff = [];
cy.get('mat-select').each((select) => {
  stuff.push(select);
}).then(()=>{
  stuff[1].click();
  cy.get('mat-option').first().click();
});

this works with stuff[1] or stuff[0]. However if I do:

stuff[0].click();
cy.get('mat-option').first().click();

stuff[1].click();
cy.get('mat-option').first().click();

it will fail because it opens both selects at the same time. So it will say cy.click() failed because this element is not visible. Adding timeouts doesnt work.

@kuceb
Copy link
Contributor

kuceb commented Jan 21, 2019

@robert-king I'm not sure I understand. Can you provide some screenshots or a reproducible?

@jennifer-shehane
Copy link
Member

Hey @robert-king, this original issue was involving inline elements issuing the error cy.click() failed because this element is being covered by another element, this doesn't look to be the error you are getting.

Could you open a new issue outlining an example that we can reproduce locally including the application code and test code.

You can also try asking questions relating to how to use Cypress be asked in our community chat.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pkg/driver This is due to an issue in the packages/driver directory topic: actionability topic: cy.click 🖱 type: bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants