title |
---|
task |
Execute code in {% url "Node.js" https://nodejs.org %} via the task
plugin event.
{% note warning 'Anti-Pattern' %}
We do not recommend starting a web server using cy.task()
. Read about {% url 'best practices' best-practices#Web-Servers %} here.
{% endnote %}
cy.task(event)
cy.task(event, arg)
cy.task(event, arg, options)
{% fa fa-check-circle green %} Correct Usage
// in test
cy.task('log', 'This will be output to the terminal')
// in plugins file
on('task', {
log (message) {
console.log(message)
return null
}
})
{% fa fa-angle-right %} event (String)
An event name to be handled via the task
event in the {% url "pluginsFile
" configuration#Folders-Files %}.
{% fa fa-angle-right %} arg (Object)
An argument to send along with the event. This can be any value that can be serialized by {% url "JSON.stringify()" https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify %}. Unserializable types such as functions, regular expressions, or symbols will be omitted to null
.
If you need to pass multiple arguments, use an object
// in test
cy.task('hello', { greeting: 'Hello', name: 'World' })
// in plugins/index.js
on('task', {
// deconstruct the individual properties
hello ({ greeting, name }) {
console.log('%s, %s', greeting, name)
return null
}
})
{% fa fa-angle-right %} options (Object)
Pass in an options object to change the default behavior of cy.task()
.
Option | Default | Description |
---|---|---|
log |
true |
{% usage_options log %} |
timeout |
{% url taskTimeout configuration#Timeouts %} |
{% usage_options timeout cy.task %} |
cy.task()
yields the value returned or resolved by the task
event in the {% url "pluginsFile
" configuration#Folders-Files %}.
cy.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.
- Performing parallel tasks, like making multiple http requests outside of Cypress.
- Running an external process.
In the task
plugin event, the command will fail if undefined
is returned. This helps catch typos or cases where the task event is not handled.
If you do not need to return a value, explicitly return null
to signal that the given event has been handled.
Command {% url "cy.readFile()
" readfile %} assumes the file exists. If you need to read a file that might not exist, use cy.task
.
// in test
cy.task('readFileMaybe', 'my-file.txt').then((textOrNull) => { ... })
// in plugins/index.js
const fs = require('fs')
on('task', {
readFileMaybe (filename) {
if (fs.existsSync(filename)) {
return fs.readFileSync(filename, 'utf8')
}
return null
}
})
// in test
describe('e2e', () => {
beforeEach(() => {
cy.task('defaults:db')
cy.visit('/')
})
it('displays article values', () => {
cy.get('.article-list')
.should('have.length', 10)
})
})
// in plugins/index.js
// we require some code in our app that
// is responsible for seeding our database
const db = require('../../server/src/db')
module.exports = (on, config) => {
on('task', {
'defaults:db': () => {
return db.seed('defaults')
}
})
}
// in test
cy.task('pause', 1000)
// in plugins/index.js
on('task', {
pause (ms) {
return new Promise((resolve) => {
// tasks should not resolve with undefined
setTimeout(() => resolve(null), ms)
})
}
})
You can increase the time allowed to execute the task, although we do not recommend executing tasks that take a long time to exit.
Cypress will not continue running any other commands until cy.task()
has finished, so a long-running command will drastically slow down your test runs.
// will fail if seeding the database takes longer than 20 seconds to finish
cy.task('seedDatabase', null, { timeout: 20000 })
cy.task()
does not support tasks that do not end, such as:
- Starting a server.
- A task that watches for file changes.
- Any process that needs to be manually interrupted to stop.
A task must end within the taskTimeout
or Cypress will fail the current test.
Sometimes you might be using plugins that export their tasks for registration. Cypress automatically merges on('task')
objects for you. For example if you are using {% url 'cypress-skip-and-only-ui' https://github.com/bahmutov/cypress-skip-and-only-ui %} plugin and want to install your own task to read a file that might not exist:
// in plugins/index.js file
const skipAndOnlyTask = require('cypress-skip-and-only-ui/task')
const fs = require('fs')
const myTask = {
readFileMaybe (filename) {
if (fs.existsSync(filename)) {
return fs.readFileSync(filename, 'utf8')
}
return null
}
}
// register plugin's task
on('task', skipAndOnlyTask)
// and register my own task
on('task', myTask)
See {% issue 2284 '#2284' %} for implementation.
{% note warning Duplicate task keys %} If multiple task objects use the same key, the later registration will overwrite that particular key, just like merging multiple objects with duplicate keys will overwrite the first one. {% endnote %}
{% requirements task cy.task %}
{% assertions once cy.task %}
{% timeouts task cy.task %}
List the contents of cypress.json
cy.task('readJson', 'cypress.json')
The command above will display in the Command Log as:
{% imgTag /img/api/task/task-read-cypress-json.png "Command Log task" %}
When clicking on the task
command within the command log, the console outputs the following:
{% imgTag /img/api/task/console-shows-task-result.png "Console Log task" %}
{% history %}
{% url "3.0.0" changelog#3-0-0 %} | cy.task()
command added
{% endhistory %}
- {% url
cy.exec()
exec %} - {% url
cy.fixture()
fixture %} - {% url
cy.readFile()
readfile %} - {% url
cy.request()
request %} - {% url
cy.writeFile()
writefile %} - {% url "Blog: Incredibly Powerful cy.task()" https://glebbahmutov.com/blog/powerful-cy-task/ %}
- {% url "Blog: Rolling for a Test" https://glebbahmutov.com/blog/rolling-for-test/ %}