Multi-Context and Windows

Back

Loading concept...

🎭 Playwright: Special Elements - Multi-Context and Windows

The Story of the Busy Restaurant Manager 🍽️

Imagine you’re the manager of a super busy restaurant with many rooms. Each room has different guests, different orders, and different waiters. You need to keep track of everything happening in ALL rooms at the same time!

Playwright works the same way when testing websites that open new windows, popups, or need multiple browser sessions running together.


🏠 What Are Browser Contexts?

Think of a browser context like a separate room in our restaurant.

  • Each room has its own guests (cookies)
  • Each room has its own menu (local storage)
  • Each room has its own waiter (session)
  • Guests in Room A can’t see what’s happening in Room B!
graph TD B["🌐 Browser"] --> C1["🚪 Context 1<br>User A's Session] B --> C2[🚪 Context 2<br>User B's Session"] C1 --> P1["📄 Page 1"] C1 --> P2["📄 Page 2"] C2 --> P3["📄 Page 3"]

Why Do We Need Multiple Contexts?

Real Example: Testing a chat app where User A sends a message to User B.

You need TWO separate “rooms” - one for each user!


🚪 Creating Multiple Browser Contexts

Here’s how we create multiple rooms (contexts):

const { chromium } = require('playwright');

async function twoUsers() {
  const browser = await chromium.launch();

  // Room 1: Alice's session
  const aliceContext = await browser.newContext();
  const alicePage = await aliceContext.newPage();

  // Room 2: Bob's session
  const bobContext = await browser.newContext();
  const bobPage = await bobContext.newPage();

  // Now Alice and Bob are separate!
  await alicePage.goto('https://chat.example.com');
  await bobPage.goto('https://chat.example.com');
}

🎯 Key Point: Alice’s cookies don’t mix with Bob’s cookies. They’re in separate rooms!


🔒 Context Isolation - The Magic Wall

What Is Isolation?

Imagine there’s an invisible wall between each room:

  • 🧱 Cookies stay in their own room
  • 🧱 Login sessions stay separate
  • 🧱 Storage data doesn’t leak
  • 🧱 Cache is independent
graph LR subgraph Context1["🔵 Context 1"] C1["🍪 Cookies A"] S1["💾 Storage A"] end subgraph Context2["🔴 Context 2"] C2["🍪 Cookies B"] S2["💾 Storage B"] end W["🧱 ISOLATION WALL"] Context1 -.-> W W -.-> Context2

Real Example: Testing Admin vs Regular User

async function testDifferentRoles() {
  const browser = await chromium.launch();

  // Admin context with special settings
  const adminContext = await browser.newContext({
    storageState: 'admin-login.json'
  });

  // Regular user context
  const userContext = await browser.newContext({
    storageState: 'user-login.json'
  });

  const adminPage = await adminContext.newPage();
  const userPage = await userContext.newPage();

  // Admin sees admin dashboard
  await adminPage.goto('/dashboard');

  // User sees limited dashboard
  await userPage.goto('/dashboard');

  // They see DIFFERENT things!
}

💡 Why This Matters: You can test “what does an admin see?” and “what does a regular user see?” at the SAME time!


📑 Multiple Pages and Tabs

Pages Are Like Tables in a Room

Inside each room (context), you can have multiple tables (pages).

  • Same room = same cookies shared
  • Different tables = different web pages open
async function multipleTabs() {
  const browser = await chromium.launch();
  const context = await browser.newContext();

  // Open first tab
  const page1 = await context.newPage();
  await page1.goto('https://shop.example.com');

  // Open second tab (same context!)
  const page2 = await context.newPage();
  await page2.goto('https://shop.example.com/cart');

  // Both tabs share the same login!
  // Add item on page1...
  await page1.click('.add-to-cart');

  // Refresh page2 to see cart updated!
  await page2.reload();
}
graph TD CTX["🚪 Single Context<br>Same Session"] --> T1["📄 Tab 1<br>Shop Page"] CTX --> T2["📄 Tab 2<br>Cart Page"] CTX --> T3["📄 Tab 3<br>Checkout"] style CTX fill:#e1f5fe

Getting All Open Pages

// Get all pages in a context
const allPages = context.pages();
console.log(`Open tabs: ${allPages.length}`);

// Find a specific page by URL
const cartPage = allPages.find(
  p => p.url().includes('/cart')
);

🎈 Handling Popups

Popups Are Like Surprise Visitors!

When you click a button and a new little window appears, that’s a popup. Playwright can catch these!

