【问题标题】:In Cypress when to use Custom Command vs Task?在赛普拉斯中,何时使用自定义命令与任务?
【发布时间】:2019-11-03 13:44:09
【问题描述】:

自定义命令和任务有什么区别?我正在尝试了解它们应该如何使用。

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

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

【问题讨论】:

  • 赛普拉斯 gitter.im 的某个人回答了这个问题,我发现它很有帮助:“您不能在赛普拉斯上下文中运行任何类型的节点相关操作。因为您的所有代码都被捆绑并发送到赛普拉斯实例。例如 console.log() 的节点命令将不会在您的测试或页面对象中运行。假设您要清理 mongo 数据库表,因此您将在插件中使用 index.js 中的 Cypress 任务。来到命令,它就像创建您想要创建的自定义方法,您可以在 Commands.js 文件中进行。”
  • 一个经验法则可能是:这段代码可以进入beforebeforeEach 回调吗?如果是,那么它是一个自定义命令。例如,任务不能调用现有的cy 命令(比如使用cy.setCookie 设置cookie),而自定义命令可以。

标签: cypress


【解决方案1】:

command(全局cy 对象上的大多数方法)是一个函数,它将一个动作排入(推​​送)到当前正在执行的命令队列中。队列执行串行异步(这就是为什么命令的返回值是一个具有.then方法的对象——但尽管如此,而且它的行为就像promise ,它是not a promise)。在上一个命令完成之前,下一个命令不会执行。

命令直接在浏览器中定义和执行。

custom command 是常规命令,但由您定义,而不是赛普拉斯 supplies out of the box 的默认命令。自定义命令对于自动化您在测试中一遍又一遍地重复的工作流程很有用(例如,通过将几个默认的 cy 命令组合在一起)。

命令用于与您的被测网络应用 (AUT) 进行交互 --- 最显着的是与 DOM(例如,通过 cy.get(selector) 查询 DOM)并进行断言。

同样重要的是要意识到,虽然命令是串行执行的,但它们会立即入队(在同一个事件循环滴答中),并且您传递给它们的任何表达式都会在当时和那里进行评估。这不是赛普拉斯特有的行为,只是普通的 JavaScript。这就是为什么你不能做这样的事情:

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

任务是在 Cypress 后端进程 (Node.js) 上定义和执行的函数,而不是在浏览器中。

要执行一个任务(您之前在cypress/plugins/index.js 文件中定义),您需要首先通过cy.task(taskName, data) 将其作为常规命令加入到您的测试中。然后赛普拉斯(当命令轮到执行时)向执行任务的后端进程发送一条消息。

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

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

没有默认任务 --- 您执行的每个任务首先需要定义自己。

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

【讨论】:

  • 在其他全面的 cypress 文档中似乎完全没有很好的解释。
  • 很棒的解释。在阅读了您的解释后,我查看了 cypress 文档,发现现在非常容易理解。在我的情况下,命令功能一直在使用,但我想现在,我可以使用命令基本上将一组类似的命令分组,这些命令用于在功能上执行功能,而不是在每个测试文件中冗余地编写执行步骤
  • @Emjey From docs.cypress.io/api/cypress-api/… 当您需要描述所有测试中需要的行为时,自定义命令效果很好。为可重复的行为编写 JavaScript/typescript 函数通常更有效
  • 请注意,也可以使用 cy.exec() 运行任意命令,例如播种数据库。这也可以在命令中使用。对于简单的一次性命令,有时可能比定义任务更简单。
【解决方案2】:

很好的答案,但总而言之,这里有两个主要区别可帮助您选择是否需要赛普拉斯命令或任务:

  • 如果您需要运行 Promise 或与后端交互,请执行任务。
  • 如果您正在与 DOM 交互并进行断言,请使用命令。

取自this article

【讨论】:

    【解决方案3】:

    Cypress 命令,通常不返回承诺。文档将它们称为“thenable”,它只是意味着结果只能通过 .then(result=>{}) 构造获得。

    这就是为什么上面的评论是正确的。 (此处显示供参考)

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

    但是,有一种封装 cypress 命令的本地方式来获得真正的 async/await 行为,如下所示:

        function getAsync(query, cb) {
          let prom = new Promise<any[]>((resolve, reject) => {
            cy.get(query).then((elements) => {
              let objArray = [];
              if (elements === undefined) {
                reject();
              }
              elements.each((index) => {
                let element = elements[index];
                let obj = cb(element);
                objArray.push(obj);
              });
              resolve(objArray);
            });
          });
          return prom;
        }
    

    调用上面的这个函数:

      it('Gets specific DOM Elements', async () => {
        let data = await getAsync('form', getForm); 
      ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-05
      • 2021-03-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多