在Cypress中访问window对象的困难

7
我正在尝试以以下方式在Cypress中访问我的App的window对象。
cy.url().should('include', '/home').then(async () => {
    const window = await cy.window();
    console.log(window);
});

对我来说上述方法不起作用,因为window被返回为undefined

然而,这篇SO文章中的答案指出:

或者您可以使用cy.state('window'),该方法会同步返回窗口对象,但是这是未经记录的,将来可能会发生更改。

此方法可以成功返回窗口值。

cy.url().should('include', '/home').then(async () => {
    const window = cy.state('window');
    console.log(window);
});

正如答案所建议的那样,cy.state('window')是未记录在案的,所以我仍然更愿意使用cy.window()。有没有什么原因它返回 undefined?(我今天开始学习cypress。)

2个回答

18

这是一个经常出现的问题。Cypress有一些文档说明命令不是Promise。我写了一篇文章,使用自定义命令来强制将命令链行为像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
  })
})
您的示例可以用几种方式编写,但是或许解释一下Cypress的工作原理会更有帮助。Cypress有一些称为“命令”的东西,它们返回新的“链式调用器”。 它是像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,但实际上它们并不是promise。Cypress命令实际上是入队的。Cypress钩子进入mocha的生命周期,确保beforebeforeEachitafterEachafter块在继续之前等待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')

// No need for `.then` chaining or async/await. This is an enqueued command
cy.window().then(win => {
  console.log(win)
})

-1

对我来说,被接受的答案 是好的,但并没有真正展示给我必要的东西。

对我来说,最棒的是一切都是同步的,你可以做像这样的事情


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块内部的事情也是同步的。这非常有用。


这不是真正正确的,它可能看起来同步是因为它很快 - 但是如果你在测试末尾以及回调函数内部放置 console.log(),你会发现回调函数(和Cypress命令)在测试代码完成后执行。如果你真的想让它同步,使用 const win = cy.state('window') - Richard Matsen
嗯,你可能是对的,我应该尝试更新我的答案。谢谢。 - canbax
非常奇怪。如果我使用 cy.log,似乎一切都是同步的,但如果我使用 console.log,事情就不像你说的那样同步。 - canbax

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接