44

I am automating Google Calculator. And from time to time Cypress is not able to execute click on button. The tests click on buttons (0 to 9 ) and do some simple math operations. And in 30% chance it can not click on element and the test will fail.

I also recorded a video when issue appears.

Video here

My Project is located here: https://github.com/afiliptsov/test-project

To run the test run : "npm run test:e2e:functional"

I tried to use different locator. Initially i was using just ID ex(#cwbt15 ) but after i made more specific locator ( #cwbt15 > .cwbtpl > .cwbts) and still having same issue.

Does anyone knows why it happens and how to avoid such behavior?

The project structure is :

  • cypress/PageObject.js - place where all elements declared.
  • cypress/support/commands.js - place where function click created and verification of value getting updated.
  • cypress/integration/functional/delete.spec.js - test which was on the video
Anton
  • 1,344
  • 3
  • 15
  • 32
  • I made more research and it seems similar issue: https://github.com/cypress-io/cypress/issues/695 – Anton Jul 10 '18 at 20:10

12 Answers12

42

For those who are using cypress version "6.x.x" and above

You could use { force: true } like:

cy.get("YOUR_SELECTOR").click({ force: true });

but this might not solve it ! The problem might be more complex, that's why check below

My solution:

cy.get("YOUR_SELECTOR").trigger("click");

Explanation:

In my case, I needed to watch a bit deeper what's going on. I started by pin the click action like this:

enter image description here

Then watch the console, and you should see something like: enter image description here

Now click on line Mouse Events, it should display a table: enter image description here

So basically, when Cypress executes the click function, it triggers all those events but somehow my component behave the way that it is detached the moment where click event is triggered.

So I just simplified the click by doing:

cy.get("YOUR_SELECTOR").trigger("click");

And it worked

Hope this will fix your issue or at least help you debug and understand what's wrong.

MagnusHH
  • 3
  • 1
Emidomenge
  • 1,172
  • 17
  • 26
  • @marcacyr I'm glad this was helpful :) – Emidomenge Jun 30 '21 at 10:02
  • 3
    actually (nov 2021) that's the only way to make 15 clicks on a single button work (e.g. clicking next in a calendar showing months). All the other way will miss one or more clicks! – Don Diego Nov 24 '21 at 16:58
  • Thanks for your contribution here. I have been struggling to fix similar issue in my case – Raju Penumatsa Mar 24 '22 at 06:39
  • 1
    This doesn't work for me. Somewhere in between I found an answer that works for me. It triggers the mouse hover, before the click. This seems to do the trick: https://stackoverflow.com/a/58302240/8408576 – dewey Apr 08 '22 at 14:50
  • For localhost everything click is working , when we tried on test server this happen and twice working for cypress to make sure lol. Also all button in my case sometimes not work with trigger click , must click() instead of .trigger('click') sadly – Yogi Arif Widodo Aug 07 '23 at 00:43
25

For me this code worked:

Inside your click methods add : { force: true } It will make force click.

Also add: cy.wait(150) to beforeEach or before click where your test fails.

It is just workaround not a solution.

Link to Cypress Issue

Also i saw this alternative:

cy.get('#query-btn').invoke('width').should('be.gt', 0)

cy.get('#query-btn').invoke('width').should('be. greaterThan', 0)

But it didnt work out for me. Maybe will be usefull for someone!

Anton
  • 1,344
  • 3
  • 15
  • 32
  • 9
    _Also add: cy.wait(150)_ : That is never a good idea. Cypress is based on async ideology, where wait should be implicit by querying for situations like elements becoming visible, etc. – Kaushik NP Jul 13 '18 at 05:31
  • 3
    I agree but in my specific case nothing else worked. And there is a post where multiple people have same type of issue. And for now i didnt found better solution. There is a url attached in answer. – Anton Jul 14 '18 at 03:26
  • 1
    Downvoted it because: 1. cy.wait() is never a solution 2. force:true does not guarantee the click to succeed – Praveen Pandey May 07 '20 at 07:48
  • 13
    @PraveenPandey When you downvoting, please propose a better solution. Cypress is pretty new tool, and sometimes bad solution is better than no solution. – Anton Aug 26 '20 at 15:31
  • 1
    There may be a race between the control showing up in the DOM, click event dispatch and another render bouncing it again. Browsers aren't perfect at this. I experience a 100% pass on local headless run, then 95% failure in CI pipeline where the machine is slower. On a button click. It would be best to have an ideal and sturdy await point but sometimes a wait will get you unblocked. +1 – Rob_vH Oct 08 '20 at 13:20
  • For me neither `force` or the accepted answer wored. Somewhere in between I found an answer that works. It triggers the mouse hover, before the click. This seems to do the trick: https://stackoverflow.com/a/58302240/8408576 – dewey Apr 08 '22 at 14:49
16

https://github.com/cypress-io/cypress/issues/2928 helped me.

cy.get('[data-qa="select_workers-list"]'.contains('+ New Worker').trigger('mouseover').click();
noam621
  • 2,766
  • 1
  • 16
  • 26
Misha
  • 179
  • 1
  • 3
  • Not sure why this was downvoted, but this is the only answer that got my script working consistently – Emjey Mar 23 '20 at 05:23
  • this worked for me too, for some reason it needs `.trigger('mouseover').` before `.click()` – jmbmage Sep 04 '20 at 16:51
  • Mouseover causes an implicit wait. :/ allows the rendering to settle before the click dispatch. Might not actually different that the wait() solution, just different implementation :) – Rob_vH Oct 08 '20 at 13:22
  • In my case, no matter how much time you cy.wait(). It didn't work. This was the only working solution for me. – EmirDev Nov 29 '21 at 18:51
  • Thanks, this helped me a lot. Neither click() or clickAndWait() or trigger('click') worked before. Only mouseover and click worked. – Stefanie Uhl Feb 21 '22 at 13:56
  • Thank you, you save my day. I have an e2e test that clicks on elements which execute a redirection, then I execute a go back to the previous page and if I tried to click on the same element the redirection didn't work. Now, with the `trigger('mouseover').click()` it works. Thanks – German Quinteros Jun 08 '22 at 15:18
9

Whoever finds this problem, the official way of handling it is described here: https://www.cypress.io/blog/2019/01/22/when-can-the-test-click/

TLDR: What @jpvantuyl said, cypress clicks the button before the onclick event is there. The lib cypress-pipe will add a .pipe method that if followed by .should will retry a function until the condition is true or it times out.

Example:

cy
  .get(numbers.result.idLocator)
  .pipe($el => $el.click()) // try this
  .pipe(
    // next line will make assertions on the element returned by this pipe
    () => cy.get(calculatorScreen.resultOutput.idLocator)
  )
  .should("contain", "0"); // until this happens or times out
Ian
  • 2,944
  • 1
  • 19
  • 19
6

This could be because the application is attaching behaviors to the button via JavaScript. When that script takes a long time to execute it allows Cypress to click the button before the OnClick event is there.

See: https://www.cypress.io/blog/2018/02/05/when-can-the-test-start/

Cypress recommends tracking when the underlying JS is in place with something like:

function waitForAppStart() {
  // keeps rechecking "appHasStarted" variable
  return new Cypress.Promise((resolve, reject) => {
    const isReady = () => {
      if (appHasStarted) {
        return resolve()
      }
      setTimeout(isReady, 0)
    }
    isReady()
  })
}
it('greets', () => {
  cy.visit('app.html', {
    onBeforeLoad: spyOnAddEventListener
  }).then(waitForAppStart)
  // all other assertion will run only when
  // the application has started
  cy.get('#name').type('Cypress{enter}')
  cy.contains('#answer', 'Cypress')
})
jpvantuyl
  • 584
  • 10
  • 22
6

Something I just learned from a colleague after none of the above worked for me and after hours of searching. Just blew my mind. Just add another .click()...

before:

cy.contains('some string').click(); 

In the left Cypress menu click on the action and you'll see the indicator that it clicks the correct part, but nothing happens. Do it manual in the browser and it works.

Fix:

cy.contains('some string').click().click();

and all of the sudden the string is clicked and test is moving on to the next page

LL1986
  • 77
  • 1
  • 1
2

In my case I had to make sure the button is visible(or not disabled), then mouseover, then click:

 cy.contains(/activate/i)
  .should('be.visible')
  .trigger('mouseover')
  .click({ force: true });

PS. /***/i means ignore letter case.

Vlad R
  • 1,851
  • 15
  • 13
2

I found that my button's event listeners were loaded but the button was not receiving the focus it needed. It was definitely clickable. I tried using the cypress-pipe package but to no avail. So, instead of invoking .click() on it 2 or more times, I ensured it was first set in focus prior to being clicked. This fixed it for me.

cy.get('button').focus().click()
1

I don't know why, but for me this worked:

cy.get('[role="button"][aria-haspopup="listbox"]').trigger('mouseover').wait(1000).click().click({force:true});
Elikill58
  • 4,050
  • 24
  • 23
  • 45
0

FWIW: I was having problems submitting/navigating after a Google Places address selection. I believe my component wasn't re-rendering post-address selection.

To solve my issue, after address selection, I selected a random text element, clicked on it (no-op) and then clicked on my continue button and it worked fine.

dougwig
  • 526
  • 6
  • 8
0

I switched my app from being rendered as SPA to using SSR (basically removing ssr: false from my svelte.config) which started to fail my Cypress tests. Reverting fixed it for my test setup.

TeemuK
  • 2,095
  • 1
  • 18
  • 17
0

I've worked through many of the answers posted above and it was https://stackoverflow.com/a/70932275/19377357 that gave me the first solution that worked. I stripped each section away to see what was necessary and what wasn't.

Apparently, all the page needed (that I was working on) was a second to load:

cy.get('YOUR-SELECTOR').wait(1000).click();

  • Do you realize `cy.get('YOUR-SELECTOR')` already waits for 4 seconds? – Rab.Scarabelli Jul 19 '23 at 22:00
  • But a hard wait is different to a timeout - although `cy.get()` has *timeout* of 4 seconds, it may return an element in much less time that that. But if the event handler has not yet loaded, the click will not succeed - see [when-can-the-test-click](https://www.cypress.io/blog/2019/01/22/when-can-the-test-click). – Monkey-with-a-grenade Jul 20 '23 at 00:01