在赛普拉斯中何时使用自定义命令与任务?

问题描述:

自定义命令和任务之间有什么区别?我试图了解它们应如何使用。

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

自定义命令文档: https://docs.cypress.io/api/cypress-api/custom-commands.html

任务文档: https://docs.cypress.io/api/commands/ task.html

命令(全局 cy 对象)是一个将操作(排队)到当前正在执行的命令队列中的函数。队列依次执行 (这就是为什么命令的返回值是具有的对象。然后方法的原因- -但尽管如此,并且它的行为像诺言,但它是不是承诺)。在上一个命令完成之前,下一个命令将不会执行。

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 自定义命令 是常规的命令,但由您定义,而不是Cypress 提供的默认命令的盒子。自定义命令对于使您一遍又一遍地在测试中重复的工作流程自动化很有用(例如,将几个默认的 cy 命令分组在一起)。

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

命令用于与您的被测Web应用程序(AUT)进行交互-最值得注意的是与DOM交互(例如,通过 cy.get(selector)来查询DOM)

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.

认识到串行执行命令时,它们会立即排入队列(在同一事件循环中打勾),您传递给它们的任何表达式也很重要。然后在那里进行评估。这不是赛普拉斯特有的行为,只是普通的JavaScript。这就是为什么您不能执行以下操作的原因:

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

也不能使用 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); 




任务是在赛普拉斯后端进程(Node.js),不在浏览器中。


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

要执行任务(您之前在 cypress / plugins / index.js 文件),您首先需要通过 cy.task(任务名称,数据) 。然后,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.

任务返回的数据被序列化(通过 JSON.stringify 或类似的名称)并发送回浏览器,并传递给您可能链接到 cy.task()命令的回调使用 .then(callback)

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

任务主要用于与您自己的服务器后端进行通信,例如播种数据库;或用于I / O,例如读/写文件(尽管赛普拉斯为此提供了命令,例如 cy.exec() cy.writeFile() )。

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.

另一个重要的一点是,在进程(赛普拉斯浏览器进程和赛普拉斯节点进程)之间发送的消息是发送的通过 IPC频道,并且必须可序列化。这意味着您传递给 cy.task(taskName,data)的数据以及从任务本身返回的响应都是字符串。因此,发送包含方法的对象将不起作用(也就是说,该方法将根本不会被转移)。

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