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:
- Create a
login()
Custom Command incommands.js
that passes a username and password to your site's login form. - Set your test account's username and password somewhere safely.
- 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.
- Add a conditional, in
e2e.js
, that runs before each test that logs the user in using thelogin()
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:
- Take username and password values as arguments
- Navigate to the login page
- Fill out and submit the login form (username, password fields) - just usual Cypress
cy.()
stuff - 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
});
});
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",
};
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' : '';
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
}
});
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'));
}
})
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
Top comments (0)