Imagine you have a button on the page. This button sometimes is enabled and sometimes is disabled. The test does not control the button (that would be too simple). The test must click the button only if it is enabled. How would you write this Cypress test?
Conditional testing is an anti-pattern, but Cypress can do it. Here is how to solve this problem in several ways.
Plain Cypress syntax
📺 Watch the first solution explained in the video Check If A Button Is Enabled Before Clicking.
Let's use plain Cypress command. We first get the button, then check its attribute inside cy.then(callback)
. We can schedule more commands in the callback
function.
1 | cy.contains('#btn', 'Click Me') |
Remember: any time you get something from the app, you must pass it forward to the next command, assertion, or cy.then(callback)
.
If the button is enabled, the test clicks and checks the updated text.
If the button happened to be disabled, the test simply logged a message and finished.
We can rewrite the test to use jQuery is
method to check if the button is enabled using the jQuery pseudo-selector :enabled
.
1 | cy.contains('#btn', 'Click Me') |
I like this syntax because it makes it clear what we are getting at; we are checking if the button is enabled. This is better than "hiding" the effects in the cy.then(callback)
via $btn.attr('disabled')
or even $btn.is(':enabled')
which are invisible to Cypress Command Log. If we are using cy.invoke command, we can click on it to see what it produced.
You can find the above examples under recipes on my Cypress examples site.
cypress-if solution
📺 Watch the next two solutions shown in the video Click Button If Enabled Using cypress-if And cypress-await Plugins.
I have introduced my plugin cypress-if in the blog post Conditional Commands For Cypress. It lets you do conditional "if / else" chains of commands based on the current subject. Here is how the above solution looks when using cypress-if
. The commands cy.if
and cy.else
are from the cypress-if
plugin
1 | // https://github.com/bahmutov/cypress-if |
When the current subject passes the jQuery assertion if('enabled')
, the logic takes the "IF" command chain path, executing all commands between cy.if
and cy.else
. Let's see how it behaves when the button is disabled.
So, so easy. Tip: want to run more commands? Just stick cy.then(callback)
inside the if / else
chain:
1 | cy.contains('button', 'Click Me') |
I really enjoy using cypress-if
, to be honest.
cypress-await solution
If you don't like working with the Cypress subjects and chains, I have cypress-await plugin for you. It sets up a spec file preprocessor that rewrites specs:
1 | // in your spec |
It looks synchronous, but under the hood all Cypress retries are still executing for each chain before assigning the value. Our conditional test can be rewritten like this:
1 | it( |
You can find more lessons on how to use cypress-if
and cypress-await
in my Cypress Plugins course.