The biggest gripe people have when they start using Cypress is the "lack" of await
keyword in front of every Cypress command. This complaint comes up again and again: why do I need to use cy.then(callback)
to work with the data from the application? Why can't I just do what other test runners do:
1 | // I WANT TO DO THIS!!!! |
I have written that how Cypress declarative approach might be simpler and shorter to write. I have recorded videos on how to avoid pyramid of Doom of callbacks. Nothing really lowers people's frustration. They want await cy...
really badly.
Ok then. Let's do this. Cypress lets you use your own spec file preprocessor to bundle or transpile the test code. I wrote cypress-await that uses Babel to automatically transpile testing specs that use await cy...
into cy....then(callback)
1 | // your code |
The code still retries using the built-in assertions like cy.get
and the entire query, so you are not losing anything using this plugin. There is even a "sync" mode that allows you to skip writing await
in front of every Cypress command and simply get the data variable = cy...
Nice!
Install and use
Just like any Cypress plugin following the README instructions.
1 | const { defineConfig } = require('cypress') |
You can even transpile some spec files using a minimatch or file path suffix. For example, the majority of our spec files might be "plain" Cypress standard, while only some using await
keyword.
1 | cypress/ |
We can set up the specPattern
to transpile only files that end with .await.cy.js
string
1 | setupNodeEvents(on, config) { |
You can debug the transpiled source to see what happens under the hood:
1 | setupNodeEvents(on, config) { |
The terminal will show the transpiled spec source code:
Sync mode
Hmm, one of the attractive parts of Cypress is its declarative syntax. Putting await
in front of every Cypress command just to remove it seems useless. The only time we really want the value is when we assign the result of executing a Cypress command to a variable. Thus my plugin cypress-await has another "sync" preprocessor. You use it the same way: point Cypress file preprocessor at the "sync" preprocessor.
1 | const { defineConfig } = require('cypress') |
Now you can write Cypress specs the way you probably wanted to write it all this time:
1 | it('checks the server using cy.request (sync)', () => { |
The plugin transforms every variable = cy....
assignment into cy....then(variable => ...)
and moves all statements after the assignment into the callback.
1 | // "sync" spec file |
Examples
I have a few examples of using the plugin in my bahmutov/cypress-todomvc-await-example repo. It is almost too boring:
Spying on the network request to know how many items to find on the page
1 | // network.sync.cy.js |
Comparing items on the page
1 | // spec.sync.cy.js |
📺 Watch video Await Cypress Command Results