Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Cypress when to use Custom Command vs Task?

Tags:

cypress

What is the difference between a Custom Command and a Task? I am trying to understand how they should each be used.

Custom Command documentation: https://docs.cypress.io/api/cypress-api/custom-commands.html

Task documentation: https://docs.cypress.io/api/commands/task.html

like image 794
Mark Jackson Avatar asked Nov 03 '19 13:11

Mark Jackson


People also ask

What is custom command in Cypress?

Cypress comes with its own API for creating custom commands and overwriting existing commands. The built in Cypress commands use the very same API that's defined below. A great place to define or overwrite commands is in your cypress/support/commands.

What are tasks in Cypress?

task() provides an escape hatch for running arbitrary Node code, so you can take actions necessary for your tests outside of the scope of Cypress. This is great for: Seeding your test database. Storing state in Node that you want persisted between spec files.

How do you write a task in Cypress?

To execute a task (which you previously defined in your cypress/plugins/index. js file), you need to first enqueue it as a regular command in your test via cy. task(taskName, data) . Cypress then (when the command takes its turn to execute) sends a message to the backend process where the task is executed.


2 Answers

A command (most methods on the global cy object) is a function that enqueues (pushes) an action to a queue of currently-executing commands. The queue executes serially and asynchronously (that's why return value of a command is an object having a .then method --- but despite that and the fact it behaves like promise, it's not a promise). Until a previous command is finished, the next command doesn't execute.

Commands are defined and executed directly in the browser.

A custom command is a regular command, but defined by you as opposed to the default commands that Cypress supplies out of the box. Custom commands are useful for automating a workflow you repeat in your tests over and over (e.g. by grouping several default cy commands together).

Commands are used to interact with your web app under test (AUT) --- most notably with the DOM (e.g. via cy.get(selector) to query the DOM), and to make assertions.

It's also important to realize that while commands are being executed serially, they are enqueued immediately (in the same event loop tick), and any expressions you pass to them are evaluated then and there. This isn't a Cypress-specific behavior, just plain JavaScript. That's why you can't do things like these:

// INCORRECT USAGE
let value;
cy.get('.myInput').invoke('val').then(val => value = val);
cy.get('.mySecondInput').type(value); // ✗ value is undefined here

Nor can you use async/await:

// INCORRECT USAGE
let value;
// ✗ doesn't work on Cypress commands
const value = await cy.get('.myInput').invoke('val');
cy.get('.mySecondInput').type(value); 

A task is a function defined and executed on the Cypress backend process (Node.js), not in the browser.

To execute a task (which you previously defined in your cypress/plugins/index.js file), you need to first enqueue it as a regular command in your test via cy.task(taskName, data). Cypress then (when the command takes its turn to execute) sends a message to the backend process where the task is executed.

Data your task returns is serialized (via JSON.stringify or something similar) and sent back to the browser where it's passed to a callback you potentially chained to your cy.task() command using .then(callback).

Tasks are mainly used to communicate with your own server backend, to e.g. seed the database; or for I/O such as reading/writing to a file (although cypress supplies commands for these such as cy.exec() or cy.writeFile()).

There are no default tasks --- every task you execute you first need to define yourself.

Another important point is that the messages that are sent between processes (the Cypress browser process, and the Cypress node process) are sent via an IPC channel, and must be serializable. That means that the data you pass to cy.task(taskName, data) are stringified, as well as is the response returned from the task itself. Thus, sending e.g. an object containing a method will not work (that is, the method won't be transferred at all).

like image 112
dwelle Avatar answered Oct 18 '22 12:10

dwelle


Great answers but in order to sum up, here are two main differences that help you choose whether you need a Cypress command or a task :

  • If you need to run a promise or interact with your backend, go with a task.
  • If you are interacting with the DOM and making assertions, go with a command.

Taken from this article

like image 23
Stephane L Avatar answered Oct 18 '22 11:10

Stephane L