赛普拉斯:如何从自定义命令中获取返回值? (柏树承诺)

Posted

技术标签:

【中文标题】赛普拉斯:如何从自定义命令中获取返回值? (柏树承诺)【英文标题】:Cypress : How to get returned value from custom commands ? (Cypress-promise) 【发布时间】:2019-09-14 18:54:25 【问题描述】:

我正在寻找一种方法来取回自定义赛普拉斯命令返回的返回值。

我目前正在使用 Cypress 和 Cypress-promise lib (https://www.npmjs.com/package/cypress-promise)

目前,结果是: 日志 1=车 1 log2=null

我的错误在哪里?

测试文件:

it('Test 1', async function() 
     const carName = await promisify(cy.set_typeCarName());
     cy.log("log2 = " + carName );
);

模块:

set_typeCarName() 
     let carName = "CAR 1";
     cy.get('#newSiteCityInput').type(carName);
     cy.log("log1 = " + carName);
     return carName;
;

Cypress.Commands.add('set_typeCarName',() => 
    webnewsite.set_typeCarName();
);

【问题讨论】:

你解决了吗?请您与我们分享解决方案吗? @wawanopoulos,如果你觉得可以的话,你能把它标记为已解决吗? 【参考方案1】:

该命令是否缺少return 语句?

Cypress.Commands.add('set_typeCarName',() => 
  return webnewsite.set_typeCarName(); // I added the initial `return`
);

【讨论】:

不工作了,赛普拉斯不返回自定义命令的结果。并在自定义命令中使用 return 时抛出警告。【参考方案2】:

我想这就是你想要的:

测试文件

            cy.set_typeCarName()
                .then((returned_value) => 
                    cy.log("log2 = " + returned_value)
                )
            );

模块

    Cypress.Commands.add('set_typeCarName',() => 
            let carName = "CAR 1";
            cy.get('#newSiteCityInput').type(carName);
            cy.log("log1 = " + carName);
            return carName;
    );

【讨论】:

这似乎是更正确的答案。无需按照@8888 的建议包装返回值。它可能已经被 Cypress 自动包装了。 这将抛出CypressError: Cypress detected that you invoked one or more cy commands in a custom command but returned a different value.。使用换行,或在then() 中返回,根据您的命令逻辑 在这里强烈反对@Kuranes。正如@Artur 所说,它需要被包装。赛普拉斯错误解释说它曾经在早期版本中自动包装,但现在不再是:In previous versions of Cypress we automatically detected this and forced the cy commands to be returned. To make things less magical and clearer, we are now throwing an error. 感谢您的更新!我无法删除我的赞成票,但我也会赞成@8888 的回答。为过时的信息道歉。【参考方案3】:

为此,我使用wrap() 返回一个包含我想要返回的值的Chainable

模块

function foo() 
  return cy.wrap('foo');


Cypress.Commands.add('foo', foo);

测试文件

cy.foo().then(value => console.log(value)); // foo

由于wrap() 返回一个Cypress.Chainable,我们可以在我们的命令上调用.then()。传递给 wrap() 的任何内容都将交给下一个命令。

另请参阅:Cypress wrap() documentation

【讨论】:

cypress 改造 javascript 的方式令人作呕。【参考方案4】:

赛普拉斯引入了一种编写代码而不是返回值的新方法,即使用别名。 https://docs.cypress.io/guides/core-concepts/variables-and-aliases.html#Closures

正常的写代码方式

async function compute()
const value = await (asynchronous function);
return value;


const x = await compute(); // #a
console.log(x);            // #b

如何在 Cypress 中执行此操作,因为我们不能在 cypress 中使用 async/await

function() compute
  cy.get('p#text').then(p => 
    const text = p.textContent;
    cy.wrap(text).as('pText');
    //even if we return text from here, it will not be accessible anywhere

  );


compute();    // #a
cy.get('@pText').then(text => 
  console.log(text);  // #b

关键是为该值设置别名,然后在下一个命令中使用它因为赛普拉斯首先运行整个代码并将命令放入队列一次代码在队列中,队列中的下一条命令只有在当前命令的所有回调完成后才会运行,因此我们可以使用上面的代码模式。

【讨论】:

我喜欢这个解决方案解决异步处理问题。我在实现中使用了命令,但发现我仍然需要一些别名处理,所以我从 then 获取一些东西,并通过同一命令中的别名返回变异版本【参考方案5】:

如何使用返回值的一个例子 注意:此方法采用一个数值,例如 3445.55 并将其设为 3,445.55

Commands.js中的方法

Cypress.Commands.add('getValueWithComma', (num) => 
      const n = String(num),
        p = n.indexOf('.');
      return n.replace(/\d(?=(?:\d3)+(?:\.|$))/g, (m, i) =>
        p < 0 || i < p ? `$m,` : m,
      );
    );

如何在.spec文件中调用

 cy.getValueWithComma(pass_value).then((returned_value) => 
              cy.log(' Returned value is   = ', returned_value);
            );

【讨论】:

不工作了,赛普拉斯不返回自定义命令的结果。并在自定义命令中使用 return 时抛出警告。【参考方案6】:

使用您的代码回答

Cypress.Commands.add('set_typeCarName',() => 
    return cy.wrap(webnewsite.set_typeCarName()); //return the wrap and use in chain
);

function set_typeCarName() 
 let carName = "CAR 1";
 cy.get('#newSiteCityInput').type(carName);
 cy.log("log1 = " + carName);
 return carName;
;

测试

it('Test 1', async function() 
     cy.set_typeCarName().then(carName => 
         cy.log("log2 = " + carName );
     
);
     

【讨论】:

【参考方案7】:

PLS 记住 cy 命令不是 Promise。您不能自信地使用async/await 并期望它们在cy 命令中正常工作。您可以将Promiseawait 关键字一起使用。并在 w3schools 上查找更多信息:https://www.w3schools.com/js/js_promise.asp,这对我有很大帮助

以下最终在柏树为我工作
// bidderCreationRequest was declared earlier

function createBidderObject() 
  const bidderJson = ;
  await new Promise((generateBidderObject) => 
    cy.request(bidderCreationRequest).then((bidderCreationResp) => 
      bidderJson.id = bidderDMCreationResp.body.id;

      generateBidderObject(bidderJson);
    );
  );

  return bidderJson.id


createBidderObject(); // returns the id of the recently created bidder instead of undefined/null

你也可以使用https://github.com/NicholasBoll/cypress-promise#readme,因为cy命令又不是Promises。因此,如果您使用 async/await 并使用本机 Promise 函数或提到的插件,那么您会很幸运

【讨论】:

以上是关于赛普拉斯:如何从自定义命令中获取返回值? (柏树承诺)的主要内容,如果未能解决你的问题,请参考以下文章

赛普拉斯自定义命令无法识别

如何在赛普拉斯中选择一个数组?

如何从导航器设置状态或调度操作(例如:柏树测试)

未捕获的错误:useNavigate() 只能在赛普拉斯单元测试用例中的 <Router> 组件的上下文中使用

如何查看赛普拉斯测试使用的属性值?

赛普拉斯:我们如何在赛普拉斯中使用不记名令牌编写 GET 请求?