Xebia Background Header Wave

Suppose you have a web application for which you would like to write browser tests using Playwright. This web application contains a login screen and after successful authentication, all functionality is loaded. This means that in order to test the application, each test requires an authenticated user. Because each test runs in isolation, each test needs to authenticate. So, in each test, you write the steps to open a browser, navigate to the login screen, fill in the username, password, click on submit, and finally wait for the page to be loaded. Running this can take from a couple of seconds for one test to minutes for dozens of tests. Ideally, you want to authenticate only once when running your Playwright tests.

What if you could somehow reuse the logged-in state across your tests? Luckily, there is such a way and it is pretty easy to set it up using Playwright. Read on and discover how you can shave off valuable time by authenticating only once with Playwright.

If you want to dive straight into the solution, you can check out the repository HERE.

Playwright authenticate once steps summary

In a nutshell, the following steps are needed and they are described in detail in their respective sections in this article:

  1. Store the test account’s username and password in a safe way
  2. Write the login test function
  3. Configure the the storage state path
  4. Write a function that calls the login function and saves the logged in state to the storage state path
  5. Write the tests that require the logged in state

Step 1: Store the Username and Password

I use dotenv to store and load the username and password. This avoids credentials becoming part of the committed code.

npm i -D dotenv

Next, let’s initialize dotenv in the configuration file of Playwright playwright.config.ts.

https://gist.github.com/corradin/998f03af89f69aa586c40b4ca6648d52

Next, create a .env file on your machine in the root of the repo with the following:

https://gist.github.com/corradin/e8b20a8a0800089024f4e00321b43d1e

Obviously, you need to fill in real values for the username and password from a valid user. In this example, we want to use meetup.com.

Step 2: Write the “Playwright authenticate once” Test

Below, the code for login.ts is shown:

https://gist.github.com/corradin/bba590d2549988c84eb6d72136a0e18e

The login function has three arguments. The username and password may be straightforward. The Playwright test library always needs a page object when defining actions for browser pages, such as navigation or interacting with the DOM.

The first action is to navigate to the login page of meetup.com. Next, the username and password fields are filled in from the values that are provided through the arguments of the function. In a later section, we will see how these arguments are provided.

As the last step a DOM element that matches a button with the type "submit" and the text "Log in" is clicked. This click is preceded by a waitForNavigation function and wrapped in a Promise.all. This means that, after the button has been clicked, the test waits for the navigation to be completed in order to return. This is useful when a click button causes indirect navigation. In this case, the click causes an API call, which validates the request, returns an OK message, and causes the page to redirect. The waitForNavigation needs to be specified before the click function in order to set up the wait.

Step 3: Configure the Storage State

Web applications may use cookie-based or token-based authentication (see here for more information). Playwright uses the storageState method to store the authenticated state of a user after the user has logged in. This state can be read when creating a new browser context. The path for this file with the stored state can be configured in the playwright.config.ts:

https://gist.github.com/corradin/5dc834c423b7a97e891fa838e1c3662d

The storageState property is where you specify the path of the file where the authenticated information is being stored. The globalSetup property is the path to your global setup file. This file contains code that runs once before all your tests.

Step 4: Write the “Playwright authenticate once” Setup

To make sure the login test is run before all other tests, Playwright defines a global setup approach. The global-setup.ts file is shown as follows:

https://gist.github.com/corradin/7632ea89e37ba895e828a13445f1544d

The username and password can be read from the environment since the env.config() method has run and processed your .env file. The storageState property can be retrieved from the playwright.config.ts file by reading from the FullConfig. The headless: false option in the method chromium.launch is not needed, but I’ve added it to see what is happening on the screen.

The call to the login function is made by providing the current page object, username, and password because the login function needs a page object for its actions. After the login, the authentication information is stored to the storageState. At the end of the global setup, the browser needs to be closed. Once this function returns, the tests start running in a different browser instance.

Step 5: Write the tests

In order for the "Playwright authenticate once" functionality to prove its point, we need at least two isolated tests that depend on the logged-in state.

https://gist.github.com/corradin/18eeaae8582848f8b5c128200ba74b09

We navigate to two different pages and verify the visibility of certain text on the screen. When we run the tests, the results can be seen below.

The test that runs once and logs in a user:

Login recording

The test that navigates to the Notifications page:

Notifications test recording

The test that navigates to the Payment methods page:

Payment methods test recording

The test run finishes in approximately 5 seconds as opposed to 13 seconds when a login is done before each test.

Conclusion

When you are writing browser tests with Playwright for a web application that needs authenticated users for your tests to work, start early with an authenticate-once approach.

Your tests will:

  1. Run faster
  2. Be closer to reality (A user logs in once and does all the actions for the duration of the session)
  3. Be cleaner
  4. Better equipped for cases in which you want to add users with different roles. You can keep track of those users in the stateStorage and feed them to your tests.

Would you like to know more about Playwright? Ready for the next step?
Go check this training: End-to-End Testing with Playwright
Any comments are more than welcome! Drop me a message through LinkedIn or Twitter @rscorradin.

Questions?

Get in touch with us to learn more about the subject and related solutions

Explore related posts