How to do authentication in Playwright

December 10th, 2024
| 1.49.0
6 min read
Loading views...
How to do authentication in Playwright

Authentication is usually the first hurdle to overcome when setting up test automation. Depending on how complicated the authentication method is, it can be a daunting task. Let’s start with a simple example of a login sequence.

login.spec.ts
Copy to clipboard

Abstracting the login sequence

Since this is a sequence that will probable need to be repeated in multiple test, we can extract it into a separate block. This could be a function module, or a page object.

Function module

In case of a function, the module might look like this:

login.ts
Copy to clipboard

We can now use this function in our test.

login.spec.ts
Copy to clipboard

Page object

As Playwright encourages the use of page objects, we can create one that might look like this:

login.ts
Copy to clipboard

This page object can now be used in our test. We’ll need to create an instance of it and call the login method. This approach is simplistic, in a real world scenario you’ll likely pass different login parameters and make the page object more flexible.

login.spec.ts
Copy to clipboard

Storing browser state

However, there are some problems with these approaches. While we stick to the DRY principle in terms of the code, when it comes to execution, we are repeating ourselves over and over. Each test will navigate to the login page, fill in the form, click the login button and then check if the login was successful.

With modern web testing tools such as Playwright this is no longer inevitable. We can capture the authentication state and reuse it in multiple tests. To do this, we’ll use two parts of Playwright’s API that help us with this: context.storageState and test.use.

The context.storageState is a property that allows us to store the browser state. It can either be saved to a separate file or returned from the funtion to be saved in a variable. A simple demonstration of how this works:

login.spec.ts
Copy to clipboard

This will save the browser cookies and local storage state to a file in the playwright/.auth.json file.

This file can then be reused in multiple tests. The test.use function is a hook that allows us to use the authentication state in our tests.

login.spec.ts
Copy to clipboard

Watch out!

If you save your browser state to a file, you need to make sure that the file or the folder is not committed to your repository. This file contains sensitive information. Use .gitignore to ignore the file or the folder:

.gitignore
Copy to clipboard

Global setup

Since the majority of tests will need authentication we can create a setup file that act as a dependency for all of our tests. This way we can include the setup globally and not have to repeat it in each test. It’s a good practice to distinguish this setup file from specs by using the .setup.ts extension instead of .spec.ts. Setup files will then become a good place for all the logic that’s responsible for setting up the state, data or other dependencies for the tests.

auth.setup.ts
Copy to clipboard

Once the setup file is created, we can set it up as a dependency in playwright.config.ts. The logic goes as follows:

  1. The setup project is used to run the setup file. This will run our auth.setup.ts file which creates the playwright/.auth.json file with the browser state (lines 6-9).
  2. The chromium project depends on the setup project, therefore it will run the setup file before running the tests (line 16).
  3. The chromium project is used to run the tests and will use the playwright/.auth.json file as the browser state (line 14).
playwright.config.ts
Copy to clipboard

Note that if you want to try this in --ui mode, you need to make sure you’ll have the setup project checked in the projects list otherwise it will be skipped. This might be obvious to experienced users, but it didn’t occured to me when I was first trying to set it up (headless mode works fine, because it runs all projects by default).

playwright ui

The approach with setup file works really well because you’ll also test your login flow. Once that is working Playwright moves on to other tests. But there might be more cases where you don’t want to be logged in. For these tests you can simply fall back to the test.use hook and reset the state for current test.

redirect.spec.ts
Copy to clipboard

Storing state and reusing it in multiple tests is the best way to handle authentication. It reduces the time to execute tests and even makes them more reliable. If your application is secured against brute force attacks (as it should be), you will limit the number of requests to your login endpoint. This creates less strain on your backend, but also means that you have lesser chance to get locked out by captcha or other security measures.

Hope you like this blogpost. If it helped you, please share it with your friends and colleagues. If you have any questions, please feel free to reach out to me on my social media profiles.

Let’s keep in touch

From time to time I send some useful tips to your inbox and let you know about upcoming events. Sign up if you want to stay in loop.

is required.

I treat your email address like I would my own. That means no ads. Just notifications of when I do cool stuff. Unsubscribe anytime. Click here to read about how I handle your data