cypress: asynchronous code in beforeEach via 'done' function breaks tests
Current behavior:
Using asynchronous code in the beforeEach
handler breaks tests. Tests that use .click
, .trigger
, etc. will have to use {force: true}
or they will fail – the command won’t occur.
After (briefly) diving into the cypress code, it looks like the click
command’s promise is being set to the canceled
state before it has a chance to pass actionability verification; almost as if it is being conflated with the promise from the beforeEach
.
Desired behavior:
I should be able to write asynchronous code in the beforeEach
callback and use done()
to indicate when I’m finished.
Steps to reproduce: (app code and test code)
I’ve set up a repo here that reproduces the problem: https://github.com/fr0/cypress-angular-test
However, the important bit is pretty short:
function timer(duration) {
return new Promise(accept => {
setInterval(() => {
accept();
}, duration);
});
}
describe('tests', function () {
beforeEach(done => {
timer(1000).then(() => {
cy.visit('/').then(() => {
done();
});
});
});
it('can click the button', () => {
cy.get('button.clickme').click(); // adding {force: true} here makes this work! without it the click never happens.
cy.get('.text').should('have.text', 'clicked!');
});
});
Versions
3.1.4
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 8
- Comments: 20 (11 by maintainers)
Commits related to this issue
- fix: Wrap promise to avoid a Cypress warning (#60) This uses the recommendation in https://github.com/cypress-io/cypress/issues/3172. — committed to DamienCassou/cypress-watch-and-reload by DamienCassou 3 years ago
- fix: Wrap promise to avoid a Cypress warning (#60) (#83) This uses the recommendation in https://github.com/cypress-io/cypress/issues/3172. — committed to bahmutov/cypress-watch-and-reload by DamienCassou 3 years ago
You defenitely need to improve the documentation about cy.wrap()! Currently the doc just simply sais
Whereas cy.wrap() is irreplaceable for so many async use cases. For example please document that cy.wrap() waits until the promise given as argument returns:
https://github.com/cypress-io/cypress-example-recipes/blob/master/examples/logging-in__using-app-code/cypress/integration/spec.js
cy.then()
exists only for legacy purposes, and it’ll get removed at some point as a breaking change. It should becy.wrap().then()
to match other valid promise signatures.The correct behavior here is
cy.wrap(otherPromise)
because cypress needs to be in control of thecy
chain.We actually detect that you’ve incorrectly returned a non-cy Promise and then invoked
cy.*
commands within it and will print a warning message in the console.The problem (and edge case here) as to why that message isn’t printing is because you have not returned the outer promise and have instead opted to use a
(done)
callback.Because you’re not returning the promise to us, Cypress cannot tell that
cy.*
commands are being wrapped from an outer promise, and therefore can’t correctly run its command chain.We likely need to additionally account for
(done)
and we could probably “assume” this is happening if you don’t return anything from the test, andcy.*
commands have not been synchronously queued, but they end up getting enqueued later.Mocha’s
(done)
really exists at this point because Promises were not as universal as they are now. There is really no reason to ever use them anymore because utilizing(done)
is the same exact thing asreturn new Promise((resolve, reject) => {})
so ultimately, don’t put
cy.visit
inside a promise, just do promises inside.then
and placecy.visit
. Cypress will chain the commands, sovisit
will happen when previous.then
finisheshow do you bootstrap the backend? Maybe use
cy.request
orcy.task
?@bahmutov , I’m having a somewhat similar problem in my use case. Basically I need to retrieve some data from the server to generate the tests from. In Mocha this can be achieved by using --delay flag. What would be the Cypress way of doing this? Can’t seem to find working solution.
https://github.com/cypress-io/cypress/issues/3114
Thanks!