Playwright Frame and New Windows
This chapter introduces how to handle iframes, dialogs, new tabs, and the Playwright event system.
iframe Operations
Playwright usesframeLocator()to locate and manipulate elements within iframes.
page.frameLocator() to Locate iframes
Example
test('Operate elements in iframe', async ({ page }) => {
await page.goto('https://www.example.com/iframe-demo');
// Locate the iframe, then locate the element inside it
const iframe = page.frameLocator('#my-iframe');
// Operate the element inside the iframe
await iframe.getByRole('button', { name: 'Submit' }).click();
await iframe.getByLabel('Username').fill('example_user');
// Assert inside the iframe
await expect(iframe.getByText('Operation successful')).toBeVisible();
});
await page.goto('https://www.example.com/iframe-demo');
// Locate the iframe, then locate the element inside it
const iframe = page.frameLocator('#my-iframe');
// Operate the element inside the iframe
await iframe.getByRole('button', { name: 'Submit' }).click();
await iframe.getByLabel('Username').fill('example_user');
// Assert inside the iframe
await expect(iframe.getByText('Operation successful')).toBeVisible();
});
Get All Frames
Example
// Get all frames on the page (including the main frame and iframes)
const frames = page.frames();
console.log('The page has ', frames.length, ' frames');
frames.forEach(frame => {
console.log('Frame:', frame.name(), frame.url());
});
const frames = page.frames();
console.log('The page has ', frames.length, ' frames');
frames.forEach(frame => {
console.log('Frame:', frame.name(), frame.url());
});
Nested iframes
Playwright'sframeLocator()supports chained calls, allowing deep access into nested iframes.
Example
// Nested iframe: outer → inner → element
const innerButton = page
.frameLocator('#outer-frame')
.frameLocator('#inner-frame')
.getByRole('button', { name: 'Confirm' });
await innerButton.click();
const innerButton = page
.frameLocator('#outer-frame')
.frameLocator('#inner-frame')
.getByRole('button', { name: 'Confirm' });
await innerButton.click();
Handling Dialogs
Playwright has a default handling strategy for browser native dialogs (alert, confirm, prompt).
Default Behavior
Playwright by defaultautomatically dismissesall dialogs:
| Dialog Type | Default Behavior |
|---|---|
alert() | Automatically dismiss (close) |
confirm() | Automatically accept (returns true) |
prompt() | Automatically accept (returns empty string) |
Custom Dialog Handling
Usingpage.on('dialog')you can intercept and customize dialog handling.
Example
test('Custom dialog handling', async ({ page }) => {
// Register a listener before triggering the dialog
page.on('dialog', async dialog => {
console.log('Dialog type:', dialog.type());
console.log('Dialog message:', dialog.message());
if (dialog.type() === 'confirm') {
// Cancel the confirm dialog
await dialog.dismiss();
} else if (dialog.type() === 'prompt') {
// Enter custom content
await dialog.accept('Content entered by EXAMPLE');
} else {
// For other types, just accept
await dialog.accept();
}
});
// The operation that triggers the dialog
await page.getByRole('button', { name: 'Delete' }).click();
});
// Register a listener before triggering the dialog
page.on('dialog', async dialog => {
console.log('Dialog type:', dialog.type());
console.log('Dialog message:', dialog.message());
if (dialog.type() === 'confirm') {
// Cancel the confirm dialog
await dialog.dismiss();
} else if (dialog.type() === 'prompt') {
// Enter custom content
await dialog.accept('Content entered by EXAMPLE');
} else {
// For other types, just accept
await dialog.accept();
}
});
// The operation that triggers the dialog
await page.getByRole('button', { name: 'Delete' }).click();
});
Dialog Object Methods
| Method | Description |
|---|---|
dialog.accept(promptText?) | Accept the dialog (can pass input text for prompt) |
dialog.dismiss() | Dismiss the dialog |
dialog.message() | Get the dialog message |
dialog.type() | Get the dialog type:'alert' | 'confirm' | 'prompt' | 'beforeunload' |
New Windows and New Tabs
When clicking a link or button opens a new tab, Playwright provides multiple ways to get the new page.
page.waitForEvent('popup') to Wait for Popup
Example
test('Handle new tab', async ({ page }) => {
// Prepare to wait for the new page event before clicking
const popupPromise = page.waitForEvent('popup');
// Click the link that opens a new window
await page.getByRole('link', { name: 'Open new window' }).click();
// Get the newly opened page
const popup = await popupPromise;
// Operate on the new page
await expect(popup).toHaveTitle(/EXAMPLE/);
await popup.getByRole('button', { name: 'OK' }).click();
// Close the new page
await popup.close();
});
// Prepare to wait for the new page event before clicking
const popupPromise = page.waitForEvent('popup');
// Click the link that opens a new window
await page.getByRole('link', { name: 'Open new window' }).click();
// Get the newly opened page
const popup = await popupPromise;
// Operate on the new page
await expect(popup).toHaveTitle(/EXAMPLE/);
await popup.getByRole('button', { name: 'OK' }).click();
// Close the new page
await popup.close();
});
context.on('page') to Listen for New Pages
Example
test('Listen for all new pages in the Context', async ({ context, page }) => {
// Listen for new page creation across the entire Context
context.on('page', async newPage => {
console.log('A new page opened:', newPage.url());
// Wait for the new page to finish loading
await newPage.waitForLoadState();
// Operate on the new page
});
await page.goto('https://www.example.com/');
// Subsequent operations that open new windows will automatically trigger the above listener
});
// Listen for new page creation across the entire Context
context.on('page', async newPage => {
console.log('A new page opened:', newPage.url());
// Wait for the new page to finish loading
await newPage.waitForLoadState();
// Operate on the new page
});
await page.goto('https://www.example.com/');
// Subsequent operations that open new windows will automatically trigger the above listener
});
Playwright Event System
Playwright's Page and Context objects are event emitters, and you can listen for various events.
Common Page Events
| Event | Trigger Timing |
|---|---|
request | When the page initiates a network request |
response | When a network response is received |
dialog | When an alert/confirm/prompt dialog appears |
download | When a file download starts |
popup | When a new page (popup/new tab) opens |
console | When the page outputs a console message |
pageerror | When an uncaught JavaScript error occurs on the page |
load | When the page finishes loading |
close | When the page closes |
Event Listening Methods
Example
// Listen continuously
page.on('request', request => {
console.log('Request:', request.method(), request.url());
});
// Listen once (automatically removed after being triggered once)
page.once('dialog', dialog => {
dialog.accept();
});
// Remove listener
const handler = (request) => { /* ... */ };
page.on('request', handler);
page.off('request', handler);
page.on('request', request => {
console.log('Request:', request.method(), request.url());
});
// Listen once (automatically removed after being triggered once)
page.once('dialog', dialog => {
dialog.accept();
});
// Remove listener
const handler = (request) => { /* ... */ };
page.on('request', handler);
page.off('request', handler);