My application has an authentication. Whenever a user is logged in, they can see their private boards. If they are not logged in, they will only see the ones that are public.
Whenever I'm logged in, I'll be able to see my email at the top right corner. And also the private board that I have created. When I click on my email on this logout icon, I will no longer see the private board. In my test, I'm using a custom command to log in. And then I visit my homepage and make sure that the board is visible and make sure that my private board is visible.
In my custom command, which I have defined here above, I'm visiting the login page, typing my email and my password, clicking on a login submit button, and then checking whether I got redirected to the homepage. I'm using this command in every one of my tests. So in the second one and in the third test as well, this approach makes sure that I'm logged in for every one of my tests, but it is kind of repetitive. Not in writing the code, but in the test execution. Before every test, we visit the page, type in our credentials, click on submit, and then get redirected.
In Cypress, there's actually a better way to approach this. We can log in just once and then use that login for every other test. Before we do that, let's talk a little bit about how authentication usually works. There are usually three parties involved. First one is the frontend, the login screen where we enter our credentials. The second part is the backend. We communicate with the backend using API request. This is a very simple authentication flow and with modern applications, things get a little bit more complicated, but in principle, there always be some communication between frontend and backend.
In our application, this is represented by this API login. This is going to send our credentials to the server and server is going to validate them. When it does that, and we actually put in, and we have actually put in proper credentials, it's going to give us an authentication token back. After I rerun my tests again, we can look into that, into our DevTools. I'm going to go to application panel and look at the cookies panel. I see the authentication token is being stored here. This authentication token is then read by our frontend application and sent with every other request the application is going to make.
So for example, if I click on this API users slash one, which is going to gather information about the logged in user, I can see that in the request header, I have this authorization header, which bears the token that was saved in cookies. This way server will know that the client that's asking for some resources is actually authorized to access them. So for example, if we do a get API boards call and we sent an authorization header, server is going to respond with a list of the boards that were created by that user. If I log out, my get API boards is going to be sent without the authorization header and server is going to respond accordingly and therefore hiding the private board from an anonymous user. So the authorization token is actually key here and since it gets stored inside browser, the browser will play critical part in differentiating between logged in and logged out user. Now let's go back to our test. What we can do in Cypress is to actually take a snapshot of a certain state in a browser and to do that, we are going to use CY session command.
This session command will take two arguments. First one will be the name of our session. Let's call this user number one. The second argument will be a callback function that is going to contain all of our login commands. When I run my test now, Cypress is going to create a new session. So it's going to run all of my login commands and then save all of the browser data like session storage, cookies, and local storage. The next time I'll run my test, instead of running my login commands, it's going to restore my session, which is much faster.
We're not visiting the login page, just restoring the data that was in the browser after we logged in the last time. This will make our tests much more effective. Let me show you this in action. I'm going to remove this it only, and I'm going to run this CY login in every one of our tests. If I comment out the session and run my test normally, it is going to take about four seconds to go through all the tests. If I return my session back and instead of going through the login page, I'm just going to restore the browser data. The speed of my tests is going to drop down to just one second.
If you have hundreds of end-to-end tests and each one of them requires a login, this is going to speed up your test run tremendously. Because instead of logging in a hundred times, you can just log in once and use the data from the first login for all of your next tests. Now, in order to achieve that, I should put my login command in a separate file so it is actually accessible throughout my test suite, but also there's an additional argument that I can put into my CY session command, and that's a configuration object. In here, I can define a cache across specs option and set that to true.
What this is going to achieve is that our session will actually be available for all of the files in my test suite. Without this, we would be doing caching just on a singular spec. Another useful option in here is the validate function. This is going to make sure that our authorization is actually valid. For longer test runs, it may happen that at some point you'll get logged out. To make sure that this doesn't disrupt your test run, you can run a validate function that will check whether you need to run this series of commands again, or if the authorization token is still valid.
The way I can do that is to get my authorization cookie and then pass it into a CY request command. I'll call the URL API users slash one, and then add a header with the authorization of bearer and our token. I actually need to take the value of this cookie. I'll save my test and I see that everything is running. This way, even if the authorization cookie would get expired, it would not pose a problem if that happened. If the authorization token is still valid, we'll restore the session and proceed with our test.