Multi-tab testing in Playwright allows you to simulate complex user workflows that span across multiple browser tabs. This is essential for testing applications with pop-ups, external links, or multi-step processes.
How Multi-Tab Testing Works
In Playwright, each tab is represented by a Page
object. You create new tabs using context.newPage()
and manage them independently. Unlike switching between tabs, you directly interact with specific page objects.
Basic Multi-Tab Example
JavaScript
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: false });
const context = await browser.newContext();
// Create first tab
const page1 = await context.newPage();
await page1.goto('https://example.com');
await page1.fill('#search', 'playwright');
// Create second tab
const page2 = await context.newPage();
await page2.goto('https://github.com');
await page2.click('text="Sign in"');
// Work with both tabs simultaneously
const title1 = await page1.title();
const title2 = await page2.title();
console.log(`Tab 1: ${title1}`);
console.log(`Tab 2: ${title2}`);
await browser.close();
})();
Python
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
context = browser.new_context()
# Create first tab
page1 = context.new_page()
page1.goto('https://example.com')
page1.fill('#search', 'playwright')
# Create second tab
page2 = context.new_page()
page2.goto('https://github.com')
page2.click('text="Sign in"')
# Work with both tabs simultaneously
title1 = page1.title()
title2 = page2.title()
print(f"Tab 1: {title1}")
print(f"Tab 2: {title2}")
browser.close()
Advanced Multi-Tab Scenarios
Handling Pop-up Windows
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const context = await browser.newContext();
const mainPage = await context.newPage();
await mainPage.goto('https://example.com');
// Listen for new pages (pop-ups)
const newPagePromise = context.waitForEvent('page');
await mainPage.click('text="Open in new tab"'); // Trigger pop-up
const popupPage = await newPagePromise;
// Wait for popup to load
await popupPage.waitForLoadState();
// Interact with both pages
await mainPage.fill('#email', 'user@example.com');
await popupPage.fill('#password', 'secretpass');
await browser.close();
})();
Managing Multiple Tabs with Arrays
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const context = await browser.newContext();
const urls = [
'https://example.com',
'https://github.com',
'https://stackoverflow.com'
];
// Create multiple tabs
const pages = await Promise.all(
urls.map(url => context.newPage().then(page => {
page.goto(url);
return page;
}))
);
// Perform actions on all tabs
const titles = await Promise.all(
pages.map(page => page.title())
);
titles.forEach((title, index) => {
console.log(`Tab ${index + 1}: ${title}`);
});
// Close all pages
await Promise.all(pages.map(page => page.close()));
await browser.close();
})();
Cross-Tab Data Sharing
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const context = await browser.newContext();
// Login in first tab
const loginPage = await context.newPage();
await loginPage.goto('https://example.com/login');
await loginPage.fill('#username', 'testuser');
await loginPage.fill('#password', 'testpass');
await loginPage.click('button[type="submit"]');
// Use session in second tab
const dashboardPage = await context.newPage();
await dashboardPage.goto('https://example.com/dashboard');
// Session cookies are shared between tabs in the same context
const isLoggedIn = await dashboardPage.isVisible('.user-menu');
console.log('User is logged in:', isLoggedIn);
await browser.close();
})();
Best Practices
1. Proper Resource Management
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const context = await browser.newContext();
try {
const pages = [];
// Create tabs
for (let i = 0; i < 3; i++) {
const page = await context.newPage();
pages.push(page);
await page.goto(`https://example.com/page${i}`);
}
// Your testing logic here
} catch (error) {
console.error('Test failed:', error);
} finally {
// Always clean up
await browser.close();
}
})();
2. Waiting for Tab Operations
// Wait for all tabs to finish loading
await Promise.all(pages.map(page =>
page.waitForLoadState('networkidle')
));
// Wait for specific elements in each tab
await Promise.all([
page1.waitForSelector('.search-results'),
page2.waitForSelector('.user-profile'),
page3.waitForSelector('.product-list')
]);
3. Error Handling
const handleTabOperation = async (page, operation) => {
try {
await operation(page);
} catch (error) {
console.error(`Tab operation failed: ${error.message}`);
// Continue with other tabs
}
};
// Use with multiple tabs
await Promise.allSettled([
handleTabOperation(page1, page => page.click('.submit-btn')),
handleTabOperation(page2, page => page.fill('.input-field', 'data')),
handleTabOperation(page3, page => page.screenshot({ path: 'tab3.png' }))
]);
Common Use Cases
- E-commerce: Testing checkout flow with product comparison in multiple tabs
- Social Media: Managing multiple accounts or cross-posting content
- Documentation: Verifying links open correctly in new tabs
- Multi-step Workflows: Testing processes that span multiple pages
- Performance Testing: Simulating multiple concurrent user sessions
Multi-tab testing with Playwright provides powerful capabilities for testing complex web applications that require interaction across multiple browser contexts.