{
  "doc": {
    "id": "api/commands/task",
    "title": "cy.task()",
    "description": "Execute code in Node.js via the task plugin event in Cypress.",
    "section": "api",
    "source_path": "/llm/markdown/api/commands/task.md",
    "version": "29f95bf8bb06f320986f3749f5bf09a35a409eab",
    "updated_at": "2026-09-04T10:49:54.630Z",
    "headings": [
      {
        "id": "api/commands/task#task",
        "text": "task",
        "level": 1
      },
      {
        "id": "api/commands/task#syntax",
        "text": "Syntax",
        "level": 2
      },
      {
        "id": "api/commands/task#usage",
        "text": "Usage",
        "level": 3
      },
      {
        "id": "api/commands/task#arguments",
        "text": "Arguments",
        "level": 3
      },
      {
        "id": "api/commands/task#yields",
        "text": "Yields",
        "level": 3
      },
      {
        "id": "api/commands/task#examples",
        "text": "Examples",
        "level": 2
      },
      {
        "id": "api/commands/task#read-a-file-that-might-not-exist",
        "text": "Read a file that might not exist",
        "level": 3
      },
      {
        "id": "api/commands/task#return-number-of-files-in-the-folder",
        "text": "Return number of files in the folder",
        "level": 3
      },
      {
        "id": "api/commands/task#seed-a-database",
        "text": "Seed a database",
        "level": 3
      },
      {
        "id": "api/commands/task#clean-up-and-verify-downloaded-files",
        "text": "Clean up and verify downloaded files",
        "level": 3
      },
      {
        "id": "api/commands/task#run-an-external-command-or-cli",
        "text": "Run an external command or CLI",
        "level": 3
      },
      {
        "id": "api/commands/task#run-node-code-before-each-test",
        "text": "Run Node code before each test",
        "level": 3
      },
      {
        "id": "api/commands/task#return-a-promise-from-an-asynchronous-task",
        "text": "Return a Promise from an asynchronous task",
        "level": 3
      },
      {
        "id": "api/commands/task#save-a-variable-across-non-same-origin-url-visits",
        "text": "Save a variable across non same-origin URL visits",
        "level": 3
      },
      {
        "id": "api/commands/task#command-options",
        "text": "Command options",
        "level": 3
      },
      {
        "id": "api/commands/task#change-the-timeout",
        "text": "Change the timeout",
        "level": 4
      },
      {
        "id": "api/commands/task#notes",
        "text": "Notes",
        "level": 2
      },
      {
        "id": "api/commands/task#tasks-must-end",
        "text": "Tasks must end",
        "level": 3
      },
      {
        "id": "api/commands/task#tasks-that-do-not-end-are-not-supported",
        "text": "Tasks that do not end are not supported",
        "level": 4
      },
      {
        "id": "api/commands/task#tasks-are-merged-automatically",
        "text": "Tasks are merged automatically",
        "level": 3
      },
      {
        "id": "api/commands/task#reset-timeout-via-cypress-config",
        "text": "Reset timeout via Cypress.config()",
        "level": 3
      },
      {
        "id": "api/commands/task#set-timeout-in-the-test-configuration",
        "text": "Set timeout in the test configuration",
        "level": 3
      },
      {
        "id": "api/commands/task#allows-a-single-argument-only",
        "text": "Allows a single argument only",
        "level": 3
      },
      {
        "id": "api/commands/task#argument-should-be-serializable",
        "text": "Argument should be serializable",
        "level": 3
      },
      {
        "id": "api/commands/task#accessing-secrets-securely",
        "text": "Accessing secrets securely",
        "level": 3
      },
      {
        "id": "api/commands/task#rules",
        "text": "Rules",
        "level": 2
      },
      {
        "id": "api/commands/task#requirements",
        "text": "Requirements",
        "level": 3
      },
      {
        "id": "api/commands/task#assertions",
        "text": "Assertions",
        "level": 3
      },
      {
        "id": "api/commands/task#timeouts",
        "text": "Timeouts",
        "level": 3
      },
      {
        "id": "api/commands/task#command-log",
        "text": "Command Log",
        "level": 2
      },
      {
        "id": "api/commands/task#history",
        "text": "History",
        "level": 2
      },
      {
        "id": "api/commands/task#see-also",
        "text": "See also",
        "level": 2
      }
    ]
  },
  "chunks": [
    {
      "id": "api/commands/task#syntax",
      "doc_id": "api/commands/task",
      "heading": "Syntax",
      "heading_level": 2,
      "content_markdown": "## Syntax\n\n```\ncy.task(event)\ncy.task(event, arg)\ncy.task(event, arg, options)\n```\n\n### Usage\n\n**Correct Usage**\n\n```\n// in test\ncy.task('log', 'This will be output to the terminal')\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        log(message) {\n          console.log(message)\n\n          return null\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        log(message) {\n          console.log(message)\n\n          return null\n        },\n      })\n    },\n  },\n})\n```\n\nThe `task` plugin event handler can return a value or a promise. The command will fail if `undefined` is returned or if the promise is resolved with `undefined`. This helps catch typos or cases where the task event is not handled.\n\nIf you do not need to return a value, explicitly return `null` to signal that the given event has been handled.\n\n### Arguments\n\n**event _(String)_**\n\nAn event name to be handled via the `task` event in the [setupNodeEvents](/llm/markdown/app/plugins/plugins-guide.md#Using-a-plugin) function.\n\n**arg _(Object)_**\n\nAn argument to send along with the event. This can be any value that can be serialized by [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`.\n\nIf you need to pass multiple arguments, use an object\n\n```\n// in test\ncy.task('hello', { greeting: 'Hello', name: 'World' })\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        // deconstruct the individual properties\n        hello({ greeting, name }) {\n          console.log('%s, %s', greeting, name)\n\n          return null\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        // deconstruct the individual properties\n        hello({ greeting, name }) {\n          console.log('%s, %s', greeting, name)\n\n          return null\n        },\n      })\n    },\n  },\n})\n```\n\n**options _(Object)_**\n\nPass in an options object to change the default behavior of `cy.task()`.\n\n| Option | Default | Description |\n| --- | --- | --- |\n| `log` | `true` | Displays the command in the [Command log](/llm/markdown/app/core-concepts/open-mode.md#Command-Log) |\n| `timeout` | [`taskTimeout`](/llm/markdown/app/references/configuration.md#Timeouts) | Time to wait for `cy.task()` to resolve before [timing out](#Timeouts) |\n\n### Yields\n\n`cy.task()` yields the value returned or resolved by the `task` event in [setupNodeEvents](/llm/markdown/app/plugins/plugins-guide.md#Using-a-plugin).\n",
      "section": "api",
      "anchors": [
        "syntax"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 573
    },
    {
      "id": "api/commands/task#usage",
      "doc_id": "api/commands/task",
      "heading": "Usage",
      "heading_level": 3,
      "content_markdown": "### Usage\n\n**Correct Usage**\n\n```\n// in test\ncy.task('log', 'This will be output to the terminal')\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        log(message) {\n          console.log(message)\n\n          return null\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        log(message) {\n          console.log(message)\n\n          return null\n        },\n      })\n    },\n  },\n})\n```\n\nThe `task` plugin event handler can return a value or a promise. The command will fail if `undefined` is returned or if the promise is resolved with `undefined`. This helps catch typos or cases where the task event is not handled.\n\nIf you do not need to return a value, explicitly return `null` to signal that the given event has been handled.\n",
      "section": "api",
      "anchors": [
        "usage"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 220
    },
    {
      "id": "api/commands/task#arguments",
      "doc_id": "api/commands/task",
      "heading": "Arguments",
      "heading_level": 3,
      "content_markdown": "### Arguments\n\n**event _(String)_**\n\nAn event name to be handled via the `task` event in the [setupNodeEvents](/llm/markdown/app/plugins/plugins-guide.md#Using-a-plugin) function.\n\n**arg _(Object)_**\n\nAn argument to send along with the event. This can be any value that can be serialized by [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`.\n\nIf you need to pass multiple arguments, use an object\n\n```\n// in test\ncy.task('hello', { greeting: 'Hello', name: 'World' })\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        // deconstruct the individual properties\n        hello({ greeting, name }) {\n          console.log('%s, %s', greeting, name)\n\n          return null\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        // deconstruct the individual properties\n        hello({ greeting, name }) {\n          console.log('%s, %s', greeting, name)\n\n          return null\n        },\n      })\n    },\n  },\n})\n```\n\n**options _(Object)_**\n\nPass in an options object to change the default behavior of `cy.task()`.\n\n| Option | Default | Description |\n| --- | --- | --- |\n| `log` | `true` | Displays the command in the [Command log](/llm/markdown/app/core-concepts/open-mode.md#Command-Log) |\n| `timeout` | [`taskTimeout`](/llm/markdown/app/references/configuration.md#Timeouts) | Time to wait for `cy.task()` to resolve before [timing out](#Timeouts) |\n",
      "section": "api",
      "anchors": [
        "arguments"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 320
    },
    {
      "id": "api/commands/task#examples",
      "doc_id": "api/commands/task",
      "heading": "Examples",
      "heading_level": 2,
      "content_markdown": "## Examples\n\n`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:\n\n*   Seeding your test database.\n*   Storing state in Node that you want persisted between spec files.\n*   Performing parallel tasks, like making multiple http requests outside of Cypress.\n*   Running an external process.\n\n### Read a file that might not exist\n\nCommand [cy.readFile()](/llm/markdown/api/commands/readfile.md) assumes the file exists. If you need to read a file that might not exist, use `cy.task`.\n\n```\n// in test\ncy.task('readFileMaybe', 'my-file.txt').then((textOrNull) => { ... })\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\nconst fs = require('fs')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        readFileMaybe(filename) {\n          if (fs.existsSync(filename)) {\n            return fs.readFileSync(filename, 'utf8')\n          }\n\n          return null\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\nimport fs from 'fs'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        readFileMaybe(filename) {\n          if (fs.existsSync(filename)) {\n            return fs.readFileSync(filename, 'utf8')\n          }\n\n          return null\n        },\n      })\n    },\n  },\n})\n```\n\n### Return number of files in the folder\n\n```\n// in test\ncy.task('countFiles', 'cypress/downloads').then((count) => { ... })\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\nconst fs = require('fs')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        countFiles(folderName) {\n          return new Promise((resolve, reject) => {\n            fs.readdir(folderName, (err, files) => {\n              if (err) {\n                return reject(err)\n              }\n\n              resolve(files.length)\n            })\n          })\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\nimport fs from 'fs'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        countFiles(folderName) {\n          return new Promise((resolve, reject) => {\n            fs.readdir(folderName, (err, files) => {\n              if (err) {\n                return reject(err)\n              }\n\n              resolve(files.length)\n            })\n          })\n        },\n      })\n    },\n  },\n})\n```\n\n### Seed a database\n\n```\n// in test\ndescribe('e2e', () => {\n  beforeEach(() => {\n    cy.task('defaults:db')\n    cy.visit('/')\n  })\n\n  it('displays article values', () => {\n    cy.get('.article-list').should('have.length', 10)\n  })\n})\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\n// we require some code in our app that\n// is responsible for seeding our database\nconst db = require('../../server/src/db')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        'defaults:db': () => {\n          return db.seed('defaults')\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\n// we require some code in our app that\n// is responsible for seeding our database\nimport db from '../../server/src/db'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        'defaults:db': () => {\n          return db.seed('defaults')\n        },\n      })\n    },\n  },\n})\n```\n\n### Clean up and verify downloaded files\n\nTasks are a good fit for file system work, such as emptying the downloads folder between tests and then finding the file the test just downloaded. `config.downloadsFolder` is the resolved absolute path, so the task keeps working if the project overrides [`downloadsFolder`](/llm/markdown/app/references/configuration.md#Downloads).\n\ndownloads.cy.js\n\n```\ncy.task('clearDownloads')\n\ncy.task('latestDownload').then((filepath) => {\n  expect(filepath).to.be.a('string')\n  cy.readFile(filepath)\n})\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\nconst fs = require('fs')\nconst path = require('path')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      const downloads = config.downloadsFolder\n\n      on('task', {\n        clearDownloads() {\n          fs.rmSync(downloads, { recursive: true, force: true })\n          fs.mkdirSync(downloads, { recursive: true })\n\n          return null\n        },\n\n        latestDownload() {\n          const files = fs\n            .readdirSync(downloads)\n            .map((name) => ({\n              name,\n              time: fs.statSync(path.join(downloads, name)).mtimeMs,\n            }))\n            .sort((a, b) => b.time - a.time)\n\n          return files.length ? path.join(downloads, files[0].name) : null\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\nimport fs from 'fs'\nimport path from 'path'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      const downloads = config.downloadsFolder\n\n      on('task', {\n        clearDownloads() {\n          fs.rmSync(downloads, { recursive: true, force: true })\n          fs.mkdirSync(downloads, { recursive: true })\n\n          return null\n        },\n\n        latestDownload() {\n          const files = fs\n            .readdirSync(downloads)\n            .map((name) => ({\n              name,\n              time: fs.statSync(path.join(downloads, name)).mtimeMs,\n            }))\n            .sort((a, b) => b.time - a.time)\n\n          return files.length ? path.join(downloads, files[0].name) : null\n        },\n      })\n    },\n  },\n})\n```\n\nCypress already trashes the downloads folder before `cypress run` when [`trashAssetsBeforeRuns`](/llm/markdown/app/references/configuration.md#trashAssetsBeforeRuns) is enabled, which it is by default. A `clearDownloads` task is for clearing the folder between tests within a run.\n\n### Run an external command or CLI\n\nWhen setup depends on a tool that isn't a Node module, such as a Docker container, a database CLI, or a cloud provider's command line tool, spawn it from the task with [`child_process.execFileSync()`](https://nodejs.org/api/child_process.html#child_processexecfilesynccommand-args-options). Passing the arguments as an array avoids the shell entirely, so quoting and `PATH` resolution behave the same way on every platform.\n\ndatabase.cy.js\n\n```\ncy.task('resetDatabase')\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\nconst { execFileSync } = require('child_process')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        resetDatabase() {\n          execFileSync('docker', ['exec', 'db', 'reset-script'], {\n            stdio: 'pipe',\n          })\n\n          return null\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\nimport { execFileSync } from 'child_process'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        resetDatabase() {\n          execFileSync('docker', ['exec', 'db', 'reset-script'], {\n            stdio: 'pipe',\n          })\n\n          return null\n        },\n      })\n    },\n  },\n})\n```\n\nA task can also return the command's output to the test:\n\nbucket.cy.js\n\n```\ncy.task('listBucket', 's3://my-test-bucket').should('have.length', 3)\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\nconst { execFileSync } = require('child_process')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        listBucket(bucket) {\n          const output = execFileSync('aws', ['s3', 'ls', bucket], {\n            encoding: 'utf8',\n          })\n\n          return output.split('\\n').filter(Boolean)\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\nimport { execFileSync } from 'child_process'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        listBucket(bucket) {\n          const output = execFileSync('aws', ['s3', 'ls', bucket], {\n            encoding: 'utf8',\n          })\n\n          return output.split('\\n').filter(Boolean)\n        },\n      })\n    },\n  },\n})\n```\n\n### Run Node code before each test\n\nThere is no `setupNodeEvents` event for each test. To run Node code before every test, call `cy.task()` from a global `beforeEach` in your [support file](/llm/markdown/app/core-concepts/writing-and-organizing-tests.md#Support-file).\n\n```\n// cypress/support/e2e.js\nbeforeEach(function () {\n  cy.task('logTestStart', this.currentTest.fullTitle())\n})\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        logTestStart(title) {\n          console.log(`Starting: ${title}`)\n\n          return null\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        logTestStart(title) {\n          console.log(`Starting: ${title}`)\n\n          return null\n        },\n      })\n    },\n  },\n})\n```\n\n### Return a Promise from an asynchronous task\n\n```\n// in test\ncy.task('pause', 1000)\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        pause(ms) {\n          return new Promise((resolve) => {\n            // tasks should not resolve with undefined\n            setTimeout(() => resolve(null), ms)\n          })\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        pause(ms) {\n          return new Promise((resolve) => {\n            // tasks should not resolve with undefined\n            setTimeout(() => resolve(null), ms)\n          })\n        },\n      })\n    },\n  },\n})\n```\n\n### Save a variable across non same-origin URL visits\n\nWhen visiting non same-origin URL, Cypress will [change the hosted URL to the new URL](/llm/markdown/app/guides/cross-origin-testing.md), wiping the state of any local variables. We want to save a variable across visiting non same-origin URLs.\n\nWe can save the variable and retrieve the saved variable outside of the test using `cy.task()` as shown below.\n\n```\n// in test\ndescribe('Href visit', () => {\n  it('captures href', () => {\n    cy.visit('https://example.cypress.io')\n    cy.get('a')\n      .invoke('attr', 'href')\n      .then((href) => {\n        // href is not same-origin as current url\n        // like https://www.cypress-dx.com\n        cy.task('setHref', href)\n      })\n  })\n\n  it('visit href', () => {\n    cy.task('getHref').then((href) => {\n      // visit non same-origin url https://www.cypress-dx.com\n      cy.visit(href)\n    })\n  })\n})\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\nlet href\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        setHref: (val) => {\n          return (href = val)\n        },\n        getHref: () => {\n          return href\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\nlet href: string\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        setHref: (val) => {\n          return (href = val)\n        },\n        getHref: () => {\n          return href\n        },\n      })\n    },\n  },\n})\n```\n\n### Command options\n\n#### Change the timeout\n\nYou can increase the time allowed to execute the task, although _we do not recommend executing tasks that take a long time to exit_.\n\nCypress will _not_ continue running any other commands until `cy.task()` has finished, so a long-running command will drastically slow down your test runs.\n\n```\n// will fail if seeding the database takes longer than 20 seconds to finish\ncy.task('seedDatabase', null, { timeout: 20000 })\n```\n",
      "section": "api",
      "anchors": [
        "examples"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 2224
    },
    {
      "id": "api/commands/task#read-a-file-that-might-not-exist",
      "doc_id": "api/commands/task",
      "heading": "Read a file that might not exist",
      "heading_level": 3,
      "content_markdown": "### Read a file that might not exist\n\nCommand [cy.readFile()](/llm/markdown/api/commands/readfile.md) assumes the file exists. If you need to read a file that might not exist, use `cy.task`.\n\n```\n// in test\ncy.task('readFileMaybe', 'my-file.txt').then((textOrNull) => { ... })\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\nconst fs = require('fs')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        readFileMaybe(filename) {\n          if (fs.existsSync(filename)) {\n            return fs.readFileSync(filename, 'utf8')\n          }\n\n          return null\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\nimport fs from 'fs'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        readFileMaybe(filename) {\n          if (fs.existsSync(filename)) {\n            return fs.readFileSync(filename, 'utf8')\n          }\n\n          return null\n        },\n      })\n    },\n  },\n})\n```\n",
      "section": "api",
      "anchors": [
        "read-a-file-that-might-not-exist"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 192
    },
    {
      "id": "api/commands/task#return-number-of-files-in-the-folder",
      "doc_id": "api/commands/task",
      "heading": "Return number of files in the folder",
      "heading_level": 3,
      "content_markdown": "### Return number of files in the folder\n\n```\n// in test\ncy.task('countFiles', 'cypress/downloads').then((count) => { ... })\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\nconst fs = require('fs')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        countFiles(folderName) {\n          return new Promise((resolve, reject) => {\n            fs.readdir(folderName, (err, files) => {\n              if (err) {\n                return reject(err)\n              }\n\n              resolve(files.length)\n            })\n          })\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\nimport fs from 'fs'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        countFiles(folderName) {\n          return new Promise((resolve, reject) => {\n            fs.readdir(folderName, (err, files) => {\n              if (err) {\n                return reject(err)\n              }\n\n              resolve(files.length)\n            })\n          })\n        },\n      })\n    },\n  },\n})\n```\n",
      "section": "api",
      "anchors": [
        "return-number-of-files-in-the-folder"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 196
    },
    {
      "id": "api/commands/task#seed-a-database",
      "doc_id": "api/commands/task",
      "heading": "Seed a database",
      "heading_level": 3,
      "content_markdown": "### Seed a database\n\n```\n// in test\ndescribe('e2e', () => {\n  beforeEach(() => {\n    cy.task('defaults:db')\n    cy.visit('/')\n  })\n\n  it('displays article values', () => {\n    cy.get('.article-list').should('have.length', 10)\n  })\n})\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\n// we require some code in our app that\n// is responsible for seeding our database\nconst db = require('../../server/src/db')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        'defaults:db': () => {\n          return db.seed('defaults')\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\n// we require some code in our app that\n// is responsible for seeding our database\nimport db from '../../server/src/db'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        'defaults:db': () => {\n          return db.seed('defaults')\n        },\n      })\n    },\n  },\n})\n```\n",
      "section": "api",
      "anchors": [
        "seed-a-database"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 209
    },
    {
      "id": "api/commands/task#clean-up-and-verify-downloaded-files",
      "doc_id": "api/commands/task",
      "heading": "Clean up and verify downloaded files",
      "heading_level": 3,
      "content_markdown": "### Clean up and verify downloaded files\n\nTasks are a good fit for file system work, such as emptying the downloads folder between tests and then finding the file the test just downloaded. `config.downloadsFolder` is the resolved absolute path, so the task keeps working if the project overrides [`downloadsFolder`](/llm/markdown/app/references/configuration.md#Downloads).\n\ndownloads.cy.js\n\n```\ncy.task('clearDownloads')\n\ncy.task('latestDownload').then((filepath) => {\n  expect(filepath).to.be.a('string')\n  cy.readFile(filepath)\n})\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\nconst fs = require('fs')\nconst path = require('path')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      const downloads = config.downloadsFolder\n\n      on('task', {\n        clearDownloads() {\n          fs.rmSync(downloads, { recursive: true, force: true })\n          fs.mkdirSync(downloads, { recursive: true })\n\n          return null\n        },\n\n        latestDownload() {\n          const files = fs\n            .readdirSync(downloads)\n            .map((name) => ({\n              name,\n              time: fs.statSync(path.join(downloads, name)).mtimeMs,\n            }))\n            .sort((a, b) => b.time - a.time)\n\n          return files.length ? path.join(downloads, files[0].name) : null\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\nimport fs from 'fs'\nimport path from 'path'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      const downloads = config.downloadsFolder\n\n      on('task', {\n        clearDownloads() {\n          fs.rmSync(downloads, { recursive: true, force: true })\n          fs.mkdirSync(downloads, { recursive: true })\n\n          return null\n        },\n\n        latestDownload() {\n          const files = fs\n            .readdirSync(downloads)\n            .map((name) => ({\n              name,\n              time: fs.statSync(path.join(downloads, name)).mtimeMs,\n            }))\n            .sort((a, b) => b.time - a.time)\n\n          return files.length ? path.join(downloads, files[0].name) : null\n        },\n      })\n    },\n  },\n})\n```\n\nCypress already trashes the downloads folder before `cypress run` when [`trashAssetsBeforeRuns`](/llm/markdown/app/references/configuration.md#trashAssetsBeforeRuns) is enabled, which it is by default. A `clearDownloads` task is for clearing the folder between tests within a run.\n",
      "section": "api",
      "anchors": [
        "clean-up-and-verify-downloaded-files"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 373
    },
    {
      "id": "api/commands/task#run-an-external-command-or-cli",
      "doc_id": "api/commands/task",
      "heading": "Run an external command or CLI",
      "heading_level": 3,
      "content_markdown": "### Run an external command or CLI\n\nWhen setup depends on a tool that isn't a Node module, such as a Docker container, a database CLI, or a cloud provider's command line tool, spawn it from the task with [`child_process.execFileSync()`](https://nodejs.org/api/child_process.html#child_processexecfilesynccommand-args-options). Passing the arguments as an array avoids the shell entirely, so quoting and `PATH` resolution behave the same way on every platform.\n\ndatabase.cy.js\n\n```\ncy.task('resetDatabase')\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\nconst { execFileSync } = require('child_process')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        resetDatabase() {\n          execFileSync('docker', ['exec', 'db', 'reset-script'], {\n            stdio: 'pipe',\n          })\n\n          return null\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\nimport { execFileSync } from 'child_process'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        resetDatabase() {\n          execFileSync('docker', ['exec', 'db', 'reset-script'], {\n            stdio: 'pipe',\n          })\n\n          return null\n        },\n      })\n    },\n  },\n})\n```\n\nA task can also return the command's output to the test:\n\nbucket.cy.js\n\n```\ncy.task('listBucket', 's3://my-test-bucket').should('have.length', 3)\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\nconst { execFileSync } = require('child_process')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        listBucket(bucket) {\n          const output = execFileSync('aws', ['s3', 'ls', bucket], {\n            encoding: 'utf8',\n          })\n\n          return output.split('\\n').filter(Boolean)\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\nimport { execFileSync } from 'child_process'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        listBucket(bucket) {\n          const output = execFileSync('aws', ['s3', 'ls', bucket], {\n            encoding: 'utf8',\n          })\n\n          return output.split('\\n').filter(Boolean)\n        },\n      })\n    },\n  },\n})\n```\n",
      "section": "api",
      "anchors": [
        "run-an-external-command-or-cli"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 417
    },
    {
      "id": "api/commands/task#run-node-code-before-each-test",
      "doc_id": "api/commands/task",
      "heading": "Run Node code before each test",
      "heading_level": 3,
      "content_markdown": "### Run Node code before each test\n\nThere is no `setupNodeEvents` event for each test. To run Node code before every test, call `cy.task()` from a global `beforeEach` in your [support file](/llm/markdown/app/core-concepts/writing-and-organizing-tests.md#Support-file).\n\n```\n// cypress/support/e2e.js\nbeforeEach(function () {\n  cy.task('logTestStart', this.currentTest.fullTitle())\n})\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        logTestStart(title) {\n          console.log(`Starting: ${title}`)\n\n          return null\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        logTestStart(title) {\n          console.log(`Starting: ${title}`)\n\n          return null\n        },\n      })\n    },\n  },\n})\n```\n",
      "section": "api",
      "anchors": [
        "run-node-code-before-each-test"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 173
    },
    {
      "id": "api/commands/task#return-a-promise-from-an-asynchronous-task",
      "doc_id": "api/commands/task",
      "heading": "Return a Promise from an asynchronous task",
      "heading_level": 3,
      "content_markdown": "### Return a Promise from an asynchronous task\n\n```\n// in test\ncy.task('pause', 1000)\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        pause(ms) {\n          return new Promise((resolve) => {\n            // tasks should not resolve with undefined\n            setTimeout(() => resolve(null), ms)\n          })\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        pause(ms) {\n          return new Promise((resolve) => {\n            // tasks should not resolve with undefined\n            setTimeout(() => resolve(null), ms)\n          })\n        },\n      })\n    },\n  },\n})\n```\n",
      "section": "api",
      "anchors": [
        "return-a-promise-from-an-asynchronous-task"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 172
    },
    {
      "id": "api/commands/task#save-a-variable-across-non-same-origin-url-visits",
      "doc_id": "api/commands/task",
      "heading": "Save a variable across non same-origin URL visits",
      "heading_level": 3,
      "content_markdown": "### Save a variable across non same-origin URL visits\n\nWhen visiting non same-origin URL, Cypress will [change the hosted URL to the new URL](/llm/markdown/app/guides/cross-origin-testing.md), wiping the state of any local variables. We want to save a variable across visiting non same-origin URLs.\n\nWe can save the variable and retrieve the saved variable outside of the test using `cy.task()` as shown below.\n\n```\n// in test\ndescribe('Href visit', () => {\n  it('captures href', () => {\n    cy.visit('https://example.cypress.io')\n    cy.get('a')\n      .invoke('attr', 'href')\n      .then((href) => {\n        // href is not same-origin as current url\n        // like https://www.cypress-dx.com\n        cy.task('setHref', href)\n      })\n  })\n\n  it('visit href', () => {\n    cy.task('getHref').then((href) => {\n      // visit non same-origin url https://www.cypress-dx.com\n      cy.visit(href)\n    })\n  })\n})\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\nlet href\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        setHref: (val) => {\n          return (href = val)\n        },\n        getHref: () => {\n          return href\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\nlet href: string\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        setHref: (val) => {\n          return (href = val)\n        },\n        getHref: () => {\n          return href\n        },\n      })\n    },\n  },\n})\n```\n",
      "section": "api",
      "anchors": [
        "save-a-variable-across-non-same-origin-url-visits"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 303
    },
    {
      "id": "api/commands/task#command-options",
      "doc_id": "api/commands/task",
      "heading": "Command options",
      "heading_level": 3,
      "content_markdown": "### Command options\n\n#### Change the timeout\n\nYou can increase the time allowed to execute the task, although _we do not recommend executing tasks that take a long time to exit_.\n\nCypress will _not_ continue running any other commands until `cy.task()` has finished, so a long-running command will drastically slow down your test runs.\n\n```\n// will fail if seeding the database takes longer than 20 seconds to finish\ncy.task('seedDatabase', null, { timeout: 20000 })\n```\n",
      "section": "api",
      "anchors": [
        "command-options"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 101
    },
    {
      "id": "api/commands/task#change-the-timeout",
      "doc_id": "api/commands/task",
      "heading": "Change the timeout",
      "heading_level": 4,
      "content_markdown": "#### Change the timeout\n\nYou can increase the time allowed to execute the task, although _we do not recommend executing tasks that take a long time to exit_.\n\nCypress will _not_ continue running any other commands until `cy.task()` has finished, so a long-running command will drastically slow down your test runs.\n\n```\n// will fail if seeding the database takes longer than 20 seconds to finish\ncy.task('seedDatabase', null, { timeout: 20000 })\n```\n",
      "section": "api",
      "anchors": [
        "change-the-timeout"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 97
    },
    {
      "id": "api/commands/task#notes",
      "doc_id": "api/commands/task",
      "heading": "Notes",
      "heading_level": 2,
      "content_markdown": "## Notes\n\n### Tasks must end\n\n#### Tasks that do not end are not supported\n\n`cy.task()` does not support tasks that do not end, such as:\n\n*   Starting a server.\n*   A task that watches for file changes.\n*   Any process that needs to be manually interrupted to stop.\n\nA task must end within the `taskTimeout` or Cypress will fail the current test.\n\n### Tasks are merged automatically\n\nSometimes 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 [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:\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\nconst skipAndOnlyTask = require('cypress-skip-and-only-ui/task')\nconst fs = require('fs')\nconst myTask = {\n  readFileMaybe(filename) {\n    if (fs.existsSync(filename)) {\n      return fs.readFileSync(filename, 'utf8')\n    }\n\n    return null\n  },\n}\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      // register plugin's task\n      on('task', skipAndOnlyTask)\n      // and register my own task\n      on('task', myTask)\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\nimport skipAndOnlyTask from 'cypress-skip-and-only-ui/task'\nimport fs from 'fs'\nconst myTask = {\n  readFileMaybe(filename) {\n    if (fs.existsSync(filename)) {\n      return fs.readFileSync(filename, 'utf8')\n    }\n\n    return null\n  },\n}\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      // register plugin's task\n      on('task', skipAndOnlyTask)\n      // and register my own task\n      on('task', myTask)\n    },\n  },\n})\n```\n\nSee [#2284](https://github.com/cypress-io/cypress/issues/2284) for implementation.\n\n**Duplicate task keys**\n\nIf multiple task objects use the same key, the later registration will overwrite that particular key, similar to how merging multiple objects with duplicate keys will overwrite the first one.\n\n### Reset timeout via `Cypress.config()`\n\nYou can change the timeout of `cy.task()` for the remainder of the tests by setting the new values for `taskTimeout` within [Cypress.config()](/llm/markdown/api/cypress-api/config.md).\n\n```\nCypress.config('taskTimeout', 30000)\nCypress.config('taskTimeout') // => 30000\n```\n\n### Set timeout in the test configuration\n\nYou can configure the `cy.task()` timeout within a suite or test by passing the new configuration value within the [test configuration](/llm/markdown/app/references/configuration.md#Test-Configuration).\n\nThis will set the timeout throughout the duration of the tests, then return it to the default `taskTimeout` when complete.\n\n```\ndescribe('has data available from database', { taskTimeout: 90000 }, () => {\n  before(() => {\n    cy.task('seedDatabase')\n  })\n\n  // tests\n\n  after(() => {\n    cy.task('resetDatabase')\n  })\n})\n```\n\n### Allows a single argument only\n\nThe syntax `cy.task(name, arg, options)` only has place for a single argument to be passed from the test code to the plugins code. In the situations where you would like to pass multiple arguments, place them into an object to be destructured inside the task code. For example, if you would like to execute a database query and pass the database profile name you could do:\n\n```\n// in test\nconst dbName = 'stagingA'\nconst query = 'SELECT * FROM users'\n\ncy.task('queryDatabase', { dbName, query })\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\nconst mysql = require('mysql')\n// the connection strings for different databases could\n// come from system environment variables\nconst connections = {\n  stagingA: {\n    host: 'staging.my.co',\n    user: 'test',\n    password: '***',\n    database: 'users',\n  },\n  stagingB: {\n    host: 'staging-b.my.co',\n    user: 'test',\n    password: '***',\n    database: 'users',\n  },\n}\n\n// querying the database from Node\nfunction queryDB(connectionInfo, query) {\n  const connection = mysql.createConnection(connectionInfo)\n\n  connection.connect()\n\n  return new Promise((resolve, reject) => {\n    connection.query(query, (error, results) => {\n      if (error) {\n        return reject(error)\n      }\n\n      connection.end()\n\n      return resolve(results)\n    })\n  })\n}\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        // destructure the argument into the individual fields\n        queryDatabase({ dbName, query }) {\n          const connectionInfo = connections[dbName]\n\n          if (!connectionInfo) {\n            throw new Error(`Do not have DB connection under name ${dbName}`)\n          }\n\n          return queryDB(connectionInfo, query)\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\nimport mysql from 'mysql'\n// the connection strings for different databases could\n// come from system environment variables\nconst connections = {\n  stagingA: {\n    host: 'staging.my.co',\n    user: 'test',\n    password: '***',\n    database: 'users',\n  },\n  stagingB: {\n    host: 'staging-b.my.co',\n    user: 'test',\n    password: '***',\n    database: 'users',\n  },\n}\n\n// querying the database from Node\nfunction queryDB(connectionInfo, query) {\n  const connection = mysql.createConnection(connectionInfo)\n\n  connection.connect()\n\n  return new Promise((resolve, reject) => {\n    connection.query(query, (error, results) => {\n      if (error) {\n        return reject(error)\n      }\n\n      connection.end()\n\n      return resolve(results)\n    })\n  })\n}\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        // destructure the argument into the individual fields\n        queryDatabase({ dbName, query }) {\n          const connectionInfo = connections[dbName]\n\n          if (!connectionInfo) {\n            throw new Error(`Do not have DB connection under name ${dbName}`)\n          }\n\n          return queryDB(connectionInfo, query)\n        },\n      })\n    },\n  },\n})\n```\n\n### Argument should be serializable\n\nThe argument `arg` sent via `cy.task(name, arg)` should be serializable; it cannot have circular dependencies (issue [#5539](https://github.com/cypress-io/cypress/issues/5539)). If there are any special fields like `Date`, you are responsible for their conversion (issue [#4980](https://github.com/cypress-io/cypress/issues/4980)):\n\n```\n// in test\ncy.task('date', new Date()).then((s) => {\n  // the yielded result is a string\n  // we need to convert it to Date object\n  const result = new Date(s)\n})\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        date(s) {\n          // s is a string, so convert it to Date\n          const d = new Date(s)\n\n          // do something with the date\n          // and return it back\n          return d\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        date(s) {\n          // s is a string, so convert it to Date\n          const d = new Date(s)\n\n          // do something with the date\n          // and return it back\n          return d\n        },\n      })\n    },\n  },\n})\n```\n\n### Accessing secrets securely\n\nYou can use `cy.task()` to securely access secrets at runtime when they aren't available during configuration. Using `cy.task()` may be useful when secrets are retrieved from external secret managers or APIs that aren't available at configuration time.\n\n[cy.env()](/llm/markdown/api/commands/env.md) is the preferred way to access secrets securely and use them in your tests, and is recommended for secrets that are available at configuration time.\n\n```\n// in test - executes at runtime\ncy.task('getSecret', 'API_KEY').then((apiKey) => {\n  cy.request({\n    method: 'POST',\n    url: 'https://api.example.com/data',\n    headers: {\n      Authorization: `Bearer ${apiKey}`,\n    },\n  })\n})\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      // Task definition - executes when cy.task() is called in tests\n      on('task', {\n        getSecret(secretName) {\n          // This reads from process.env at runtime, not at configuration time\n          // Useful when secrets are fetched dynamically or only needed conditionally\n          const secret = process.env[secretName]\n\n          if (!secret) {\n            throw new Error(`Secret ${secretName} is not set`)\n          }\n\n          return secret\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      // Task definition - executes when cy.task() is called in tests\n      on('task', {\n        getSecret(secretName: string) {\n          // This reads from process.env at runtime, not at configuration time\n          // Useful when secrets are fetched dynamically or only needed conditionally\n          const secret = process.env[secretName]\n\n          if (!secret) {\n            throw new Error(`Secret ${secretName} is not set`)\n          }\n\n          return secret\n        },\n      })\n    },\n  },\n})\n```\n",
      "section": "api",
      "anchors": [
        "notes"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 1715
    },
    {
      "id": "api/commands/task#tasks-must-end",
      "doc_id": "api/commands/task",
      "heading": "Tasks must end",
      "heading_level": 3,
      "content_markdown": "### Tasks must end\n\n#### Tasks that do not end are not supported\n\n`cy.task()` does not support tasks that do not end, such as:\n\n*   Starting a server.\n*   A task that watches for file changes.\n*   Any process that needs to be manually interrupted to stop.\n\nA task must end within the `taskTimeout` or Cypress will fail the current test.\n",
      "section": "api",
      "anchors": [
        "tasks-must-end"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 81
    },
    {
      "id": "api/commands/task#tasks-that-do-not-end-are-not-supported",
      "doc_id": "api/commands/task",
      "heading": "Tasks that do not end are not supported",
      "heading_level": 4,
      "content_markdown": "#### Tasks that do not end are not supported\n\n`cy.task()` does not support tasks that do not end, such as:\n\n*   Starting a server.\n*   A task that watches for file changes.\n*   Any process that needs to be manually interrupted to stop.\n\nA task must end within the `taskTimeout` or Cypress will fail the current test.\n",
      "section": "api",
      "anchors": [
        "tasks-that-do-not-end-are-not-supported"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 76
    },
    {
      "id": "api/commands/task#tasks-are-merged-automatically",
      "doc_id": "api/commands/task",
      "heading": "Tasks are merged automatically",
      "heading_level": 3,
      "content_markdown": "### Tasks are merged automatically\n\nSometimes 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 [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:\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\nconst skipAndOnlyTask = require('cypress-skip-and-only-ui/task')\nconst fs = require('fs')\nconst myTask = {\n  readFileMaybe(filename) {\n    if (fs.existsSync(filename)) {\n      return fs.readFileSync(filename, 'utf8')\n    }\n\n    return null\n  },\n}\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      // register plugin's task\n      on('task', skipAndOnlyTask)\n      // and register my own task\n      on('task', myTask)\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\nimport skipAndOnlyTask from 'cypress-skip-and-only-ui/task'\nimport fs from 'fs'\nconst myTask = {\n  readFileMaybe(filename) {\n    if (fs.existsSync(filename)) {\n      return fs.readFileSync(filename, 'utf8')\n    }\n\n    return null\n  },\n}\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      // register plugin's task\n      on('task', skipAndOnlyTask)\n      // and register my own task\n      on('task', myTask)\n    },\n  },\n})\n```\n\nSee [#2284](https://github.com/cypress-io/cypress/issues/2284) for implementation.\n\n**Duplicate task keys**\n\nIf multiple task objects use the same key, the later registration will overwrite that particular key, similar to how merging multiple objects with duplicate keys will overwrite the first one.\n",
      "section": "api",
      "anchors": [
        "tasks-are-merged-automatically"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 307
    },
    {
      "id": "api/commands/task#reset-timeout-via-cypress-config",
      "doc_id": "api/commands/task",
      "heading": "Reset timeout via Cypress.config()",
      "heading_level": 3,
      "content_markdown": "### Reset timeout via `Cypress.config()`\n\nYou can change the timeout of `cy.task()` for the remainder of the tests by setting the new values for `taskTimeout` within [Cypress.config()](/llm/markdown/api/cypress-api/config.md).\n\n```\nCypress.config('taskTimeout', 30000)\nCypress.config('taskTimeout') // => 30000\n```\n",
      "section": "api",
      "anchors": [
        "reset-timeout-via-cypress-config"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 47
    },
    {
      "id": "api/commands/task#set-timeout-in-the-test-configuration",
      "doc_id": "api/commands/task",
      "heading": "Set timeout in the test configuration",
      "heading_level": 3,
      "content_markdown": "### Set timeout in the test configuration\n\nYou can configure the `cy.task()` timeout within a suite or test by passing the new configuration value within the [test configuration](/llm/markdown/app/references/configuration.md#Test-Configuration).\n\nThis will set the timeout throughout the duration of the tests, then return it to the default `taskTimeout` when complete.\n\n```\ndescribe('has data available from database', { taskTimeout: 90000 }, () => {\n  before(() => {\n    cy.task('seedDatabase')\n  })\n\n  // tests\n\n  after(() => {\n    cy.task('resetDatabase')\n  })\n})\n```\n",
      "section": "api",
      "anchors": [
        "set-timeout-in-the-test-configuration"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 100
    },
    {
      "id": "api/commands/task#allows-a-single-argument-only",
      "doc_id": "api/commands/task",
      "heading": "Allows a single argument only",
      "heading_level": 3,
      "content_markdown": "### Allows a single argument only\n\nThe syntax `cy.task(name, arg, options)` only has place for a single argument to be passed from the test code to the plugins code. In the situations where you would like to pass multiple arguments, place them into an object to be destructured inside the task code. For example, if you would like to execute a database query and pass the database profile name you could do:\n\n```\n// in test\nconst dbName = 'stagingA'\nconst query = 'SELECT * FROM users'\n\ncy.task('queryDatabase', { dbName, query })\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\nconst mysql = require('mysql')\n// the connection strings for different databases could\n// come from system environment variables\nconst connections = {\n  stagingA: {\n    host: 'staging.my.co',\n    user: 'test',\n    password: '***',\n    database: 'users',\n  },\n  stagingB: {\n    host: 'staging-b.my.co',\n    user: 'test',\n    password: '***',\n    database: 'users',\n  },\n}\n\n// querying the database from Node\nfunction queryDB(connectionInfo, query) {\n  const connection = mysql.createConnection(connectionInfo)\n\n  connection.connect()\n\n  return new Promise((resolve, reject) => {\n    connection.query(query, (error, results) => {\n      if (error) {\n        return reject(error)\n      }\n\n      connection.end()\n\n      return resolve(results)\n    })\n  })\n}\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        // destructure the argument into the individual fields\n        queryDatabase({ dbName, query }) {\n          const connectionInfo = connections[dbName]\n\n          if (!connectionInfo) {\n            throw new Error(`Do not have DB connection under name ${dbName}`)\n          }\n\n          return queryDB(connectionInfo, query)\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\nimport mysql from 'mysql'\n// the connection strings for different databases could\n// come from system environment variables\nconst connections = {\n  stagingA: {\n    host: 'staging.my.co',\n    user: 'test',\n    password: '***',\n    database: 'users',\n  },\n  stagingB: {\n    host: 'staging-b.my.co',\n    user: 'test',\n    password: '***',\n    database: 'users',\n  },\n}\n\n// querying the database from Node\nfunction queryDB(connectionInfo, query) {\n  const connection = mysql.createConnection(connectionInfo)\n\n  connection.connect()\n\n  return new Promise((resolve, reject) => {\n    connection.query(query, (error, results) => {\n      if (error) {\n        return reject(error)\n      }\n\n      connection.end()\n\n      return resolve(results)\n    })\n  })\n}\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        // destructure the argument into the individual fields\n        queryDatabase({ dbName, query }) {\n          const connectionInfo = connections[dbName]\n\n          if (!connectionInfo) {\n            throw new Error(`Do not have DB connection under name ${dbName}`)\n          }\n\n          return queryDB(connectionInfo, query)\n        },\n      })\n    },\n  },\n})\n```\n",
      "section": "api",
      "anchors": [
        "allows-a-single-argument-only"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 537
    },
    {
      "id": "api/commands/task#argument-should-be-serializable",
      "doc_id": "api/commands/task",
      "heading": "Argument should be serializable",
      "heading_level": 3,
      "content_markdown": "### Argument should be serializable\n\nThe argument `arg` sent via `cy.task(name, arg)` should be serializable; it cannot have circular dependencies (issue [#5539](https://github.com/cypress-io/cypress/issues/5539)). If there are any special fields like `Date`, you are responsible for their conversion (issue [#4980](https://github.com/cypress-io/cypress/issues/4980)):\n\n```\n// in test\ncy.task('date', new Date()).then((s) => {\n  // the yielded result is a string\n  // we need to convert it to Date object\n  const result = new Date(s)\n})\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        date(s) {\n          // s is a string, so convert it to Date\n          const d = new Date(s)\n\n          // do something with the date\n          // and return it back\n          return d\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      on('task', {\n        date(s) {\n          // s is a string, so convert it to Date\n          const d = new Date(s)\n\n          // do something with the date\n          // and return it back\n          return d\n        },\n      })\n    },\n  },\n})\n```\n",
      "section": "api",
      "anchors": [
        "argument-should-be-serializable"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 275
    },
    {
      "id": "api/commands/task#accessing-secrets-securely",
      "doc_id": "api/commands/task",
      "heading": "Accessing secrets securely",
      "heading_level": 3,
      "content_markdown": "### Accessing secrets securely\n\nYou can use `cy.task()` to securely access secrets at runtime when they aren't available during configuration. Using `cy.task()` may be useful when secrets are retrieved from external secret managers or APIs that aren't available at configuration time.\n\n[cy.env()](/llm/markdown/api/commands/env.md) is the preferred way to access secrets securely and use them in your tests, and is recommended for secrets that are available at configuration time.\n\n```\n// in test - executes at runtime\ncy.task('getSecret', 'API_KEY').then((apiKey) => {\n  cy.request({\n    method: 'POST',\n    url: 'https://api.example.com/data',\n    headers: {\n      Authorization: `Bearer ${apiKey}`,\n    },\n  })\n})\n```\n\n*   cypress.config.js\n*   cypress.config.ts\n\n```\nconst { defineConfig } = require('cypress')\n\nmodule.exports = defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      // Task definition - executes when cy.task() is called in tests\n      on('task', {\n        getSecret(secretName) {\n          // This reads from process.env at runtime, not at configuration time\n          // Useful when secrets are fetched dynamically or only needed conditionally\n          const secret = process.env[secretName]\n\n          if (!secret) {\n            throw new Error(`Secret ${secretName} is not set`)\n          }\n\n          return secret\n        },\n      })\n    },\n  },\n})\n```\n\n```\nimport { defineConfig } from 'cypress'\n\nexport default defineConfig({\n  // setupNodeEvents can be defined in either\n  // the e2e or component configuration\n  e2e: {\n    setupNodeEvents(on, config) {\n      // Task definition - executes when cy.task() is called in tests\n      on('task', {\n        getSecret(secretName: string) {\n          // This reads from process.env at runtime, not at configuration time\n          // Useful when secrets are fetched dynamically or only needed conditionally\n          const secret = process.env[secretName]\n\n          if (!secret) {\n            throw new Error(`Secret ${secretName} is not set`)\n          }\n\n          return secret\n        },\n      })\n    },\n  },\n})\n```\n",
      "section": "api",
      "anchors": [
        "accessing-secrets-securely"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 365
    },
    {
      "id": "api/commands/task#rules",
      "doc_id": "api/commands/task",
      "heading": "Rules",
      "heading_level": 2,
      "content_markdown": "## Rules\n\n### Requirements\n\n*   `cy.task()` requires being chained off of `cy`.\n*   `cy.task()` requires the task to eventually end.\n\n### Assertions\n\n*   `cy.task()` will only run assertions you have chained once, and will not [retry](/llm/markdown/app/core-concepts/retry-ability.md).\n\n### Timeouts\n\n*   `cy.task()` can time out waiting for the task to end.\n",
      "section": "api",
      "anchors": [
        "rules"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 65
    },
    {
      "id": "api/commands/task#command-log",
      "doc_id": "api/commands/task",
      "heading": "Command Log",
      "heading_level": 2,
      "content_markdown": "## Command Log\n\nThis example uses the [Return number of files in the folder](#Return-number-of-files-in-the-folder) task defined above.\n\n```\ncy.task('countFiles', 'cypress/e2e')\n```\n\nThe command above will display in the Command Log as:\n\nWhen clicking on the `task` command within the command log, the console outputs the following:\n",
      "section": "api",
      "anchors": [
        "command-log"
      ],
      "path": "/llm/json/chunked/api/commands/task.json",
      "token_estimate": 61
    }
  ]
}