In this chapter, we'll learn about authentication optimization.
We'll see ways to make our sign in faster.
First, we'll see how regular auth works with page objects, how to store the auth with global setup via UI, how to store the auth for multiple roles in a project, and lastly, how to store it via API request.
To implement this login scenario, we are going to open the login.spec.ts
file that is under tests
> ui
> specs
.
You'll find it here - login.spec.ts
and the login-page.ts
which is under tests
> ui
> pages
.
The login.spec.ts
file is the file that will do the sign-in for us.
We have the imports here, as usual.
We are getting the username and password.
We are creating a new page object that we've already learned about.
We are going to skip lines 10, 11 and 12 for now and we go straight to the beforeEach
method.
Here, we are doing a goto
that will open the loginPage
.
The URL is here in this utils file pages.ts
file and we are finally creating the new page object LoginPage
.
Pass in the page
that will go straight to the constructor method - we'll take a look at the Page object in a minute.
For the tests, we do have a test.describe
with the test case name, and here we have the test scenario "successful login".
We are doing the login passing the userName
and password
, and we are checking if the login is successful.
We also have two other scenarios for "failing login", one with the "invalid username" and another one with the "invalid password".
Here, we can see that we pass the invalidUsername
, and here we can see that we pass the invalidPassword
.
For both test cases, we are checking the invalid credentials the same way.
If we go to the LoginPage
page object, we'll see that we have the imports as well.
We have the variable declarations and the constructor
method that will have the locators with the different locators strategies.
For the doLogin
method, which is being called here in the spec file - lines 21, 27 and 33 - we call fillEmail
with the email
we just passed as a parameter.
We fillPassword
and we click the loginButton
.
To check if the sign in is successful, we check the URL and the title of the page.
To check the invalid credentials, we check if the panel has the invalid login message that's being called from this message.ts
file as well.
What this file does is exactly what we would do manually.
Normally, in applications, we usually repeat these steps for every single test.
Playwright has a way to restore the login state so you don't need to repeat these steps for every single test.
We'll see how to do that right now.
To exemplify how storing the sign in works, we are going to open the profile-stored-authentication.spec.ts
, which is also under the specs
folder and the profile-page.ts
, which is also under pages
.
In this file, we do have the imports.
We do have the ProfilePage
object model, and in the beforeEach
you can see that we go straight to the pages.profile
and we create a new profilePage
page object, passing the page
.
In the describe
, we just do checkLoggedIn
- you can see in this method here that we do not do any sign in, and neither in the constructor.
So how does that work?
But before understanding how that works, let's first make sure that the sign in state is working.
In order to do that, I added .only
to the test and I ran the test right here previously.
Before running, I changed the checkLoggedIn
method.
I changed it by removing the .not
here, so we are validating if the notLoggedInLabel
is visible, which is an intentional failure.
If we go to the report and go to the trace, we will see that the page is loaded with the user, meaning the sign in is happening.
I reverted the code to what it was supposed to be, and now we can check how to do that.
In the playwright.config.ts
, we have two items that will be essential for reusing the sign in state.
One is the globalSetup
, where you define a file that will actually do the sign in and create a JSON file with the sign in state to be reused across other tests.
Second is the storageState
- that will be the file that will store the state for us.
If we take a look at the global-setup.ts
, that is under tests
> setup
> global-setup
, you will see that we have the imports as normal, and here we have the parameter config: FullConfig
.
This is actually being imported from @playwright/test
.
That's how it'll connect to the playwright.config.ts
file.
We are defining the user
, the baseURL
, and the storageState
- this is actually the path that we defined in the playwright.config.ts
file here on line 15.
We will launch a browser - it can be Chromium or any other one that you want.
Here we are passing headless: true
.
You could pass headless
as false
if you want, but because we are just signing in, we don't need to do anything other than that.
We will create a newPage
in a new page object, the loginPage
object.
We will goto
the baseURL
login page, doLogin
, and checkLoggedIn
, as we would normally do, and we will store the storageState
with this command.
Finally, we'll do the browser.close
and export
the global setup.
If you want to work with Trace Viewer, you can take a look at this documentation, because if the test fails here, it won't trace anything, but you can implement a trace viewer to help you with that.
This is how the storageState.json
file looks.
It's a group of cookies
and origins
, cookies
like this and origins
like this.
So every time it starts a test, Playwright will automatically load that for you.
Important to note here, if you don't have this globalSetup
running for every run, you could have the file stored in your server or your local machine.
So, you don't necessarily need the globalSetup
if you have a way to have this session saved on the machine that you're running the tests on.
Another note is that this will run once per run.
So, every time you type the command to trigger a test, it will run this globalSetup
.
If you have 10 tests inside that command, that's fine, but if you trigger the command two times, it will create the file again.
Back to the login.spec.ts
file, the line that we just skipped a few minutes ago - test.use({ storageState: { cookies: [], origins: [] } });
- this will make the storageState
empty and then it will not load the sign in state.
Another way of doing it is test.use({ storageState: undefined });
but there is an issue open for Playwright right now, and people will be working to fix that very soon.
But this solution works just fine.
Because this demo QA application has some session limitations, we added this configuration here - test.describe.configure({ mode: 'serial' });
- to make the test run in serial
mode instead of in parallel mode, in case you have multiple tests running at the same time using the same session.
That could make the test fail.
If you have this command, the test will execute in serial
mode, so it's a nice feature to have in applications that don't handle sessions very well.
This is the end of the first video of chapter 1, and we still have one more to go. I'll see you there.
Quiz
The quiz for this chapter can be found in 1.2.