Search code examples
jquerycypresscypress-intercept

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


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. :-)


Solution

  • 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 {
            ...
          }
    
        })
      })