【问题标题】:Cypress test: is .contains() equivalent to should('contain')?赛普拉斯测试:.contains() 是否等同于 should('contain')?
【发布时间】:2018-04-26 12:10:38
【问题描述】:

这是:cy.get('[name=planSelect]').contains(dummyPlan)

相当于这个:cy.get('[name=planSelect]').should('contain', dummyPlan)

如果是这样,哪个是首选?第一个更像是一个隐含的断言,但在我看来它更短更清晰。

后续问题: 在查看了如何最好地选择 e2e 测试的元素后,我发现 Cypress docs 建议使用 data-cy 属性。有没有理由比仅仅在标记中添加name 属性更好? name 应该只用于表单字段吗?

【问题讨论】:

  • 我建议在 get 之后使用 contains 然后使用 should cy.get('[name=planSelect]').contains(dummyPlan, {matchCase: false}).should('exist') 验证存在

标签: e2e-testing cypress


【解决方案1】:

如果带有name=planSelect 的元素不包含dummyPlan,则cypress 测试的结果将相同,即此时测试将失败。

它们之间的区别在于,在第一种形式中,使用contains(),您实际上是在尝试选择一个元素,而 cy.get(...).contains() 的结果将产生这个预期的 DOM元素,允许进一步链接方法,例如:

cy.get('[name=planSelect]').contains(dummyPlan).click();

在第二种形式中,您使用 Chai 链接器 contain 进行显式断言以验证 dummyPlan 存在于另一个元素中。

这是一个微妙的区别,结果是一样的,但我建议你使用cy.get('[name=planSelect]').contains(dummyPlan),仅在你想在包含后链接其他方法的情况下使用,如果你想显式断言,请使用第二种形式这个元素存在。从逻辑上讲,第一个表示一般测试失败(cypress 试图找到一个不存在的元素),第二个表示显式断言失败(元素应该包含 dummyPlan,但它没有)。

至于您的第二个问题,name 是一个有效的 HTML 属性,如果在其原始功能中使用该属性(命名输入字段)或该属性仅存在于您的测试中,则可能会导致混淆用于测试目的。我建议您按照文档的建议使用cy-name,因为这样可以避免这种歧义,并清楚地表明此属性cy-name 仅用于测试目的。

此外,在某些情况下,您可能决定在将代码发送到生产之前从代码中删除所有 cy-name(在构建过程中,使用一些 webpack 插件,例如 string-replace-loader)。如果仅使用 name,您将无法执行相同操作,因为如果您的代码中有一些输入,您还将删除所需的输入 name

【讨论】:

  • 很好的答案,谢谢!我明白你关于通用失败与显式失败的意思,并同意你的看法,所以感谢你帮助澄清这一点!
  • Cypress 实际上 advises 使用数据元素来定位元素 data-cy="someName"
【解决方案2】:

回答

  • .contains(selector, content) 是最好的选择器;它重试 元素选择 AND 允许文本匹配(不仅仅是<tag> .class#id[attributes])

  • .should() 只是一个断言,只重试断言 (不是元素选择)

.should('exist') 是隐含的,除非您指定自己的 - 这就是他们允许 .should('not.exist') 的方式


切线

浏览器支持 XPath 1.0,这是一种基于 DOM 树遍历进行复杂查询的非常酷但晦涩的方法。有一个contains 谓词函数:

//*[         contains(normalize-space(.), 'The quick brown fox jumped over the lazy dog.') ]
   [not(.//*[contains(normalize-space(.), 'The quick brown fox jumped over the lazy dog.') ])]

这会从文档的根目录中搜索包含文本但不包含包含文本的后代节点的任何节点。

您可以在控制台中使用 Chrome $x() 快捷方式或这个 polyfill(和助手)对其进行测试:

getLowestDomNodesByText("The quick brown fox jumped over the lazy dog.")

function getLowestDomNodesByText (text) {
  return x(`//*[contains(normalize-space(.), '${text}')][not(.//*[contains(normalize-space(.), '${text}') ])]`);
};

function x (expression) {
  const results = new XPathEvaluator().evaluate(expression, document);

  const nodes = [];
  let node = null;
  while (node = results.iterateNext()) {
    nodes.push(node);
  }

  return nodes;
}

如果您需要更高的性能,您可以使用带有 NodeFilter.SHOW_TEXT 的 TreeWalker,正如我已经研究了很长时间的 chrome extension 中所看到的那样

【讨论】:

    【解决方案3】:

    我建议在 get 之后使用 contains,然后使用 should 验证存在。

    cy.get('[name=planSelect]').contains(dummyPlan, {matchCase: false}).should('exist')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-14
      • 2018-08-01
      • 2021-10-20
      • 2020-05-16
      相关资源
      最近更新 更多