Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wait for method to exist #1164

Closed
bootstraponline opened this issue Jan 8, 2018 · 7 comments
Closed

Wait for method to exist #1164

bootstraponline opened this issue Jan 8, 2018 · 7 comments

Comments

@bootstraponline
Copy link

bootstraponline commented Jan 8, 2018

  • Operating System: Windows 10
  • Cypress Version: 1.4.1
  • Browser Version: Google Chrome Version 63.0.3239.132 (Official Build) (64-bit)

Is this a Feature or Bug?

Feature

Current behavior:

It doesn't seem possible to wait for a method to exist.

Desired behavior:

I'd like a generic wait method that will retry a function until it evaluates to true, similar to WebDriver running execute script and checking the result. The wait function in cypress doesn't appear to allow waiting for methods to be defined.

How to reproduce:

Test a react app that dynamically defines methods based on component life cycle events.

Test code:

it('window.app exists', function() {
    cy.visit('http://localhost:3000/')

    cy.window().its('app').should('exist').then((window) => {

      console.log("cy window:");
      console.log(cy.window().app)
      cy.wrap(cy.window().app).should('exist')
      console.log(window.app);
    });
  })
class App extends React.Component<Props, State> {
  
  constructor(props: Props) {
    super(props);
    // Expose App component on Window for testing.
    if (window && window.document.location.hostname === 'localhost') {
      // tslint:disable-next-line
      window['app'] = this;
    }

Additional Info (images, stack traces, etc)

image

@brian-mann
Copy link
Member

brian-mann commented Jan 8, 2018

You can already do this. There are lots of ways Cypress makes this much easier.

First off you can always use a should(fn) to retry a function over and over again until it does not throw.

https://docs.cypress.io/api/commands/should.html#Function

However you don't need this because its(...) will automatically retry until the property exists on the subject.

https://docs.cypress.io/api/commands/its.html#Rules

Also per your code you are mixing up sync and async code.

it('window.app exists', function() {
    cy.visit('http://localhost:3000/')

    // should('exist') here is not necessary because thats the default assertion
    cy.window().its('app').should('exist').then((window) => {
                                                 // dont call this window, call it win

     // using .its('app') changes the subject to be that property 
     // which is why what you're doing below doesn't work

      console.log("cy window:");
      console.log(cy.window().app) // cy.window() is async it does not return a useful value
      cy.wrap(cy.window().app).should('exist') // nope
      console.log(window.app); // because the subject is already 'app', you're drilling into the 'app' property which is undefined
    });
  })

Here is the correct code:

it('window.app exists', function() {
    cy.visit('http://localhost:3000/')

    cy.window().its('app').then((app) => {
      debugger // please use these, don't use console.log(...)
      app // is defined
    })
  })

@brian-mann
Copy link
Member

Everything in Cypress is made to be easy - you hardly have to write any code or do any kinds of backflips. If you are - then something is probably wrong.

I would suggest further reading our guides here about async and sync code - it shows you common patterns and idioms for dealing with Cypress commands.

https://docs.cypress.io/guides/core-concepts/variables-and-aliases.html

As a final note - remember you're using Cypress not Selenium - which means that you can just drop debugger into your test code and you can use the full scope of the Dev Tools to stop at anything and inspect it. Don't use console.log - there is never a reason to do that instead of a debugger. Using a debugger would immediately enable you to view the local variables in scope and you'd see that your app was yielded to you (and not window).

@bootstraponline
Copy link
Author

Thanks for the tip about debugger;, that made the error immediately clear.

Can I use the new ES7 async / await syntax?
No. The Command API is not designed in a way that makes this possible.

https://docs.cypress.io/faq/questions/using-cypress-faq.html#Can-I-use-the-new-ES7-async-await-syntax

Are there plans for an async/await compatible API?

@brian-mann
Copy link
Member

Streams and promises are not analogous - there is no way to make them behave the same. Cypress commands are more akin to streams of data where data is piped and in and through and thus affected by others. Commands must be linked together. The guides we suggested in that link explain it pretty well.

@bootstraponline
Copy link
Author

Thanks. I will read them in more detail.

@bootstraponline
Copy link
Author

bootstraponline commented Jan 8, 2018

// Works
cy.get('input[data-automation-id="gil"]').as('gil');
cy.get('@gil').should('have.value', '123');

// Works
cy.get('@gil').then(array => {
  cy.wrap(array[0]).should('have.property', 'value', '123');
})

// Both of these error
// Timed out retrying: expected '<input#TextField29.ms-TextField-field.field_95da125e>' to have a property 'value'
cy.get('@gil').should('have.property', 'value', '123');
cy.get('@gil').first().should('have.property', 'value', '123');

@brian-mann Is this ^ user error or a legit bug in the API? I have read the docs and am not sure why one works and the other doesn't.

@brian-mann
Copy link
Member

User error. Not a bug. have.property asserts that the subject has a property. When doing cy.get('...') that yields you a wrapped jquery array-like objects. Those do not have a value property.

have.value is special in that it tunnels into the subject and calls the appropriate jquery methods underneath. Just use the element based assertions when dealing with DOM elements.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants