angulartestingcucumbercypresscypress-cucumber-preprocessor

Why do pre-defined variables not behave as expected in Cypress?


I'm getting wacky results when pre-defining element variables and using them afterwards in Cypress 10 w/ Cucumber. Consider this login test:

Given("I'm logged in as Default user", () => {        

    cy.visit('/');

    let usernameField = cy.get('#myUsernameInputField');
    let passwordField = cy.get('#myPasswordInputField');
    let signInButton = cy.get('#mySignInButton');
  
    usernameField.clear();

    usernameField.type('myUsername@gmail.com');
   
    passwordField.type('myPassword');
  
    signInButton.click();

});

This results in both the username and password being typed into the passwordField, and the signInButton never being clicked. Only when I rearrange the variables in a more chronological order does this test behave as expected:

Given("I'm logged in as Default user", () => {

    cy.visit('/');

    let usernameField = cy.get('#myUsernameInputField');
    usernameField.clear();
    usernameField.type('myUsername@gmail.com');

    let password = cy.get('#myPasswordInputField');
    password.type('myPassword');
  
    let signInButton = cy.get('#mySignInButton');
    signInButton.click();

});

I planned to eventually move these variables into a page object file. But here in the test, they don't behave as expected when I pre-define them and try to use them later. Why is this?


Solution

  • Basically, you shouldn't hold references to query results in plain javascript variables.

    The reason is, Cypress runs on a queue system and the queue has only one "subject" at any time.

    You should think of the queue as a separate thread or execution process that runs asynchronously to the test execution, so it's possible that the variables in the thread are getting out of sync with the queue subject.


    The conventional way to do this is to use the query results immediately like

    cy.get('#myUsernameInputField').type('myUsername@gmail.com');
    

    then move on to the next query (password).

    If for some reason you do need a reference to the query result, Cypress has an alias mechanism to handle it

    cy.get('#myUsernameInputField').as('username)
    
    ...
    // later in the test
    
    cy.get('@username').type('myUsername@gmail.com');