Spec-Zone.ru › Cypress

задача

Выполните код в Node через событие плагина task.

Антипаттерн

Мы не рекомендуем запускать веб-сервер с использованием cy.task(). Прочтите о лучших практиках здесь.

Синтаксис

cy.task(event)
cy.task(event, arg)
cy.task(event, arg, options)

Использование

Правильное использование

// in test
cy.task('log', 'This will be output to the terminal')
// in plugins file
module.exports = (on, config) => {
  on('task', {
    log(message) {
      console.log(message)

      return null
    },
  })
}

Обработчик события плагина task может возвращать значение или промис. Команда завершится с ошибкой, если будет возвращено undefined или если промис разрешится со значением undefined. Это помогает поймать опечатки или случаи, когда событие задачи не обрабатывается.

Если вам не нужно возвращать значение, явным образом верните null, чтобы указать, что данное событие обработано.

Аргументы

event (Строка)

Имя события, которое будет обработано через событие task в файле pluginsFile.

arg (Объект)

Аргумент, передаваемый вместе с событием. Это может быть любое значение, которое может быть сериализовано с помощью JSON.stringify(). Несериализуемые типы, такие как функции, регулярные выражения или символы, будут опущены для null.

Если вам нужно передать несколько аргументов, используйте объект

// in test
cy.task('hello', { greeting: 'Hello', name: 'World' })
// in plugins/index.js
module.exports = (on, config) => {
  on('task', {
    // deconstruct the individual properties
    hello({ greeting, name }) {
      console.log('%s, %s', greeting, name)

      return null
    },
  })
}

options (Объект)

Передайте объект options, чтобы изменить стандартное поведение cy.task().

Параметр Значение по умолчанию Описание
log true Отображает команду в Журнале команд
timeout taskTimeout Время ожидания cy.task() до истечения времени ожидания

Возвращаемые значения

cy.task() возвращает значение, возвращенное или разрешенное событием task в файле pluginsFile.

Примеры

cy.task() предоставляет возможность выполнения произвольного кода Node, чтобы вы могли выполнять действия, необходимые для ваших тестов, вне контекста Cypress. Это отлично подходит для:

  • Инициализации вашей тестовой базы данных.
  • Хранения состояния в Node, которое вы хотите сохранить между файлами спецификаций.
  • Выполнения параллельных задач, таких как отправка нескольких http-запросов вне Cypress.
  • Выполнения внешнего процесса.

Чтение файла, который может отсутствовать

Команда cy.readFile() предполагает, что файл существует. Если вам нужно прочитать файл, который может отсутствовать, используйте cy.task.

// in test
cy.task('readFileMaybe', 'my-file.txt').then((textOrNull) => { ... })
// in plugins/index.js
const fs = require('fs')

module.exports = (on, config) => {
  on('task', {
    readFileMaybe(filename) {
      if (fs.existsSync(filename)) {
        return fs.readFileSync(filename, 'utf8')
      }

      return null
    },
  })
}

Возврат количества файлов в папке

// in test
cy.task('countFiles', 'cypress/downloads').then((count) => { ... })
// in plugins/index.js
const fs = require('fs')

module.exports = (on, config) => {
  on('task', {
    countFiles(folderName) {
      return new Promise((resolve, reject) => {
        fs.readdir(folderName, (err, files) => {
          if (err) {
            return reject(err)
          }

          resolve(files.length)
        })
      })
    },
  })
}

Инициализация базы данных

// 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
module.exports = (on, config) => {
  on('task', {
    pause(ms) {
      return new Promise((resolve) => {
        // tasks should not resolve with undefined
        setTimeout(() => resolve(null), ms)
      })
    },
  })
}

Сохранение переменной при переходе по URL с другим источником

При переходе по URL с другим источником Cypress будет изменять хостинг-URL на новый URL, очищая состояние любых локальных переменных. Мы хотим сохранить переменную при переходе по URL с другим источником.

Мы можем сохранить переменную и получить сохраненную переменную вне теста с помощью cy.task(), как показано ниже.

// in test
describe('Href visit', () => {
  it('captures href', () => {
    cy.visit('https://www.mywebapp.com')
    cy.get('a')
      .invoke('attr', 'href')
      .then((href) => {
        // href is not same-origin as current url
        // like https://www.anotherwebapp.com
        cy.task('setHref', href)
      })
  })

  it('visit href', () => {
    cy.task('getHref').then((href) => {
      // visit non same-origin url https://www.anotherwebapp.com
      cy.visit(href)
    })
  })
})
// in plugins/index.js
let href

module.exports = (on, config) => {
  on('task', {
    setHref: (val) => {
      return (href = val)
    },
    getHref: () => {
      return href
    },
  })
}

Параметры команды

Изменение таймаута

Вы можете увеличить время, отведенное на выполнение задачи, хотя мы не рекомендуем выполнять задачи, которые долго завершаются.

Cypress не будет продолжать выполнение других команд до завершения cy.task(), поэтому длительная команда значительно замедлит выполнение ваших тестов.

// will fail if seeding the database takes longer than 20 seconds to finish
cy.task('seedDatabase', null, { timeout: 20000 })

Примечания

Задачи должны завершаться

Задачи, которые не завершаются, не поддерживаются

cy.task() не поддерживает задачи, которые не завершаются, такие как:

  • Запуск сервера.
  • Задача, отслеживающая изменения файлов.
  • Любой процесс, для остановки которого необходимо ручное вмешательство.

Задача должна завершиться в течение taskTimeout или Cypress завершит текущий тест с ошибкой.

Задачи автоматически объединяются

Иногда вы можете использовать плагины, которые экспортируют свои задачи для регистрации. Cypress автоматически объединяет on('task') объекты для вас. Например, если вы используете плагин cypress-skip-and-only-ui и хотите установить свою собственную задачу для чтения файла, который может отсутствовать:

// 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)

См. #2284 для реализации.

Дублирование ключей задач

Если несколько объектов задач используют один и тот же ключ, более поздняя регистрация перезапишет этот ключ, аналогично тому, как объединение нескольких объектов с дублирующими ключами перезаписывает первый.

Сброс таймаута через Cypress.config()

Вы можете изменить таймаут cy.task() для оставшейся части тестов, установив новые значения для taskTimeout в Cypress.config().

Cypress.config('taskTimeout', 30000)
Cypress.config('taskTimeout') // => 30000

Установить таймаут в настройках теста

Вы можете настроить таймаут cy.task() в наборе или тесте, передав новое значение конфигурации в настройках теста.

Это установит таймаут на все время выполнения тестов, а затем вернет его к значению по умолчанию taskTimeout по завершении.

describe('has data available from database', { taskTimeout: 90000 }, () => {
  before(() => {
    cy.task('seedDatabase')
  })

  // tests

  after(() => {
    cy.task('resetDatabase')
  })
})

Разрешает только один аргумент

Синтаксис cy.task(name, arg, options) предусматривает только один аргумент, передаваемый из кода теста в код плагинов. В ситуациях, когда вы хотите передать несколько аргументов, поместите их в объект, чтобы разобрать его внутри кода задачи. Например, если вы хотите выполнить запрос к базе данных и передать имя профиля базы данных, вы можете сделать так:

// in test
const dbName = 'stagingA'
const query = 'SELECT * FROM users'

cy.task('queryDatabase', { dbName, query })
// in plugins/index.js
const mysql = require('mysql')
// the connection strings for different databases could
// come from a config file, or from environment variables
const connections = {
  stagingA: {
    host: 'staging.my.co',
    user: 'test',
    password: '***',
    database: 'users',
  },
  stagingB: {
    host: 'staging-b.my.co',
    user: 'test',
    password: '***',
    database: 'users',
  },
}

// querying the database from Node
function queryDB(connectionInfo, query) {
  const connection = mysql.createConnection(connectionInfo)

  connection.connect()

  return new Promise((resolve, reject) => {
    connection.query(query, (error, results) => {
      if (error) {
        return reject(error)
      }

      connection.end()

      return resolve(results)
    })
  })
}
module.exports = (on, config) => {
  on('task', {
    // destructure the argument into the individual fields
    queryDatabase({ dbName, query }) {
      const connectionInfo = connections[dbName]

      if (!connectionInfo) {
        throw new Error(`Do not have DB connection under name ${dbName}`)
      }

      return queryDB(connectionInfo, query)
    },
  })
}

Аргумент должен быть сериализуемым

Аргумент arg, отправленный через cy.task(name, arg) , должен быть сериализуемым; он не может иметь циклические зависимости (проблема #5539). Если есть какие-либо специальные поля, например, Date, вы несете ответственность за их преобразование (проблема #4980):

// in test
cy.task('date', new Date()).then((s) => {
  // the yielded result is a string
  // we need to convert it to Date object
  const result = new Date(s)
})
// in plugins/index.js
module.exports = (on, config) => {
  on('task', {
    date(s) {
      // s is a string, so convert it to Date
      const d = new Date(s)

      // do something with the date
      // and return it back
      return d
    },
  })
}

Правила

Требования

  • cy.task() требует цепочки вызовов от cy .
  • cy.task() требует, чтобы задача в конечном итоге завершилась.

Утверждения

  • cy.task() будет выполнять утверждения, которые вы прицепили только один раз, и не будет повторно выполнять их.

Таймауты

  • cy.task() может выйти из строя, ожидая завершения задачи.

Журнал команд

Вывод содержимого файла конфигурации cypress.json по умолчанию

cy.task('readJson', 'cypress.json')

Вышеуказанная команда отобразится в журнале команд как:

Command Log task

При нажатии на команду task в журнале команд, консоль выведет следующее:

Console Log task

История

Версия Изменения
3.0.0 Добавлена команда cy.task()

См. также

  • cy.exec()
  • cy.fixture()
  • cy.readFile()
  • cy.request()
  • cy.writeFile()
  • Блог: Крайне мощный cy.task()
  • Блог: Тестирование с подбрасыванием
  • Универсальный тест кода с Cypress
  • репозиторий cypress-db-example демонстрирует, как подключиться к базе данных Sqlite3 и использовать её во время тестов.
  • Блог: Тестирование Mongo с Cypress показывает, как получить доступ к MongoDB во время API-тестов Cypress локально и на CircleCI.

© 2017 Cypress.io
Licensed under the MIT License.
https://docs.cypress.io/api/commands/task

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API