Authentication in Playwright

Anandhi K
5 min readJul 24, 2022

--

In most of the Web Applications, user must login into application to do any action and also for further interactions we may want to retain the same session. Same in case of automation testing for every scenario we must login into an application especially in e2e testing we may need to test with various user roles.

There are cases where we may repeat the Sign-in process like,

1. Before each Scenario,

2. Reuse the already Signed-in state,

3. Sign-in via API request using any Authorization methods

4. Or may want to Sign-in as multiple users for testing various roles.

All these can be implemented in Playwright without much coding. Playwright easily achieve this by using BrowserContext.

What is BrowserContext?

A BrowserContext is an isolated incognito-alike session within a browser instance. Browser contexts are fast and cheap to create. We recommend running each test scenario in its own new Browser context, so that the browser state is isolated between the tests. If you are using Playwright Test, this happens out of the box for each test. Otherwise, we can also create browser contexts manually.

Tests written with Playwright execute in isolated clean-slate environments called browser contexts. Each test gets a brand new page created in a brand new context. This isolation model improves reproducibility and prevents cascading test failures.

The above Signed-in scenarios can be implemented in Playwright using below strategies :

1. Sign in with beforeEach()

2. Reuse signed in state

3. Sign in via API Request

4. Reuse the signed in page in multiple tests

1.Sign in with beforeEach() :

If we want to login into application before each test execution we embed login functionality in beforeEach().

test.beforeEach(async({page}) => {    await page.goto(‘https://www.demoblaze.com/')    await page.click(‘#login2’)    page.waitForLoadState()    // page.waitForTimeout(5000)    await page.fill(‘input#loginusername’, ‘user1’)    await page.fill(‘input#loginpassword’, ‘user1’)    const loginBtn = await page.locator(‘button.btn.btn-primary’,   {hasText:’Log in’})    await loginBtn.click()})test(‘Valid LoginTest’, async({page}) => {    const loginUsr = await page.locator(‘a#nameofuser’)    await expect(loginUsr).toContainText(‘Welcome’)})

Redoing login for every test will slow down test execution. Instead, reuse existing authentication state.

2. Reuse Signed in State:

Playwright provides a way to reuse the signed-in state in the tests. That way we can log in only once and then skip the log in step for all of the tests. Let we create a new global setup script named global-setup.ts under project folder.

import { chromium, FullConfig } from ‘@playwright/test’;async function globalSetup(config: FullConfig) {  const browser = await chromium.launch();  const page = await browser.newPage();  await page.goto(‘https://www.demoblaze.com/')  await page.click(‘#login2’)  page.waitForLoadState()  // page.waitForTimeout(5000)  await page.fill(‘input#loginusername’, ‘user1’)  await page.fill(‘input#loginpassword’, ‘user1’)  const loginBtn = await page.locator(‘button.btn.btn-primary’,   {hasText:’Log in’})  await loginBtn.click()  // Save signed-in state to ‘storageState.json’.  await page.context().storageState({ path: ‘storageState.json’ });  await browser.close();}

Now register this global-setup script in Playwright configuration file as below,

const config: PlaywrightTestConfig = {  globalSetup: ‘./global-setup’,  testDir: ‘./tests’,  testMatch : [“authentication.test.ts”],  use:{    headless :false,    ignoreHTTPSErrors:true,    screenshot:”only-on-failure”,    video:”retain-on-failure”,    storageState: ‘storageState.json’},

globalSetup: Path to the global setup file.

This file will be required and run before all the tests. It must export a single function. This test already authenticated because we mentioned storageState which was populated by globalSetup. And modify login test to verify signed-in user,

test(‘Valid LoginTest’, async({page}) => {  const loginUsr = await page.locator(‘a#nameofuser’)  await expect(loginUsr).toContainText(‘Welcome’)})

3. Sign in via API Request:

If web application supports signing in via API, we can use APIRequestContext to simplify sign in flow.

What is APIRequestContext?

This API is used for the Web API testing. We can use it to trigger API endpoints, configure micro-services, prepare environment or the service to your e2e test.

globalSetup function from the example above should be updated as:

async function globalSetup() {  const requestContext = await request.newContext();  await requestContext.post(‘https://api.demoblaze.com/login', {  form: {    ‘username’: ‘user1’,    ‘password’: ‘user1’  }  });  // Save signed-in state to ‘storageState.json’.  await requestContext.storageState({ path: ‘storageState.json’ });  await requestContext.dispose();}

The above url is a Request Url from Headers and query parameters (username, password ) from payload.

4. Multiple Signed in Roles:

In some applications we may need to perform various scenarios based on User Role. Already we have generated storageState using globalSetup script. But now we generate two .json files for each different users using codegen.

For admin user generate adminAuth.json

npx playwright codegen — save-storage=adminAuth.json

For normal user generate uAuth.json

npx playwright codegen — save-storage=uAuth.json

On running these commands will record the scripts and after login action on closing the browser will generate the .json files under project folder.

The two storageState files got generated with below contents.

And modify the test to use .json files as below,

test(‘Valid User LoginTest’, async({browser}) => {  const context = await browser.newContext({  storageState: ‘./uAuth.json’  })  const page = await context.newPage()  await page.goto(‘https://www.demoblaze.com/')  await page.waitForTimeout(5000)  const loginUsr = await page.locator(‘a#nameofuser’)  await expect(loginUsr).toContainText(‘Welcome’)})
test('Valid Admin LoginTest', async({browser}) => {
const context = await browser.newContext({ storageState: './adminAuth.json' }) const page = await context.newPage() await page.goto('https://www.demoblaze.com/') await page.waitForTimeout(5000) const loginUsr = await page.locator('a#nameofuser') await expect(loginUsr).toContainText('Welcome CorpAdmin')})

Now playwright use these files to login into app without repeating the login action. Let we run our test,

npx playwright test

Both the tests are passed and generated the report as below,

Now we have signed in as two different users to perform various scenarios.

Reference :

Authentication | Playwright

Conclusion:

Playwright provides various options to automate authentication in e2e testing. This feature really helps to write automation testing for different scenarios with multiple user authentication.

--

--

Anandhi K

DevOps Test Automation Consultant, Trainer and Blogger in Cypress, Selenium, Cucumber, Playwright & CI/CD Tools.