最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Difficulty accessing window object in Cypress - Stack Overflow

programmeradmin0浏览0评论

I'm trying to access the window object of my App in Cypress in the following manner.

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

The above method is not working for me as window is returned as undefined.

However, the answer in this SO post states the following:

Or you can use cy.state('window') which returns the window object synchronously, but this is undocumented and may change in the future.

This method does return the window value successfully.

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

As the answer suggests, cy.state('window') is undocumented so I would still rather use cy.window(). Is there any reason why it's returning undefined? (I started learning cypress today.)

I'm trying to access the window object of my App in Cypress in the following manner.

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

The above method is not working for me as window is returned as undefined.

However, the answer in this SO post states the following:

Or you can use cy.state('window') which returns the window object synchronously, but this is undocumented and may change in the future.

This method does return the window value successfully.

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

As the answer suggests, cy.state('window') is undocumented so I would still rather use cy.window(). Is there any reason why it's returning undefined? (I started learning cypress today.)

Share Improve this question edited Apr 10, 2021 at 3:55 Richard Matsen 23.5k3 gold badges55 silver badges84 bronze badges asked Oct 30, 2018 at 4:56 ptkptk 7,63317 gold badges53 silver badges106 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 18

This comes up frequently. Cypress has some documentation stating Commands are not Promises. I did a write up using a custom command to force a Command Chain to behave like a promise, but it is still experimental and nuanced.

First I'll give your example almost verbatim to what you're trying to accomplish:

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
  })
})

Your example could be written a number of ways, but maybe explaining a bit how Cypress works will help more.

Cypress has something called "Commands" that return new "Chainers". It is fluid syntax like JQuery:

// fill and submit form
cy
  .get('#firstname')
  .type('Nicholas')
  .get('#lastname')
  .type('Boll')
  .get('#submit')
  .click()

You can (and should) break up chains to be more like sentences:

// fill and submit form
cy.get('#firstname').type('Nicholas')
cy.get('#lastname').type('Boll')
cy.get('#submit').click()

You might have guessed that all Cypress Chainer commands are asynchronous. They have a .then, but they aren't actually promises. Cypress commands actually enqueue. Cypress hooks into mocha's lifecycle to make sure a before, beforeEach, it, afterEach, after block waits until Cypress commands are no longer enqueued before continuing.

Let's look at this example:

it('should enter the first name', () => {
  cy.get('#firstname').type('Nicholas')
})

What actually happens is Cypress sees the cy.get Command and enqueues the get command with the argument '#firstname'. This immediately (synchronously) returns execution to the test. Cypress then sees the cy.type command with the argument 'Nicholas' and returns immediately to the test. The test is technically done at this point since there is no done callback and no Promise was returned. But Cypress hooks into the lifecycle of mocha and doesn't release the test until enqueued commands are completed.

Now that we have 2 enqueued commands and the test is waiting for Cypress to release the test, the get command is popped off the queue. Cypress will try to find an element on the page with an id of firstname until it finds it or times out. Assuming it finds the element, it will set a state variable called subject (cy.state('subject'), but don't rely on that). The next enqueued command type will grab the previous subject and attempt to type each key from the string 'Nicholas' one at a time with a default delay of 50ms until the string is done. Now there are no more enqueued commands and Cypress releases the test and the runner continues to the next test.

That was a bit simplified - Cypress does a lot more to make sure .type only runs on elements that can receive focus and are interactable, etc.

Now, knowing this, you can write your example a bit more simply:

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)
})

For me, the accepted answer is good but not really showing me what is necessary.

For me, it is awesome that everything is synchronous and you can do things like


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);
});

Here the interesting thing is even the things inside the then blocks are synchronous. This is so useful.

发布评论

评论列表(0)

  1. 暂无评论