In this file, I have a describe
block that contains 2 tests — “test #1” and “test #2”.
Let's first talk about our first test. In my test, I do a simple login. So let me run the test so you can see what it does.
As you can see its clicks on the login button. Then inside the login window, it fills in the email and the password, and then I click on the login button. After that, a message that the user is logged in appears, and it can also see my email in the top right corner.
These are all the things that the user can see, but there is also something happening in the background.
Most notably, the application saves a cookie inside my browser so that the server knows that I'm authenticated. This way, even when I refresh my app, I will stay logged in.
Let's look inside the console.
When I look inside the application tab, you can see that there's a Trello token (trello_token
) saved in here.
This is the authorization cookie that our application uses to authenticate against server. Our application is programmed in a way that this cookie will get sent with every HTTP request that is sent over to the server. That way our server will know which user is trying to read or write data to the database. This is a common practice for applications that use log in.
Of course, there are various ways authentication can be made, but that is out of scope of this course.
For now, it is enough to know that in our application, if we have this authorization cookie inside the browser, and it is valid, we are going to be logged in. That enables us to simply copy this cookie, and instead of clicking UI, we can just setCookie
, and open our application as if we were already logged in.
So, the first argument is going to be named of our cookie. That's going to be “trello_token”, and the second argument will be the value. As you can see, it's quite a long string and it contains information about our user as well as authorization token.
describe('Cookies', () => {
beforeEach(() => {
cy
.visit('/')
})
it('test #1', () => {
cy
.setCookie('trello_token', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImZpbGlwQGV4YW1wbGUuY29tIiwiaWF0IjoxNjE1OTg5MTkyLCJleHAiOjE2MTU5OTI3OTIsInN1YiI6IjIifQ.c3HqS_RRCJp4IPYvwbUkxWPwBx4VXJa_0ArzKq7qx_M')
});
});
Now when I save my test, you can see that the cookie is saved over here, but the in the app I'm not logged in. The problem is that I have first opened my page and only then set the cookie.
Let's change our tests slightly and do a reload
after we saved that cookie.
it('test #1', () => {
cy
.setCookie('trello_token', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImZpbGlwQGV4YW1wbGUuY29tIiwiaWF0IjoxNjE1OTg5MTkyLCJleHAiOjE2MTU5OTI3OTIsInN1YiI6IjIifQ.c3HqS_RRCJp4IPYvwbUkxWPwBx4VXJa_0ArzKq7qx_M')
cy
.reload()
});
When I now save my test, you can see that after the reload
, I am logged in. But why were we locked out in the first place?
The reason for that is that Cypress actually deletes cookies and local storage data in between our tests.
So, although I have this cookie over here, if I filter out my first test and run only
the second one, and now save my test you can see that it is not here.
Even if I run both of my tests, you can see the cookie quickly appear and then disappear from the application app.
This might feel like a roadblock initially, but it's actually a good thing.
Keeping the state of each of your tests clean ensures that your tests don't create a domino effect. Meaning that if a first test fails, it makes your second, third and a fourth test fail too.
My recommendation is that you keep your tests in isolation so that anytime a test fails, it doesn't affect any other test.
But let's say we don't want to log in inside each of our tests. And that while we want to clear all the cookies in between tests, we want to stay authorized.
To help with that, Cypress has an API that enables you to preserve cookies that you define.
So, let's define a rule here, and we will do that by typing Cypress.Cookies.defaults
. As an argument in this function, we are going to type preserve
, and this can either be a string or an array of strings. Let's type “trello_token”.
Cypress.Cookies.defaults(}
preserve: 'trello_token'
})
When I now save my test, you can see that the cookie is still here even after the second test happened.
This API is actually something you wouldn't put inside your test, but the right place for that is inside our support folder.
Here in the “index.js” file, you can define all kinds of rules that you want to apply for your whole test suite. So, if we want to stay logged in, we will put that rule over here.
However, you might be in a situation where you don't want to have such a rule in place.
Let's say you only want to preserve cookies in this file. And for all your other test files, you want to delete all your cookies for that. Cypress has another function in its Cypress.Cookies
API.
Let's type Cypress.Cookies
, and there's a function called preserveOnce
. Inside here, you just put in the name of the cookie you want to preserve, “trello_token”.
Cypress.Cookies.preserveOnce('trello_token')
It will preserve the cookie with the name “trello_token” for the next test.
Now, of course, this works well if we have 2 tests, but if we added another one, we might run into a problem.
At the end of our test run, the cookie has disappeared. So, if we want to make sure that our cookie doesn't get deleted, we can just move this to the beforeEach
block. That way our cookie will never get deleted.
describe('Cookies', () => {
beforeEach(() => {
Cypress.Cookies.preserveOnce('trello_token')
cy
.visit('/')
})
it('test #1', () => {
cy
.setCookie('trello_token', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImZpbGlwQGV4YW1wbGUuY29tIiwiaWF0IjoxNjE1OTg5MTkyLCJleHAiOjE2MTU5OTI3OTIsInN1YiI6IjIifQ.c3HqS_RRCJp4IPYvwbUkxWPwBx4VXJa_0ArzKq7qx_M')
cy
.reload()
});
it('test #2', () => {
});
it('test #3', () => {
});
});
Let's recap.
For authentication, web applications often use cookies that are stored in the browser and then get sent with each request that is sent to the server.
To maintain a clean state Cypress deletes cookies in between tests so that you're encouraged to keep your tests isolated from each other.
To change these rules, you can use the Cypress.Cookies
API.
You can either set up defaults and give the name of the cookies that you want to preserve. Or you can use the preserveOnce
function and just preserve cookies in the context of a single test file.