What do the dollar-sign ( $ ) do before variables in Cypress (in then clauses)

1.7k views Asked by At

In the Cypress documentation for Variables and Aliases it uses the dollar sign before the variables in the then-clauses. Like this:

cy.get('button').then(($btn) => {
  // $btn is the object that the previous
  // command yielded us
})

But I can't figure out why.

There are many other posts simply saying a bunch of stuff about "that it's just another character" so nothing special. And also a bunch of mentions of jQuery, obviously.

I just had an example of a complex Cypress-command, that didn't work, because I didn't have the dollar sign. Here is my code:

The Command

Cypress.Commands.add( "verifyUsersAccessToArticle", ( articleFixture, userType ) => {
  cy.fixture( articleFixture, "utf8" ).as( 'article' );

  // Intercept async-loaded content XHR
  cy.get( "@article" ).then( ($article) => {
    cy.intercept({
      method: 'GET',
      url: '/wp-json/sn/public/v1/article/' + $article.postId,
    }).as('postContentFull');
  });

  // Log in
  cy.visit( Cypress.env( 'baseUrl' ) );
  if( userType !== 'noUser' ){
    cy.loginUser( userType );
  }

  // Go to article
  cy.get( "@article" ).then( ($article) => {
    cy.visit( Cypress.env( 'baseUrl' ) + $article.url );
  });

  // Let content load
  cy.wait( 1000 );
  if( userType !== 'noUser' ){
    cy.userIsLoggedIn();
  }

  cy.get( "@article" ).then( ($article) => {

    // Have access
    if( $article[ userType ].hasAccess ){
      cy.get( '@postContentFull' ).then( ( $postContentFull ) => {
        expect( $postContentFull.response.statusCode ).to.equal( 200 );
        cy.get( '#main .post-content' ).children().its( 'length' ).should( 'be.gte', 4 ); // 4 <p>'s
        cy.get('.react-pay-product-paywall').should( 'not.exist' );
      });
    }

    // Doesn't have access
    if( ! $article[ userType ].hasAccess ){
      cy.get( '@postContentFull' ).then( ( $postContentFull ) => {
        expect( $postContentFull.response.statusCode ).to.equal( 402 );
        cy.get( '#main .post-content' ).children().its( 'length' ).should( 'be.lte', 4 ); // 4 <p>'s
        cy.get('.react-pay-title').contains( $article[ userType ].paywallTitle );
        cy.get('.react-pay-card-price > span').contains( $article[ userType ].paywallPrice );
      });
    }
  });
});

The Test

it( 'Verify users access to article', () => {
  
  let articles = [
  'foo-article',
  'bar-article'
  ];

  articles.forEach( (article) => {
    cy.verifyUsersAccessToArticle( Cypress.env( 'name' ) + '/' + article, 'subscriptionTypeZero' );
  });

});

If I wrote postContentFull instead of $postContentFull, then I'm getting an error on the second run (when it runs the iteration for the bar-article):

- then      function(){} 
TypeError 

Cannot read properties of undefined (reading 'statusCode')

Cannot read properties of undefined

Overarching question

What does that dollar sign do?
And am I blind - or why can I not find it in the Cypress documentation?


Update 1: I might have misunderstood something

I think I have a flakey test - and have incorrectly assumed that the dollar sign was the solution. But I'm pretty sure that it's simply because the @article (that is intercepted) hasn't resolved, when the cy.get( "@article" ).then( ($article) => { is executed.

And when I added the dollar sign, the server simply returned faster.

I still would like to figure out, what the dollar sign does. :-)

1

There are 1 answers

0
Fody On BEST ANSWER

Ditto comments above, but further info -

You should wait on the intercept, not get it.

cy.get('@postContentFull') will only work if the intercept has already intercepted.

Also, since you construct a new intercept for each article make the alias unique (otherwise you can't be sure which intercept you get).

cy.fixture( articleFixture, "utf8" )
  .then(article => {                // convention: no $ here, since it's not jQuery

    const alias = 'postContentFull' + article.postId
    cy.intercept('/wp-json/sn/public/v1/article/' + article.postId)
      .as(alias)

    cy.visit('/');                 // visit baseUrl
    if(userType !== 'noUser') {
      cy.loginUser(userType);
    }

    cy.visit(article.url);         // Cypress prepends baseUrl

    cy.wait('@' + alias).then(() => {

      if(article[userType].hasAccess) {
        ...
      } else {
        ...
      }

    })
  })