这是一个经常出现的问题。Cypress有一些文档说明命令不是Promise。我写了一篇文章,使用自定义命令来强制将命令链行为像Promise一样,但这仍然是实验性和微妙的。
首先,我会几乎逐字地给出你要完成的示例:
cy.url().should('include', '/home').then(() => {
cy.window().then(win => {
console.log(win)
})
})
您的示例可以用几种方式编写,但是或许解释一下Cypress的工作原理会更有帮助。Cypress有一些称为“命令”的东西,它们返回新的“链式调用器”。 它是像JQuery一样流畅的语法。
cy
.get('#firstname')
.type('Nicholas')
.get('#lastname')
.type('Boll')
.get('#submit')
.click()
你可以(而且应该)把链条断开,使其更像句子:
cy.get('#firstname').type('Nicholas')
cy.get('#lastname').type('Boll')
cy.get('#submit').click()
你可能已经猜到了,所有的Cypress Chainer命令都是异步的。它们有一个.then
,但实际上它们并不是promise。Cypress命令实际上是入队的。Cypress钩子进入mocha的生命周期,确保before
、beforeEach
、it
、afterEach
、after
块在继续之前等待Cypress命令不再入队。
让我们看这个例子:
it('should enter the first name', () => {
cy.get('#firstname').type('Nicholas')
})
Cypress在看到
cy.get
命令时会将参数
'#firstname'
与
get
命令一起排队。这会立即(同步地)将执行返回给测试。然后,Cypress看到带有参数
'Nicholas'
的
cy.type
命令并立即返回到测试。此时测试已经完成,因为没有
done
回调和没有Promise被返回。但是Cypress挂钩到mocha的生命周期中,并且在入队的命令完成之前不释放测试。
现在,我们有2个入队的命令,并且测试正在等待Cypress释放测试,get
命令从队列中弹出。 Cypress将尝试查找具有id为firstname
的元素,直到找到它或超时。假设它找到了该元素,它将设置一个名为subject
的状态变量(cy.state('subject')
,但不要依赖它)。下一个入队的命令type
将获取先前的subject
并尝试逐个输入字符串'Nicholas'
中的每个键,每个键默认延迟50ms,直到完成整个字符串。现在没有更多的入队命令,Cypress释放测试并允许运行器继续进行下一个测试。
这有点简化了 - Cypress会做很多工作,以确保.type
仅在可以获得焦点且可交互的元素上运行等等。
现在,了解了这些知识,您可以更简单地编写示例:
cy.url().should('include', '/home')
cy.window().then(win => {
console.log(win)
})
console.log()
,你会发现回调函数(和Cypress命令)在测试代码完成后执行。如果你真的想让它同步,使用const win = cy.state('window')
。 - Richard Matsency.log
,似乎一切都是同步的,但如果我使用console.log
,事情就不像你说的那样同步。 - canbax