Think of it like this: You’re watching the door, and when a surprise guest arrives, you’re ready to greet them.

async function handlePopup() {
  const page = await context.newPage();
  await page.goto('https://example.com');

  // Wait for popup BEFORE clicking
  const popupPromise = page.waitForEvent('popup');

  // Click the button that opens popup
  await page.click('#open-login-popup');

  // Catch the popup!
  const popup = await popupPromise;

  // Now interact with popup
  await popup.fill('#username', 'myuser');
  await popup.click('#login-btn');
}

The Popup Pattern Explained

graph TD A["📄 Main Page"] -->|Click Button| B["🎈 Popup Opens"] B -->|Playwright Catches| C["📄 Popup Page Object"] C -->|You Can Now| D["Fill Forms"] C -->|You Can Now| E["Click Buttons"] C -->|You Can Now| F["Read Content"]

Important Popup Tips

Situation What Happens
target="_blank" link Creates popup
window.open() call Creates popup
OAuth login button Usually popup
Payment window Often popup
// Handle popup with timeout
const popup = await page.waitForEvent('popup', {
  timeout: 5000  // Wait max 5 seconds
});

// Check if popup loaded correctly
await popup.waitForLoadState('domcontentloaded');
console.log('Popup URL:', popup.url());

🪟 New Window Handling

Windows Are Like New Rooms Opening Up

When a website opens a completely new browser window, it’s similar to a popup but bigger!

async function handleNewWindow() {
  const page = await context.newPage();
  await page.goto('https://docs.example.com');

  // Prepare to catch new window
  const newWindowPromise = context.waitForEvent('page');

  // Click link that opens new window
  await page.click('a[target="_blank"]');

  // Get the new window
  const newWindow = await newWindowPromise;

  // Wait for it to load
  await newWindow.waitForLoadState();

  // Work with new window
  const title = await newWindow.title();
  console.log('New window title:', title);
}

Multiple Windows - Keep Track!

async function manageWindows() {
  const context = await browser.newContext();

  // Start with one page
  const mainPage = await context.newPage();
  await mainPage.goto('https://example.com');

  // Track all pages that open
  context.on('page', async (newPage) => {
    console.log('New window opened!');
    console.log('URL:', newPage.url());
  });

  // Your test continues...
  // Every new window triggers the event!
}
graph LR CTX["🚪 Context"] --> M["📄 Main Window"] M -->|Opens| N1["🪟 New Window 1"] M -->|Opens| N2["🪟 New Window 2"] CTX -.->|Listens| E["👂 page Event"]

Closing Windows Properly

// Close a specific window
await newWindow.close();

// Close all windows except main
const pages = context.pages();
for (const p of pages) {
  if (p !== mainPage) {
    await p.close();
  }
}

🎯 Putting It All Together

Complete Example: Testing Multi-User Chat

const { chromium } = require('playwright');

async function testChat() {
  const browser = await chromium.launch();

  // Two separate users (contexts)
  const aliceCtx = await browser.newContext();
  const bobCtx = await browser.newContext();

  const alicePage = await aliceCtx.newPage();
  const bobPage = await bobCtx.newPage();

  // Both go to chat
  await alicePage.goto('https://chat.app');
  await bobPage.goto('https://chat.app');

  // Alice logs in
  await alicePage.fill('#user', 'alice');
  await alicePage.click('#join');

  // Bob logs in
  await bobPage.fill('#user', 'bob');
  await bobPage.click('#join');

  // Alice sends message
  await alicePage.fill('#msg', 'Hello Bob!');
  await alicePage.click('#send');

  // Bob sees it!
  const msg = await bobPage.textContent('.message');
  console.log('Bob received:', msg);

  // Clean up
  await aliceCtx.close();
  await bobCtx.close();
  await browser.close();
}

🌟 Quick Reference

Concept Restaurant Analogy Playwright Code
Browser The Restaurant chromium.launch()
Context A Private Room browser.newContext()
Page A Table context.newPage()
Popup Surprise Guest page.waitForEvent('popup')
New Window New Room Opens context.waitForEvent('page')

💪 You’ve Got This!

Now you understand:

  • Multiple contexts = separate user sessions
  • Context isolation = data doesn’t mix between sessions
  • Multiple pages = many tabs, same session
  • Popups = catching small windows that appear
  • New windows = handling full new browser windows

Remember: Think of the restaurant! Each room is isolated, but you’re the manager who can see and control everything. 🎭


Happy Testing! 🚀

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.