Testing Multi-Role Workflows in Playwright: The Power of BrowserContexts

// Published on 2026-10-12

Imagine you need to automate a classic collaborative workflow:

  1. Admin creates a project and assigns a reviewer.
  2. Reviewer receives a notification, inspects the project, and requests changes.
  3. Customer checks the status to see the current progress.

In traditional automation tools like Selenium, automating this multi-role scenario was notoriously painful. You either had to:

  • Continuously log in, perform an action, log out, and log back in as the next persona (slow and fragile), or
  • Launch three separate heavyweight browser instances simultaneously, consuming massive amounts of RAM and CPU on your CI runners.

Playwright fundamentally solved this architectural bottleneck with a simple, elegant concept: The BrowserContext.


1. The Playwright Hierarchy

To understand why Playwright handles multiple personas so well, look at its core architecture:

                  Playwright
                      │
                      ▼
                   Browser (Heavyweight process, e.g. Chromium)
                      │
        ┌─────────────┴─────────────┐
        ▼                           ▼
  BrowserContext A            BrowserContext B
  (Admin: Session, Cookies)   (Reviewer: Session, Cookies)
        │                           │
        ▼                           ▼
      Page                        Page

In Playwright:

  • Browser: The actual browser executable running on the operating system. It is expensive to spin up and tear down.
  • BrowserContext: An incognito-like, completely isolated environment within that single browser process. It has its own independent cache, cookies, local storage, and session tokens.
  • Page: A specific tab or window running inside a context.

Creating a new BrowserContext is practically instant (taking just a few milliseconds) and consumes negligible memory.


2. Modeling Multi-User Personas in Code

Instead of launching multiple browsers, you launch one browser and create separate contexts for each persona:

try (Playwright playwright = Playwright.create()) {
    Browser browser = playwright.chromium().launch(
        new BrowserType.LaunchOptions().setHeadless(true)
    );

    // Context 1: Admin Persona
    BrowserContext adminContext = browser.newContext();
    Page adminPage = adminContext.newPage();
    adminPage.navigate("https://app.example.com/login");
    // Perform admin project creation...

    // Context 2: Reviewer Persona (Completely isolated session)
    BrowserContext reviewerContext = browser.newContext();
    Page reviewerPage = reviewerContext.newPage();
    reviewerPage.navigate("https://app.example.com/login");
    // Review project independently...

    // Context 3: Customer Persona
    BrowserContext customerContext = browser.newContext();
    Page customerPage = customerContext.newPage();
    customerPage.navigate("https://app.example.com/login");
    // Verify customer perspective...

    browser.close();
}

Neither session knows about the other. Cookies, tokens, and storage never collide. You can switch between personas seamlessly in the exact same test without ever having to log out.


3. Resilient Locator Strategy Hierarchy

Beyond isolated contexts, Playwright encourages locators that resemble real user interactions rather than brittle DOM paths.

Here is the locator hierarchy I use in production:

1. Role + Accessible Name  ──▶ getByRole('button', { name: 'Submit' })   [Best]
2. Label / Placeholder      ──▶ getByLabel('Username') / getByPlaceholder('Enter email')
3. Test ID (data-testid)   ──▶ getByTestId('order-submit-btn')
4. Stable CSS / ID         ──▶ locator('#order-submit')
5. XPath                   ──▶ locator('//button[text()="Submit"]')      [Avoid if possible]
6. DOM Index / Position    ──▶ locator('div > div:nth-child(2)')         [Last Resort Only]

The Golden Locator Rule:

If two interactive elements on a page are completely indistinguishable by role, accessible text, or label, do not resort to complex, brittle XPaths or nth-child indices.

Instead, partner with your developers to add a stable unique test attribute, such as data-testid="confirm-delete-btn".

A great automated test reflects real product behavior, and clean locators make your suite resilient against cosmetic UI refactors.


Conclusion

Test automation should reflect how modern web applications actually work. By leveraging Playwright's BrowserContext architecture, you can model realistic multi-user collaboration in a single execution loop with minimal resource overhead.

extension Live Applications account_tree Projects article Writing photo_camera Photography play_circle Stream
search Search