Await-ing Cypress Chains
See original GitHub issueCurrent behavior:
await
-ing cypress chains yields undefined
Desired behavior:
await
-ing cypress chains yields the value of the chain (since the chain is a promise-like, it should work with await out of the box)
Additional Info (images, stack traces, etc)
I understand the recommended way to use cypress is closures, however, when dealing with multiple variables, we run into callback hell’s lil’ brother closure hell.
The ability to use await
on Cypress chains could be beneficial in many ways:
- avoiding nesting closures many levels deep, thus preventing unreadable code
- making it easy for programmers familiar with traditional async patterns to start using Cypress
Example code using closures
describe('Filter textbox', () => {
beforeEach(() => {
cy.get(test("suplovaniTable")).as("suplovaniTable");
cy.get(test("filterTextbox")).as("filterTextbox");
});
it('changes data on filter text change', () => {
cy.get("@suplovaniTable").then((el) => {
return el[0].innerHTML;
}).then((innerHTML) => {
return sha256(innerHTML);
}).then((hash) => {
cy.get("[data-test=suplovaniTable] > tbody > :nth-child(1) > :nth-child(2)")
.then((tds) => {
const text = tds[0].innerText;
cy.get("@filterTextbox").type(text);
cy.get("@suplovaniTable")
.then(el => el[0].innerHTML)
.then((innerHTML) => {
expect(hash).to.not.equal(sha256(innerHTML));
});
});
});
});
});
Example code using await
describe('Filter textbox', () => {
beforeEach(() => {
cy.get(test("suplovaniTable")).as("suplovaniTable");
cy.get(test("filterTextbox")).as("filterTextbox");
});
it('changes data on filter text change', async () => {
const table = await cy.get("@suplovaniTable");
const hash = sha256(table[0].innerHTML);
const filterCell = await cy.get("[data-test=suplovaniTable] > tbody > :nth-child(1) > :nth-child(2)");
await cy.get("@filterTextbox").type(filterCell[0].innerText);
const newTable = await cy.get("@suplovaniTable");
const newHash = sha256(newTable[0].innerHTML);
expect(hash).to.not.equal(newHash);
});
});
- Operating System: Windows 10 x64
- Cypress Version: Beta 2.1.0
- Browser Version: Chrome 64
Issue Analytics
- State:
- Created 6 years ago
- Reactions:407
- Comments:79 (31 by maintainers)
Top Results From Across the Web
Cypress.io — Using async and await | by Nicholas Boll | Medium
Async/await makes it much easier to unwrap values, but Commands are not Promises. Using await on a Cypress chain will not work as...
Read more >then | Cypress Documentation
If the return value is a chain of Cypress commands (eg return cy.get('button') ) ... .then() can time out waiting for a promise...
Read more >Introduction to Cypress - Cypress Documentation
To match the behavior of web applications, Cypress is asynchronous and relies on timeouts to know when to stop waiting on an app...
Read more >Understanding the Asynchronous nature of Cypress
This means you cannot use things like async/await within your Cypress tests. ... that to resolve before continuing forward through the chain of...
Read more >Cypress.Promise
Waiting for Promises. it('waits for promises to resolve', () => { let waited = false function waitOneSecond() { // return a promise that...
Read more >Top Related Medium Post
Top Related StackOverflow Question
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Cypress commands are not 1:1 Promises.
https://gitter.im/cypress-io/cypress?at=5a9ec8bf458cbde55701c7a8
They have promise like features in the sense that they have a
.then(fn)
and they can assume other thenables and do the right thing, but they themselves are not true Promises.This has serious implications where the
async/await
implementation would simply not work correctly in Cypress.What is possible - is to use
async/await
to replace the.then(fn)
but even that has problems.You could not use
try / catch
because that is the same thing as.catch()
for Promises, which Cypress does not and will never have.Because Cypress enqueues commands on a master singleton, it already manages the async coordination for you. It’s impossible to ever lose a chain of commands.
What this means is - you would sometimes add the
await
keyword when you need to work with the yielded value of a command - but then mostly not do this.This also means you wouldn’t use the
async
keyword on functions that return Cypress commands.This IMO would end up being confusing. You would use
async/await
inconsistently from how you’d use it outside of Cypress. It would require a lot of explanation in the docs.FWIW you can already avoid callback hell in Cypress by writing much more terse JS. There is almost never a situation where you ever would need to create nested callbacks, or ever need to make heavy use of
const
.+1 Protractor / Selenium are deprecating their old specflow (that works just like Cypress) and replacing it with a native promise based one. In my previous assignment, we migrated our tests to use async / await and really makes things way clearer. Using Cypress now and it’s clearly an improvement over protractor / selenium on many topics, but this is a big disappointment.