DEV Community

Cover image for Using Cypress to test multiple web pages as a logged-in user
ADS-BNE
ADS-BNE

Posted on • Edited on

Using Cypress to test multiple web pages as a logged-in user

Sometimes you need to test multiple pages when logged in as a user. This became apparent for me when I was testing a site that relied on a user to login to review content changes before articles were published.

Whilst we had a suite of Cypress tests for the live site, we didn't have any for the 'preview' versions of the site's blog article content, and so were faced with the challenge of being only able to run tests after a release.

Here's how we went about using Cypress' sessions to test our pages as a logged in user.


TL;DR:

  1. Create a login() Custom Command in commands.js that passes a username and password to your site's login form.
  2. Set your test account's username and password somewhere safely.
  3. Save your test account's username and password, and a boolean saying whether to run as a logged in user or not in Cypress' Environment Variables.
  4. Add a conditional, in e2e.js, that runs before each test that logs the user in using the login() Custom Command.

Step 1: Creating a Custom Command to login a user and create a session

First, we need to actually need to create the process for Cypress to login as a user. We need a special command to do that.

Cypress allows you to create Custom Commands for your project. Unsurprisingly, these are stored in commands.js (cypress/e2e/support/commands.js).

Our login Custom Command should simply do the following:

  1. Take username and password values as arguments
  2. Navigate to the login page
  3. Fill out and submit the login form (username, password fields) - just usual Cypress cy.() stuff
  4. Register a new 'session' (eg new cookies) with Cypress and cache it

My Custom Command login script looks like:

//cypress/e2e/support/commands.js
Cypress.Commands.add('login', (username, password) => {
    cy.session([username, password], () => {
        cy.visit('/login');
        cy.get("#username").type(username);
        cy.get("#password").type(password);
        cy.get('#login-btn').click();
    },{
        cacheAcrossSpecs: true
    });
});
Enter fullscreen mode Exit fullscreen mode

Note the cy.session() function and the cacheAcrossSpecs: true setting.

Step 2 (optional): Saving your username and password

Next we want to save our username and password somewhere for our new login Custom Command to use.

Now, you could just hard code them into the Custom Command above, but that's not entirely advisable if you're pushing them on a shared git repo or something like that. But if you want to do that or just set them some other way you can skip this step.

For myself, I opted to create a users.js (cypress/e2e/support/users.js) file to save them on and used .gitignore to exclude from being pushed up to Github.

//cypress/e2e/support/users.js
module.exports.uatUser = {
    un: "myUserAcc",
    pw: "myP4ssw0rd",
};
Enter fullscreen mode Exit fullscreen mode

In .gitignore: cypress/e2e/support/users.js

Step 3: Setting Environment Variables

We need to make our username and password available to all our test spec files. We also need a way to tell Cypress if we want to run the test as a logged in user, or just a normal public user.

The way we do that is with Cypress' Environment Variables. These are simply variables that are available to Cypress across all tests.

First, we need know if we want to run the test as a logged in user or not. I did this using an npm Environment Config (not to be confused with Cypress' own Environment Variables). These are simply values taken from the command line input, eg: process.env.npm_config_hello is set by adding --hello=world to your command.

For example, to create a variable to tell Cypress we are going to run something as a logged in user we make a new constant:

const userLoggedIn = process.env.npm_config_loggedIn === "yes" ? 'yes' : '';
Enter fullscreen mode Exit fullscreen mode

And in our command line we'd run: node ./cypress/e2e/myTests.js --loggedIn-yes to set it.

There are many ways to set Environment Variables in Cypress, but as I run my tests via the Module API .run() function I just include them as such:

//myTests.js
const cypress = require('cypress');
const user = require('./support/users.js'); //<- where I've stored my 
const userLoggedIn = process.env.npm_config_loggedIn === "yes" ? 'yes' : '';
// Array of my test spec files.
const specs = [
    `./homePage.spec.js`,
    `./aboutPage.spec.js`,
     //etc
];
// Run Cypress
cypress.run({
    browser: 'chrome',
    headed: false,
    spec: specs,
    env: {
        loggedIn: userLoggedIn, //<- set from the command line
        userName: user.uatUser.un, //<- this login var from users.js
        password: user.uatUser.pw, //<- this login var from users.js
    }
});
Enter fullscreen mode Exit fullscreen mode

In this way, we are making our environment, username and password available to all our tests.

Step 4: Logging-in, or checking the session, before each test is run

We need to ensure that our user is logged in before each test runs. You might think we need to run our Login Custom Command before each test starts. And you'd be right. But, lucky for us we don't actually need to update each of our test specs to do this.

Instead, we can simply add the follow to our support/e2e.js file:

//support/e2e.js
before(() => {
    if (Cypress.env('loggedIn') == 'yes'){
        cy.task('log', `Running test as a logged in user ------------`);
        cy.login( Cypress.env('userName'), Cypress.env('password'));
    }
})
Enter fullscreen mode Exit fullscreen mode

As you can guess, the before() function runs before each test starts. It's the same as adding it to each test's spec.js file, but a lot less work.

Note, we are passing it the loggedIn, username and password values we set in our Cypress environment variables (obviously, we're not going to login if the loggedIn value isn't yes).

Now, just to clear something up: When I first was looking into this I was concerned that the above code meant that Cypress would have to login before every, single, test. This is not so.

Remember when we added cacheAcrossSpecs: true above? That allows Cypress to cache to the user session and so only run the login process once per set of tests. In other words Cypress will not waste time re-filling out the login form for each consecutive test if it has already logged in once.

And that should be it! You can now run your set of tests both as a logged in and non-logged in user!

For my example above, to run tests as a logged in user I would simply run: node ./cypress/e2e/myTests.js --loggedIn==yes


Cover photo by Markus Spiske

Top comments (0)