Cypress 测试:.contains() 是否等同于 should('contain')?

Cypress test: is .contains() equivalent to should('contain')?

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

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

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

后续问题:环顾四周,看看如何最好地使用 select 元素进行端到端测试后,我发现 Cypress docs 建议使用 data-cy 属性。这比仅向标记添加 name 属性更好吗? name 应该只用于表单字段吗?

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

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

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

在第二种形式中,您使用 Chai 链接器 contain.

进行显式断言以验证 dummyPlan 存在于另一个元素中

这是一个细微的差别,结果是一样的,但我建议你使用 cy.get('[name=planSelect]').contains(dummyPlan) 仅当你想在 contains 之后链接一些其他方法时,如果你想使用第二种形式想要明确断言此元素存在。从逻辑上讲,第一个代表一般测试失败(赛普拉斯试图找到一个不存在的元素),第二个代表显式断言失败(元素应该包含 dummyPlan 但它没有)。

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

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

回答

  • .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;
}

如果您需要更高的性能,可以将 TreeWalker 与 NodeFilter.SHOW_TEXT 一起使用,如 chrome extension 我已经研究了很长时间

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

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