Cypress如何执行命令
【摘要】 当cypress脚本执行的时候,发生了什么?非常重要,所以原样摘录官方文档https://docs.cypress.io/guides/core-concepts/introduction-to-cypress#Commands-Are-AsynchronousCypress commands don’t do anything at the moment they are invoked,...
当cypress脚本执行的时候,发生了什么?
非常重要,所以原样摘录官方文档
https://docs.cypress.io/guides/core-concepts/introduction-to-cypress#Commands-Are-Asynchronous
Cypress commands don’t do anything at the moment they are invoked
, but rather enqueue themselves to be run
later.
This is what we mean when we say Cypress commands are asynchronous.
it('hides the thing when it is clicked', () => {
cy.visit('/my/resource/path') // Nothing happens yet
cy.get(".hides-when-clicked") // Still nothing happening
.should("be.visible") // Still absolutely nothing
.click() // Nope, nothing
cy.get('.hides-when-clicked') // Still nothing happening
.should('not.be.visible') // Definitely nothing happening yet
})
// Ok, the test function has finished executing...
// We've queued all of these commands and now
// Cypress will begin running them in order!
Cypress doesn’t kick off the browser automation until the test function exits.
但是,以上说的都是Cypress的命令,如果是其他的语句,比如算术运算、赋值运算,则是马上执行的。
所以,下面就要说到,这种混合的情况
it('does not work as we expect', () => {
cy.visit('/my/resource/path') // Nothing happens yet
cy.get('.awesome-selector') // Still nothing happening
.click() // Nope, nothing
// Cypress.$ is synchronous, so evaluates immediately
// there is no element to find yet cause cy.visit() was only queued to visit
// and did not actually visit the application
let el = Cypress.$('.new-el') // evaluates immediately as []
if (el.length) { // evaluates immediately as 0
cy.get('.another-selector')
} else {// this will always run
cy.get('.optional-selector')
}
})
下面是正确的版本
it('does not work as we expect', () => {
cy.visit('/my/resource/path') // Nothing happens yet
cy.get('.awesome-selector') // Still nothing happening
.click() // Nope, nothing
.then(() => {
// placing this code inside the .then() ensures
// it runs after the cypress commands 'execute'
let el = Cypress.$('.new-el') // evaluates after .then()
if (el.length) {
cy.get('.another-selector')
} else {
cy.get('.optional-selector')
}
})
})
再来一个例子:
it('test', () => {
let username = undefined // evaluates immediately as undefined
cy.visit('https://app.com') // Nothing happens yet
cy.get('.user-name') // Still, nothing happens yet
.then(($el) => {
// Nothing happens yet
username = $el.text()
})
if (username) {// evaluates immediately as undefined
cy.contains(username).click()
} else {// this will always run
cy.contains('My Profile').click()
}
})
修改为:
it('test', () => {
let username = undefined // evaluates immediately as undefined
cy.visit('https://app.com') // Nothing happens yet
cy.get('.user-name') // Still, nothing happens yet
.then(($el) => {
username = $el.text()
if (username) {
cy.contains(username).click()
} else {
cy.get('My Profile').click()
}
})
})
总结:
简单的说,将获取返回、和使用返回的语句,一同放到then()的回调函数里,就可以了。
You purposefully cannot do anything useful with the return value from a command. Commands are enqueued and managed entirely behind the scenes.
We’ve designed our API this way because the DOM is a highly mutable object that constantly goes stale. For Cypress to prevent flake, and know when to proceed, we manage commands in a highly controlled deterministic way.
之所以这样设计API,是因为DOM是一个高度可变的对象,经常会过时。为了Cypress防止碎片,并知道何时继续,我们以高度受控的确定性方式管理命令。
Cypress的api构建方式与您可能习惯的非常不同: 这些设计模式是有意为之的。意图见上一条。
下面说一下循环的坑
需求是某个页面是刷随机数字的,当刷出的是7时结束,否则刷下一个数字
let found7 = false
while (!found7) {
// this schedules an infinite number of "cy.get..." commands, eventually crashing
// before any of them have a chance to run and set found7 to true
cy.get('#result')
.should('not.be.empty')
.invoke('text')
.then(parseInt)
.then((number) => {
if (number === 7) {
found7 = true
cy.log('lucky **7**')
} else {
cy.reload()
}
})
}
有了前面的知识,就知道上面是一个死循环。cy.get()在不断的加入命令队列中,但是没有机会执行。
keeps adding more cy.get(’#result’) commands to the test chain without executing any!
下面是正确的版本:
const checkAndReload = () => {
// get the element's text, convert into a number
cy.get('#result')
.should('not.be.empty')
.invoke('text')
.then(parseInt)
.then((number) => {
// if the expected number is found
// stop adding any more commands
if (number === 7) {
cy.log('lucky **7**')
return
}
// otherwise insert more Cypress commands
// by calling the function after reload
cy.wait(500, { log: false })
cy.reload()
checkAndReload()
})
}
cy.visit('public/index.html')
checkAndReload()
然而不得不说,虽然结果正确了,但是事情比之前变的复杂了。
最后说一下每个cypress的命令,都自带保证机制
(通过重试、等待)
After a test function is finished running, Cypress goes to work executing the commands that were enqueued using the cy.* command
chains.
Any waiting or retrying that is necessary to ensure a step/command was successful must complete before the next step begins. If they don’t complete successfully before the timeout is reached, the test will fail.
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)