Pages
A Page (client/page.ts:80) represents a single tab or popup window within a browser context.
export class Page extends ChannelOwner < channels . PageChannel > {
private _browserContext : BrowserContext ;
private _mainFrame : Frame ;
private _frames = new Set < Frame >();
private _closed = false ;
private _viewportSize : Size | undefined ;
readonly keyboard : Keyboard ;
readonly mouse : Mouse ;
readonly touchscreen : Touchscreen ;
readonly request : APIRequestContext ;
}
Creating Pages
From Context
const context = await browser . newContext ();
const page = await context . newPage ();
Shortcut (Creates Context + Page)
const page = await browser . newPage ();
// Equivalent to:
// const context = await browser.newContext();
// const page = await context.newPage();
From client/browser.ts:137:
async newPage ( options : BrowserContextOptions = {}): Promise < Page > {
return await this._wrapApiCall( async () => {
const context = await this . newContext ( options );
const page = await context . newPage ();
page . _ownedContext = context ; // Context owned by this page
context . _ownerPage = page ;
return page ;
}, { title : 'Create page' });
}
Page Lifecycle
Page Creation
const page = await context . newPage ();
Navigation
await page . goto ( 'https://example.com' );
await page . waitForLoadState ( 'networkidle' );
Interaction
await page . click ( '#button' );
await page . fill ( 'input[name="email"]' , '[email protected] ' );
Navigation
Basic Navigation
// Navigate to URL
await page . goto ( 'https://example.com' );
// Wait for load state
await page . goto ( 'https://example.com' , {
waitUntil: 'networkidle'
});
// Navigate with timeout
await page . goto ( 'https://example.com' , {
timeout: 60000 // 60 seconds
});
Navigation Options
From client/frame.ts:111-115:
async goto ( url : string , options : FrameGotoOptions = {}) : Promise < Response | null > {
const waitUntil = verifyLoadState ( 'waitUntil' , options . waitUntil === undefined ? 'load' : options . waitUntil );
this . page (). context (). _checkUrlAllowed ( url );
return Response . fromNullable (( await this . _channel . goto ({ url , ... options , waitUntil , timeout: this . _navigationTimeout ( options ) })). response );
}
Wait states:
load - Page load event fired (default)
domcontentloaded - DOM is ready
networkidle - No network connections for 500ms
commit - Navigation committed
History Navigation
// Go back
await page . goBack ();
// Go forward
await page . goForward ();
// Reload
await page . reload ();
Wait for Navigation
// Click and wait for navigation
const [ response ] = await Promise . all ([
page . waitForNavigation (),
page . click ( 'a.link' )
]);
// Wait for specific URL
await page . waitForURL ( '**/dashboard' );
// Wait for URL pattern
await page . waitForURL ( / \/ user \/ \d + / );
Frames
Frames represent the main document or iframes within a page.
export class Frame extends ChannelOwner < channels . FrameChannel > {
_parentFrame : Frame | null = null ;
_url = '' ;
_name = '' ;
_detached = false ;
_childFrames = new Set < Frame >();
_page : Page | undefined ;
}
Accessing Frames
// Main frame
const mainFrame = page . mainFrame ();
// All frames
const frames = page . frames ();
// Find frame by name
const frame = page . frame ({ name: 'myframe' });
// Find frame by URL
const frame = page . frame ({ url: / . * example . com . * / });
Frame Hierarchy
// Get child frames
const childFrames = frame . childFrames ();
// Get parent frame
const parentFrame = frame . parentFrame ();
// Check if detached
if ( frame . isDetached ()) {
console . log ( 'Frame no longer exists' );
}
From client/page.ts:174-188:
private _onFrameAttached ( frame : Frame ) {
frame . _page = this ;
this . _frames . add ( frame );
if ( frame . _parentFrame )
frame . _parentFrame . _childFrames . add ( frame );
this . emit ( Events . Page . FrameAttached , frame );
}
private _onFrameDetached ( frame : Frame ) {
this . _frames . delete ( frame );
frame . _detached = true ;
if ( frame . _parentFrame )
frame . _parentFrame . _childFrames . delete ( frame );
this . emit ( Events . Page . FrameDetached , frame );
}
Working with Frames
// Interact with main frame
await page . mainFrame (). click ( '#button' );
// Interact with specific frame
const frame = page . frame ({ name: 'iframe1' });
await frame . fill ( 'input' , 'value' );
// Wait for frame to load
await frame . waitForLoadState ( 'load' );
FrameLocator
A modern way to work with iframes:
// Locate iframe
const frameLocator = page . frameLocator ( 'iframe#myframe' );
// Interact with elements inside iframe
await frameLocator . locator ( 'button' ). click ();
await frameLocator . getByRole ( 'textbox' ). fill ( 'text' );
// Nested iframes
const nested = page
. frameLocator ( 'iframe#outer' )
. frameLocator ( 'iframe#inner' )
. locator ( 'button' );
From client/locator.ts:405:
export class FrameLocator implements api . FrameLocator {
private _frame : Frame ;
private _frameSelector : string ;
locator ( selector : string , options ?: LocatorOptions ) : Locator {
return new Locator (
this . _frame ,
this . _frameSelector + ' >> internal:control=enter-frame >> ' + selector ,
options
);
}
}
FrameLocator is recommended over page.frame() as it automatically waits and handles frame lifecycle.
Page Properties
URL
const url = page . url ();
console . log ( 'Current URL:' , url );
Title
const title = await page . title ();
console . log ( 'Page title:' , title );
Content
// Get HTML content
const html = await page . content ();
// Set HTML content
await page . setContent ( '<html><body>Hello</body></html>' );
Viewport
// Get viewport size
const viewport = page . viewportSize ();
console . log ( viewport ); // { width: 1280, height: 720 }
// Set viewport size
await page . setViewportSize ({ width: 1920 , height: 1080 });
Page Events
// Page loaded
page . on ( 'load' , () => {
console . log ( 'Page loaded' );
});
// DOM content loaded
page . on ( 'domcontentloaded' , () => {
console . log ( 'DOM ready' );
});
// New page/popup opened
page . on ( 'popup' , popup => {
console . log ( 'New popup:' , popup . url ());
});
// Console message
page . on ( 'console' , msg => {
console . log ( 'Console:' , msg . type (), msg . text ());
});
// Dialog (alert, confirm, prompt)
page . on ( 'dialog' , dialog => {
console . log ( 'Dialog:' , dialog . message ());
dialog . accept ();
});
// Request made
page . on ( 'request' , request => {
console . log ( 'Request:' , request . url ());
});
// Response received
page . on ( 'response' , response => {
console . log ( 'Response:' , response . url (), response . status ());
});
// Page closed
page . on ( 'close' , () => {
console . log ( 'Page closed' );
});
// Page crashed
page . on ( 'crash' , () => {
console . log ( 'Page crashed' );
});
Popup Handling
// Wait for popup
const [ popup ] = await Promise . all ([
page . waitForEvent ( 'popup' ),
page . click ( 'a[target="_blank"]' )
]);
await popup . waitForLoadState ();
console . log ( 'Popup URL:' , popup . url ());
await popup . close ();
Dialog Handling
// Handle alert/confirm/prompt
page . on ( 'dialog' , async dialog => {
console . log ( 'Dialog type:' , dialog . type ());
console . log ( 'Dialog message:' , dialog . message ());
if ( dialog . type () === 'confirm' ) {
await dialog . accept ();
} else if ( dialog . type () === 'prompt' ) {
await dialog . accept ( 'my input' );
} else {
await dialog . dismiss ();
}
});
// Trigger dialog
await page . evaluate (() => alert ( 'Hello' ));
Workers
Access Web Workers and Service Workers:
// Web Workers
page . on ( 'worker' , worker => {
console . log ( 'Worker created:' , worker . url ());
worker . on ( 'console' , msg => {
console . log ( 'Worker console:' , msg . text ());
});
});
const workers = page . workers ();
// Service Workers (from context)
context . on ( 'serviceworker' , worker => {
console . log ( 'Service Worker:' , worker . url ());
});
Multiple Pages
const context = await browser . newContext ();
// Create multiple pages
const page1 = await context . newPage ();
const page2 = await context . newPage ();
const page3 = await context . newPage ();
// They share cookies and storage
await page1 . goto ( 'https://example.com/login' );
await page1 . fill ( '#username' , 'user' );
await page1 . click ( '#login' );
// page2 is also logged in (same context)
await page2 . goto ( 'https://example.com/dashboard' );
// Get all pages in context
const pages = context . pages ();
console . log ( `Total pages: ${ pages . length } ` );
Page Isolation
Pages within the same context share state:
const context = await browser . newContext ();
const page1 = await context . newPage ();
const page2 = await context . newPage ();
// Set cookie on page1
await page1 . goto ( 'https://example.com' );
await context . addCookies ([{
name: 'session' ,
value: 'abc123' ,
domain: 'example.com' ,
path: '/'
}]);
// page2 has the same cookie
await page2 . goto ( 'https://example.com' );
const cookies = await context . cookies ();
// Both pages see the session cookie
Viewport and Emulation
// Mobile emulation
const iPhone = devices [ 'iPhone 13' ];
const context = await browser . newContext ({
... iPhone
});
const page = await context . newPage ();
// Custom viewport
await page . setViewportSize ({
width: 1920 ,
height: 1080
});
// Media emulation
await page . emulateMedia ({
colorScheme: 'dark' ,
reducedMotion: 'reduce'
});
Screenshots
// Full page screenshot
await page . screenshot ({ path: 'screenshot.png' });
// Viewport screenshot
await page . screenshot ({
path: 'viewport.png' ,
fullPage: false
});
// Specific element
await page . locator ( '#header' ). screenshot ({
path: 'header.png'
});
PDF Generation
// Generate PDF (Chromium only)
await page . pdf ({
path: 'page.pdf' ,
format: 'A4' ,
margin: {
top: '1cm' ,
right: '1cm' ,
bottom: '1cm' ,
left: '1cm'
}
});
Accessibility
// Get accessibility tree
const snapshot = await page . accessibility . snapshot ();
console . log ( JSON . stringify ( snapshot , null , 2 ));
// Get performance metrics (Chromium only)
const metrics = await page . metrics ();
console . log ( metrics );
// { Timestamp, Documents, Frames, JSEventListeners, ... }
Best Practices
Always wait for appropriate load state after navigation. await page . goto ( 'https://example.com' , {
waitUntil: 'networkidle' // Wait for network to be idle
});
Use FrameLocator for iframe interactions. // Better than page.frame()
const frameLocator = page . frameLocator ( 'iframe' );
await frameLocator . locator ( 'button' ). click ();
Set up event listeners before triggering actions. // Setup listener first
const popupPromise = page . waitForEvent ( 'popup' );
// Then trigger
await page . click ( 'a[target="_blank"]' );
// Then wait
const popup = await popupPromise ;
Frame vs FrameLocator
Feature Frame FrameLocator Auto-waiting No Yes Retries No Yes Lifecycle handling Manual Automatic Recommended Legacy Modern
// Old way
const frame = page . frame ({ name: 'myframe' });
if ( frame ) {
await frame . click ( 'button' );
}
// New way (recommended)
const frame = page . frameLocator ( 'iframe[name="myframe"]' );
await frame . locator ( 'button' ). click ();
Next Steps
Selectors Learn how to find elements
Auto-waiting Understanding automatic waiting
Locators Working with locators