Cypress does not have a REPL which is unfortunate: sometimes you just want to run a few Cypress commands after the test has finished to see how to extend the test. Yet the only way you can run a command is by adding it to the spec file, saving it, causing Cypress to re-run the entire test. Unless you use tricks like using cypress-data-session plugin or splitting a long test, waiting for the entire test to finish just to check one command is frustrating.
This is where an internal Cypress command cy.now
comes in very handy. This is the only place where cy.now
is explained in the Cypress docs:
Pretty sweet, isn't it? But if that warning is not strong enough, let me add my own:
🚨 The
cy.now
andcy.state
commands described in this blog post are internal to Cypress Test Runner. They can change without any warning in the future versions, they may not work in all cases, and they can cause your blood pressure to rise to dangerous levels. Please consult a Cypress doctor before using them.
If you are ok with that, let's continue.
cy.now
So let's say we have opened the DevTools console, the test has finished and we want to visit the site again. In the console run cy.now('visit', '/')
. The site loads.
Let's say we want to check if a selector works. Try using cy.now('get', '.todo')
to see what happens.
Hmm, which elements did it find? The cy.now
returns a promise, so we should print the results to the console using cy.now('get', '.todo').then(console.log)
.
There is another way to see the results of the cy.now
commands. They are logged to the Cypress Command Log at the end of the last test (excluding pending or skipped tests). The video below shows me expanding the last test and observing the commands I executed using cy.now
command.
Note that there are no DOM snapshots for cy.now
commands, but you can log the command results by clicking on the command itself.
The cy.now
command returns a Promise object, not a Cypress chainable object, thus you cannot chain multiple commands together, which makes it hard to build a REPL.
cy.now use case
Building an entire testing suite by relying on cy.now
is a bad idea. But using it sparingly might be necessary. For example, in cypress-data-session I have a few static Cypress.*
methods to help with debugging the cached data. Like calling a task by name to print all currently existing data sessions in the plugin process - I don't want the user to type cy.now('tast', ...)
to list the sessions, instead I exposed static methods:
1 | // in the plugin file we have a task that prints the sessions and returns them |
1 | /** |
Super, the user can run this command at any time from the console to see the sessions. The browser even shows autocomplete for the Cypress
methods, which is convenient.
But what if we want to use the same static method during the test?
cy.state
Take the static method Cypress.printSharedDataSessions
. Imagine we want to confirm the plugin process has a specific key present. We want to call the task and get the value and chain assertions on it.
1 | it('stores the value', () => { |
Hmm, we need to run cy.task
if the tests are running or use cy.now
if the user called Cypress.printSharedDataSessions
from the browser console. How do we know if the tests are running or not? This is where the internal cy.state
command comes in handy. Again, this is a command NOT meant to be used. The Cypress Documentation site has a few places where it mentions it, like this one:
The best way to understand what cy.state
has is to look at it in the console. It is a grab bag of everything Cypress Test Runner uses internally.
There are a lot of things. Often Cypress public commands like cy.get
use cy.state('document')
and cy.state('window')
to get references to the application's document and window objects without using cy.document()
and cy.window()
commands. In our case cy.state('ctx')._runnable
looks like it might do the trick. If there is a test running, it returns an object. After the tests have finished, it returns undefined. Thus we can we use it to determine if we can call cy.task
or must use cy.now
to call get the info from the plugin process.
1 | /** |
One last detail. Normally cy.*
methods can only be called inside a test or a hook. The commands cy.now
and cy.state
are exceptions.
Note: this blog post was linked from Cypress Advent 2021