Sunday, May 4, 2025

Efficiently Sharing Context in Parallel Tests with Playwright

In this example we will explore how to share browser, context and page in multiple test during parallel execution in playwright. Parallel execution in Playwright for JavaScript allows running tests concurrently to reduce execution time. Playwright’s test runner (@playwright/test) supports parallelism by default, leveraging Node.js processes to run tests across multiple workers. 

How to perform parallel execution in playwright

Sharing browser, context, and page variables across multiple tests during parallel execution in Playwright requires careful management to avoid conflicts and ensure test isolation. Here are a few approaches:


1. Using test.describe.configure({ mode: 'parallel' })

Tests within a describe block configured with parallel mode run concurrently, but they do not inherently share variables. To share variables, declare them in the beforeEach hook within the same describe block.


 Syntax for parallel run

import { test } from '@playwright/test';

test.describe.configure({ mode: 'parallel' });

test('runs in parallel 1', async ({ page }) => { /* ... */ });
test('runs in parallel 2', async ({ page }) => { /* ... */ });

This example ensures each test has access to the same instances in single test file.

const { test, expect } = require('@playwright/test');

test.describe.configure({ mode: 'parallel' });

test.describe('Parallel Tests', () => {
  let browser, context, page;

  test.beforeEach(async ({ browser }) => {
    browser = browser;
    context = await browser.newContext();
    page = await context.newPage();
   
  });

  test('Test 1', async () => {
    // Use page, context, browser
    await page.goto('https://chatgpt.com/');
    
    // This will wait for 20 seconds and close the browser window.
    await page.waitForTimeout(20_000);
  });

  test('Test 2', async () => {
   // Use the same page, context, browser
   await page.goto('https://www.skptricks.com/');

   // This will wait for 10 seconds and close the browser window.
   await page.waitForTimeout(10_000);
  });
});


Output:

D:\playwright Project\Playwright-tutorial>npx playwright test parallel-run.spec.js --project=chromium --headed

Running 2 tests using 2 workers

    1 [chromium]  tests\parallel-run.spec.js:15:3  Parallel Tests  Test 1 (23.2s)
    2 [chromium]  tests\parallel-run.spec.js:23:3  Parallel Tests  Test 2 (16.3s)

  2 passed (25.6s)

Alternatively, you can opt-in all tests into this fully-parallel mode in the configuration file:

playwright.config.ts

import { defineConfig } from '@playwright/test';

export default defineConfig({
  fullyParallel: true,
});

You can also opt in for fully-parallel mode for just a few projects:

playwright.config.ts

import { defineConfig } from '@playwright/test';

export default defineConfig({
  // runs all tests in all files of a specific project in parallel
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
      fullyParallel: true,
    },
  ]
});


Limit workers

You can control the maximum number of parallel worker processes via command line or in the configuration file.

From the command line:

npx playwright test --workers 6


In the configuration file:

playwright.config.ts

import { defineConfig } from '@playwright/test';

export default defineConfig({
  // Limit the number of workers on CI, use default locally
  workers: process.env.CI ? 2 : undefined,
});


Disable parallelism

You can disable any parallelism by allowing just a single worker at any time. Either set workers: 1 option in the configuration file or pass --workers=1 to the command line.

npx playwright test --workers=1


2. Custom Fixtures

Custom fixtures provide a structured way to manage and share test state. Create a custom fixture that initializes the browser, context, and page, then use this fixture in your tests.


 Benefits

  1. Cleaner tests: no need to repeat login code in every test
  2. Reusable setups: you can add fixtures for blog drafts, image uploads, etc.
  3. Improved performance: open context once per test instead of starting from scratch.


//fixtures/fixtures.js

import { test as base, expect } from '@playwright/test';

export const test = base.test.extend({
  browser: async ({ playwright }, use) => {
    const browser = await playwright.chromium.launch({ headless: false });
    await use(browser);
    await browser.close();
  },

  context: async ({ browser }, use) => {
    const context = await browser.newContext();
    await use(context);
    await context.close();
  },

  page: async ({ context }, use) => {
    const page = await context.newPage();
    await use(page);
    await page.close();
  }
});

//tests/parallel-run-using-fixture.spec.js
import { test , expect } from '../fixtures/fixtures.js';  

  test('Test 1', async ({page}) => {
    // Use page, context, browser
    await page.goto('https://chatgpt.com/');
    
    // This will wait for 20 seconds and close the browser window.
    await page.waitForTimeout(20_000);
  });

  test('Test 2', async ({page}) => {
   // Use the same page, context, browser
   await page.goto('https://www.skptricks.com/');

   // This will wait for 10 seconds and close the browser window.
   await page.waitForTimeout(10_000);
  });

  test('Test 3', async ({page}) => {
    // Use page, context, browser
    await page.goto('https://chatgpt.com/');
    
    // This will wait for 20 seconds and close the browser window.
    await page.waitForTimeout(20_000);
  });

  test('Test 4', async ({page}) => {
   // Use the same page, context, browser
   await page.goto('https://www.skptricks.com/');

   // This will wait for 10 seconds and close the browser window.
   await page.waitForTimeout(10_000);
  });


Output:

D:\playwright Project\Playwright-tutorial>npx playwright test  parallel-run-using-fixture.spec.js --project=chromium --headed
complete the execution for global setup...

Running 4 tests using 2 workers

    1 [chromium]  tests\parallel-run-using-fixture.spec.js:5:7  Test 1 (23.5s)
    2 [chromium]  tests\parallel-run-using-fixture.spec.js:13:7  Test 2 (16.6s)
    3 [chromium]  tests\parallel-run-using-fixture.spec.js:21:7  Test 3 (22.4s)
    4 [chromium]  tests\parallel-run-using-fixture.spec.js:29:7  Test 4 (14.1s)
Access shared data in teardown :  Sumit Kumar Pradhan
complete the execution for global teardown...

  4 passed (42.2s)

Choosing between parallel and sequential execution in Playwright tests hinges on understanding your tests’ nature and their impact on the application environment. By categorizing tests into stateful and stateless, developers can apply the appropriate execution strategy, ensuring efficiency and reliability in their E2E testing processes.


No comments:

Post a Comment