Ever clicked a link in a web app and suddenly you're in a new tab or window?
That exact moment is where most automation tests go, “Wait, where did my browser go?”
Well, not anymore. 😎
Today, I’m going to walk you through how to handle multiple tabs/windows using Playwright and yes, it’s way easier than you think!
🧪 The Real-Life Scenario
While playing around with OrangeHRM's demo site(https://opensource-demo.orangehrmlive.com/), I noticed something interesting:
There’s a link on the login page that says "OrangeHRM Website" — and when you click it… boom! New tab opens with the company's homepage.
Perfect use case to try out multiple window handling in Playwright! 🧠
🚀 Warm-up: Managing Multiple Pages Manually
First, let’s create two separate tabs and visit two different pages. Simple but useful!
test('Handle pages like a multitasking pro', async () => {
const browser = await chromium.launch();
const context = await browser.newContext();
// Create two blank pages in the same browser context
const page1 = await context.newPage();
const page2 = await context.newPage();
// Let's see how many pages we've got (spoiler: 2)
const allPages = context.pages();
console.log(`Number of pages: ${allPages.length}`); // Output: 2
// Navigate each page to different URLs
await page1.goto('https://opensource-demo.orangehrmlive.com/web/index.php/auth/login');
await page2.goto('https://www.orangehrm.com/');
// Validate titles like a boss
await expect(page1).toHaveTitle('OrangeHRM');
await expect(page2).toHaveTitle('Human Resources Management Software | OrangeHRM HR Software');
});
📌 We created two pages (tabs), navigated to different URLs, and validated the titles. Classic multitasking!
💥 Real Magic: Catching the Popup Like a Ninja
Let’s get to the fun part — clicking a link that opens a new tab and making sure your test doesn’t freak out.
test('Handle surprise windows without screaming', async () => {
const browser = await chromium.launch();
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://opensource-demo.orangehrmlive.com/web/index.php/auth/login');
// Set up a listener BEFORE clicking the link
const [childPage] = await Promise.all([
context.waitForEvent('page'), // Wait for the new page event
page.locator('a[href="http://www.orangehrm.com"]').click() // Click the link
]);
// Wait for the new page to finish loading
await newPage.waitForLoadState();
console.log(`New page URL: ${newPage.url()}`);
await expect(newPage).toHaveTitle('Human Resources Management Software | OrangeHRM HR Software');
});
🧠 What Just Happened?
Let’s break that down:
`context.waitForEvent('page')` | Listens for a new tab to open
`Promise.all([...])` | Ensures the click and event listener sync up
`childPage.waitForLoadState()` | Waits for the new tab to fully load
`childPage.url()`+`toHaveTitle()`| Verifies the content of the new tab
It’s like having Spidey-sense for popups! 🕷️
🔑 Bonus Tip
You can also do this instead if you like things a bit more step-by-step:
const pagePromise = context.waitForEvent('page');
await page.click('text=OrangeHRM Website');
const childPage = await pagePromise;
Both approaches are valid — use whichever feels more readable for your project!
🧩 Why This Is Super Useful
✅ External links (terms and conditions, privacy policies)
✅ Payment gateway flows (Wise, PayPal, etc.)
✅ OAuth logins (Sign in with Google, GitHub, etc.)
✅ Any situation where a new window gets launched 🚀
🏁 Final Thoughts
Working with multiple windows used to be a huge headache in automation, but Playwright makes it feel like magic🪄.
🙋♀️ Next time an app throws a new tab at you, channel your inner Playwright wizard. Wave your code wand, murmur context.waitForEvent('page'), and watch the chaos unfold—calmly, from your terminal. 🧙♂️
Comments
Post a Comment