我正尝试通过以下方式访问Cypress中我的应用程序的窗口对象。
cy.url().should('include', '/home').then(async () => {
const window = await cy.window();
console.log(window);
});
上述方法对我不起作用,因为window
返回为undefined
。
不过,this SO post中的答案如下:
或者您可以使用cy.state('window')返回窗口对象 同步进行,但这是未记录的,将来可能会更改。
此方法确实成功返回窗口值。
cy.url().should('include', '/home').then(async () => {
const window = cy.state('window');
console.log(window);
});
正如答案所示,cy.state('window')未记录在案,所以我还是想使用cy.window()。有什么原因会返回未定义? (我今天开始学习柏树。)
答案 0 :(得分:2)
这经常出现。赛普拉斯有一些说明Commands are not Promises的文档。我使用自定义命令进行了写操作,以强制命令链的行为像promise,但是它仍然是实验性的和细微的。
首先,我将逐字逐句地给出您要达到的目标的示例:
cy.url().should('include', '/home').then(() => {
cy.window().then(win => {
console.log(win) // The window of your app, not `window` which is the Cypress window object
})
})
您的示例可以用多种方式编写,但也许稍微解释一下赛普拉斯的工作原理会有所帮助。
赛普拉斯有一个叫做“命令”的东西,可以返回新的“ Chainers”。它是像JQuery这样的易变的语法:
// fill and submit form
cy
.get('#firstname')
.type('Nicholas')
.get('#lastname')
.type('Boll')
.get('#submit')
.click()
您可以(并且应该)将连锁分解为更像句子:
// fill and submit form
cy.get('#firstname').type('Nicholas')
cy.get('#lastname').type('Boll')
cy.get('#submit').click()
您可能已经猜到所有Cypress Chainer命令都是异步的。他们有一个.then
,但实际上不是承诺。赛普拉斯命令实际上已入队。赛普拉斯了解了mocha的生命周期,以确保before
,beforeEach
,it
,afterEach
,after
块等待,直到Cypress命令不再排队,然后再继续。
让我们看看这个例子:
it('should enter the first name', () => {
cy.get('#firstname').type('Nicholas')
})
实际发生的是赛普拉斯看到了cy.get
命令,并在get
命令中加入了参数'#firstname'
。立即(同步)将执行返回测试。然后,赛普拉斯将看到带有参数cy.type
的{{1}}命令,并立即返回测试。由于没有'Nicholas'
回调并且没有返回Promise,因此从技术上来说,该测试已完成。但是赛普拉斯陷入了摩卡咖啡的生命周期,直到排队的命令完成才发布测试。
现在我们有了2个已排队的命令,并且测试正在等待Cypress释放测试,done
命令从队列中弹出。赛普拉斯将尝试在页面上找到ID为get
的元素,直到找到该元素或该元素超时。假设找到了元素,它将设置一个名为firstname
(subject
,但不要依赖它)的状态变量。下一个排队的命令cy.state('subject')
将获取前一个type
,并尝试一次从字符串subject
中键入每个键,默认延迟为50ms,直到完成字符串为止。现在不再有排队的命令,赛普拉斯将释放测试,跑步者将继续进行下一个测试。
这有点简化-赛普拉斯做了很多工作,以确保'Nicholas'
仅在可以获得焦点并且可以交互的元素上运行。
现在,知道了这一点,您可以更简单地编写示例:
.type
答案 1 :(得分:0)
对我来说,the accepted answer 很好,但并没有真正向我展示什么是必要的。
对我来说,一切都是同步的,你可以做这样的事情,真是太棒了
let bg1 = null;
// simply store the value of a global object in the DOM
cy.window().then((win) => {
bg1 = win.myPreciousGlobalObj.color;
});
// Do something that changes a global object
cy.get('a.dropdown-toggle').contains('File').click();
cy.window().then((win) => {
const bg2 = win.myPreciousGlobalObj.color;
// check if nodes and edges are loaded
expect(bg1 != bg2).to.eq(true);
});
这里有趣的是,甚至 then
块内的东西都是同步的。这太有用了。