Learn Playwright - Advanced Browser Actions
Episode 8 of 23

Learn Playwright - Advanced Browser Actions

This episode covers advanced browser scenarios: handling frames, popups, and multiple tabs, drag and drop along with keyboard and mouse actions, automating file upload and download, as well as network interception and request mocking to control responses.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

End-to-end tests that only click buttons and fill forms will quickly hit their limits. Real applications use iframes, open popups, involve drag and drop, file uploads, and communicate with servers that are sometimes unreliable. This episode 8 covers the advanced actions that unlock these scenarios.

These capabilities distinguish a test suite that merely runs from a suite that truly tests the application thoroughly. You'll learn to control elements inside frames, handle new windows, simulate complex input, automate files, and control network responses as if you were a proxy between the application and its server.

Handling Frames, Popups, and Multiple Tabs

Working with Iframes

Elements inside an iframe cannot be accessed directly from page. Playwright provides page.frameLocator(), which returns a locator that operates inside a frame:

JSActions inside an iframe
const frame = page.frameLocator('#payment-iframe');
await frame.getByLabel('Card Number').fill('4111111111111111');
await frame.getByRole('button', { name: 'Pay' }).click();

page.frameLocator('#payment-iframe') returns a locator scoped to a specific frame. To handle frames you don't know in advance, use page.frames() to list all existing frames and pick as needed.

Popups and Multiple Tabs

A popup is a new page opened from the parent page. Don't wait directly with page.waitForEvent after the action — set up the listener first to avoid a race condition:

JSHandling a popup
const popupPromise = page.waitForEvent('popup');
await page.getByRole('link', { name: 'Open Policy' }).click();
const popup = await popupPromise;
await popup.getByRole('heading').waitFor();

page.waitForEvent('popup') returns a promise that resolves when the popup opens. Once you have the popup, actions can be directed to that new page instance, completely separate from the parent page.

A context allows opening several tabs and switching between them. page.bringToFront() makes a specific tab active:

JSOpen a new tab and focus it
const page2 = await context.newPage();
await page2.goto('https://example.com');
await page2.bringToFront();

Using context.newPage() creates a new tab in the same context — these tabs share session storage and cookies. It's great for testing flows that involve several tabs at once.

Drag and Drop, Keyboard, and Mouse Actions

Drag and Drop

There are two ways to drag and drop: via a dedicated method or through manual mouse actions:

JSDrag and drop with a method
await page.getByRole('listitem', { name: 'Item 1' }).dragTo(
  page.getByRole('listitem', { name: 'Target' })
);

dragTo() handles the mouse down, move, and up sequence automatically. If the application needs finer control, use page.mouse manually.

Manual Keyboard and Mouse

For special scenarios, keyboard and mouse actions can be fully controlled:

JSManual keyboard and mouse
await page.getByRole('textbox').press('Control+a');
await page.keyboard.type('new text');
await page.mouse.move(100, 200);
await page.mouse.down();
await page.mouse.move(300, 400);
await page.mouse.up();

page.keyboard.type('new text') types at the default speed, while page.mouse gives you pixel-coordinate control for complex manual drags.

File Upload and Download

File Upload

Uploads can be done with setInputFiles on a file input, or with buffer payloads for scenarios that need flexibility:

JSUpload a file and verify its name
await page.getByLabel('Upload Document').setInputFiles('report.pdf');
await expect(page.getByText('report.pdf')).toBeVisible();

setInputFiles('report.pdf') accepts a local path. Playwright also supports buffer objects to create files directly from memory — useful when test data is generated dynamically.

File Download

To catch a download, set up the event listener before triggering the download:

JSCatching a download
const downloadPromise = page.waitForEvent('download');
await page.getByRole('button', { name: 'Download Report' }).click();
const download = await downloadPromise;
await download.saveAs('./artifacts/report.pdf');

download.saveAs('./artifacts/report.pdf') saves the downloaded file to the specified location. You can check download.suggestedFilename() to validate the file name.

Network Interception and Request Mocking

Intercepting and Modifying Requests

With page.route, you can redirect requests to mocks, block certain requests, or modify them:

JSMock an API response
await page.route('**/api/products/**', (route) => {
  route.fulfill({
    status: 200,
    contentType: 'application/json',
    body: JSON.stringify([{ id: 1, name: 'Mock Product' }]),
  });
});

page.route('**/api/products/**', handler) intercepts all requests matching the URL pattern. Inside the handler, route.fulfill(...) returns a fabricated response without ever contacting the server.

Blocking Unnecessary Resources

To speed up tests, block requests for assets that aren't relevant, like fonts or analytics:

JSBlock tracking requests
await page.route('**/analytics.js', (route) => route.abort());
await page.route('**/*.woff2', (route) => route.abort());

route.abort() cancels the request so the browser doesn't download that resource. This reduces network noise and speeds up test execution on applications heavy with tracking scripts.

Run the advanced actions tests
npx playwright test tests/advanced-actions.spec.ts

The command npx playwright test tests/advanced-actions.spec.ts runs the tests that use the techniques above. When frames, popups, and network mocking are combined, the trace viewer is your best friend for verifying the order of actions.

Closing

Episode 8 expanded the reach of your tests to scenarios that used to feel hard: elements inside iframes and popups, several tabs at once, precise drag and drop and keyboard/mouse actions, file upload and download, plus network interception and request mocking to control server responses.

Key takeaways:

  • frameLocator targets elements inside iframes without leaving the locator API.
  • Set up the popup listener before triggering the action that opens a new window.
  • dragTo, page.keyboard, and page.mouse serve different levels of precision.
  • setInputFiles and waitForEvent('download') automate file exchanges.
  • page.route enables mocking, modifying, and blocking requests.

In the next episode we'll discuss data-driven and parameterized testing — parameterized tests with test.each, external data sources like CSV and JSON, running the same scenario with many datasets, and best practices for repeatable coverage.

Learn Playwright - Advanced Browser Actions | Learn Playwright