赛普拉斯中的别名(`.as`)是什么?
What are aliases (`.as`) in cypress?
我有以下代码:
cy.get('input:checkbox').first().as('firstCheckbox').then(() => {
cy.get('@firstCheckbox').should('be.checked').click()
cy.get('.globalMessage-display > :nth-child(1) > .alert').should('be.visible')
cy.get('.globalMessage-display > :nth-child(1) > .alert').should('not.exist')
cy.get('@firstCheckbox').should('not.be.checked').click()
cy.get('.globalMessage-display > :nth-child(1) > .alert').should('be.visible')
cy.get('.globalMessage-display > :nth-child(1) > .alert').should('not.exist')
cy.get('@firstCheckbox').should('be.checked')
})
在 cy.get('@firstCheckbox').should('be.checked').click()
之后,复选框被移动到最后一个索引位置而不是第一个。
根据我对别名的理解,这应该无关紧要,因为我用 ('@')
引用它并且它在哪个位置并不重要。不幸的是,下一个 cy.get('@firstCheckbox')
访问了新的第一个元素,而不是我最初引用的那个。我也无法从文档中弄清楚。
哪里出错了?
https://docs.cypress.io/guides/core-concepts/variables-and-aliases
https://docs.cypress.io/api/commands/as
@agoff 更新:
您的代码似乎可以更好地工作,但我注意到新代码存在一个新问题。
如果取消选中该复选框,则 class 会重新加载 js,导致它从 dom 中短暂消失。之后它再也找不到它并且测试中止。
我也尝试过重新加载,但它再也找不到该元素了。如何处理?
选中的复选框 class 的名称为 custom-control-input ng-untouched ng-pristine ng-valid
。在取消选中 class 名称更改为 custom-control-input.ng-untouched.ng-valid.ng-dirty
一秒钟后,元素被删除并重新加载到 DOM 并使用 class 名称 custom-control-input ng-untouched ng-pristine ng-valid
。问题在于第二个 cy.wrap($el)
试图找到元素 custom-control-input.ng-untouched.ng-valid.ng-dirty
尽管搜索并找到了带有 class custom-control-input ng-untouched ng-pristine ng-valid
的初始元素。那是我不明白的另一件事。
我认为您在混淆和滥用别名。当您使用 .then()
时,您已经生成了找到的元素。因此,您可以直接引用该对象(在包装它之后),而不是使用别名。我相信这样的事情应该可以解决您的问题...
cy.get('input:checkbox').then(($el) => {
cy.wrap($el).should('be.checked').click()
.and('not.be.checked').click()
.and('be.checked')
})
如果在点击事件期间应用程序删除输入并在末尾附加一个新输入,就会发生这种情况。那么你的别名是无效的,因为它指向的元素不再在 DOM.
如果我移动点击处理程序中的元素,您的代码就可以工作。
如果我克隆点击处理程序中的元素,您的代码将失败。
怎么办?
点击后刷新您的别名()
cy.get('input:checkbox').first().as('myCheckbox').then(() => {
cy.get('@myCheckbox').should('be.checked').click()
.then(() => cy.get('input:checkbox').last().as('myCheckbox')) // it's last now!
cy.get('.globalMessage-display > :nth-child(1) > .alert').should('be.visible')
cy.get('.globalMessage-display > :nth-child(1) > .alert').should('not.exist')
cy.get('@myCheckbox').should('not.be.checked').click()
.then(() => cy.get('input:checkbox').last().as('myCheckbox'))
cy.get('.globalMessage-display > :nth-child(1) > .alert').should('be.visible')
cy.get('.globalMessage-display > :nth-child(1) > .alert').should('not.exist')
cy.get('@myCheckbox').should('be.checked')
})
alias 命令还有另一个技巧。
如果元素被克隆和替换,原始元素将与DOM分离。
cy.get('@alias')
检测分离元素并重播原始命令以自动刷新。
它不适用于 .first()
,因为元素改变了位置。
但是如果您使用 data-cy
属性而不是 .first()
,您的代码将起作用。
cy.get('input:checkbox[data-cy="first-checkbox"]')
.as('myCheckbox').then(() => {
cy.get('@myCheckbox')
.should('be.checked').click() // cloned and moved to another position
...
cy.get('@myCheckbox') // detached by previous click
.should('not.be.checked').click() // so alias replays original get
// with [data-cy="first-checkbox"]
...
cy.get('@myCheckbox').should('be.checked') // as above
})
这是执行此操作的赛普拉斯代码
let { subject, alias, command } = aliasObj
const resolveAlias = () => {
if ($dom.isElement(subject)) { // if this is a DOM element
const replay = () => {
cy.replayCommandsFrom(command)
return undefined
}
if ($dom.isDetached(subject)) { // is it detached?
subject = subject.filter((index, el) => $dom.isAttached(el)) // all detached?
if (!subject.length) {
return replay() // perform the replay
}
}
我有以下代码:
cy.get('input:checkbox').first().as('firstCheckbox').then(() => {
cy.get('@firstCheckbox').should('be.checked').click()
cy.get('.globalMessage-display > :nth-child(1) > .alert').should('be.visible')
cy.get('.globalMessage-display > :nth-child(1) > .alert').should('not.exist')
cy.get('@firstCheckbox').should('not.be.checked').click()
cy.get('.globalMessage-display > :nth-child(1) > .alert').should('be.visible')
cy.get('.globalMessage-display > :nth-child(1) > .alert').should('not.exist')
cy.get('@firstCheckbox').should('be.checked')
})
在 cy.get('@firstCheckbox').should('be.checked').click()
之后,复选框被移动到最后一个索引位置而不是第一个。
根据我对别名的理解,这应该无关紧要,因为我用 ('@')
引用它并且它在哪个位置并不重要。不幸的是,下一个 cy.get('@firstCheckbox')
访问了新的第一个元素,而不是我最初引用的那个。我也无法从文档中弄清楚。
哪里出错了?
https://docs.cypress.io/guides/core-concepts/variables-and-aliases
https://docs.cypress.io/api/commands/as
@agoff 更新:
您的代码似乎可以更好地工作,但我注意到新代码存在一个新问题。 如果取消选中该复选框,则 class 会重新加载 js,导致它从 dom 中短暂消失。之后它再也找不到它并且测试中止。 我也尝试过重新加载,但它再也找不到该元素了。如何处理?
选中的复选框 class 的名称为 custom-control-input ng-untouched ng-pristine ng-valid
。在取消选中 class 名称更改为 custom-control-input.ng-untouched.ng-valid.ng-dirty
一秒钟后,元素被删除并重新加载到 DOM 并使用 class 名称 custom-control-input ng-untouched ng-pristine ng-valid
。问题在于第二个 cy.wrap($el)
试图找到元素 custom-control-input.ng-untouched.ng-valid.ng-dirty
尽管搜索并找到了带有 class custom-control-input ng-untouched ng-pristine ng-valid
的初始元素。那是我不明白的另一件事。
我认为您在混淆和滥用别名。当您使用 .then()
时,您已经生成了找到的元素。因此,您可以直接引用该对象(在包装它之后),而不是使用别名。我相信这样的事情应该可以解决您的问题...
cy.get('input:checkbox').then(($el) => {
cy.wrap($el).should('be.checked').click()
.and('not.be.checked').click()
.and('be.checked')
})
如果在点击事件期间应用程序删除输入并在末尾附加一个新输入,就会发生这种情况。那么你的别名是无效的,因为它指向的元素不再在 DOM.
如果我移动点击处理程序中的元素,您的代码就可以工作。
如果我克隆点击处理程序中的元素,您的代码将失败。
怎么办?
点击后刷新您的别名()
cy.get('input:checkbox').first().as('myCheckbox').then(() => {
cy.get('@myCheckbox').should('be.checked').click()
.then(() => cy.get('input:checkbox').last().as('myCheckbox')) // it's last now!
cy.get('.globalMessage-display > :nth-child(1) > .alert').should('be.visible')
cy.get('.globalMessage-display > :nth-child(1) > .alert').should('not.exist')
cy.get('@myCheckbox').should('not.be.checked').click()
.then(() => cy.get('input:checkbox').last().as('myCheckbox'))
cy.get('.globalMessage-display > :nth-child(1) > .alert').should('be.visible')
cy.get('.globalMessage-display > :nth-child(1) > .alert').should('not.exist')
cy.get('@myCheckbox').should('be.checked')
})
alias 命令还有另一个技巧。
如果元素被克隆和替换,原始元素将与DOM分离。
cy.get('@alias')
检测分离元素并重播原始命令以自动刷新。
它不适用于 .first()
,因为元素改变了位置。
但是如果您使用 data-cy
属性而不是 .first()
,您的代码将起作用。
cy.get('input:checkbox[data-cy="first-checkbox"]')
.as('myCheckbox').then(() => {
cy.get('@myCheckbox')
.should('be.checked').click() // cloned and moved to another position
...
cy.get('@myCheckbox') // detached by previous click
.should('not.be.checked').click() // so alias replays original get
// with [data-cy="first-checkbox"]
...
cy.get('@myCheckbox').should('be.checked') // as above
})
这是执行此操作的赛普拉斯代码
let { subject, alias, command } = aliasObj
const resolveAlias = () => {
if ($dom.isElement(subject)) { // if this is a DOM element
const replay = () => {
cy.replayCommandsFrom(command)
return undefined
}
if ($dom.isDetached(subject)) { // is it detached?
subject = subject.filter((index, el) => $dom.isAttached(el)) // all detached?
if (!subject.length) {
return replay() // perform the replay
}
}