Now that you understand Playwright’s core components Browser, Context, Page, and Locator, it’s time to start performing real interactions on web pages. In this chapter, you’ll learn how to simulate user actions: clicking buttons, typing into inputs, selecting dropdown options, and navigating between pages.
These actions are the heart of browser automation. Once you master them, you can automate virtually any user flow from login forms to full checkout processes.
Understanding Playwright’s auto-waiting behavior
Before we dive into examples, there’s one powerful feature you need to understand: auto-waiting.
Playwright automatically waits for elements to:
- Appear in the DOM.
- Be visible and stable (not moving or hidden).
- Be ready for interaction.
That means you don’t have to use sleep() or arbitrary delays like in other tools, Playwright does it for you.
For example:
await page.click('button#submit');
Even if the button appears a second later, Playwright waits automatically until it’s ready to click.
1. Navigating to a webpage
The simplest action is navigation, opening a URL.
await page.goto('https://example.com');
You can also wait for navigation events explicitly:
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
Common waitUntil options:
| Option | Description |
|---|---|
load | Wait until the load event fires (default) |
domcontentloaded | Wait until HTML is parsed |
networkidle | Wait until there are no active network requests |
2. Clicking elements
Clicking buttons and links is one of the most common actions.
Example:
await page.click('text=Get Started');
This line finds an element with visible text “Get Started” and clicks it.
You can use many selector types:
await page.click('#login-button'); // by ID
await page.click('.submit'); // by class
await page.click('[data-testid="signup"]'); // by data attribute
Tip: Always prefer data-testid attributes or role-based selectors for stable tests.
You can also chain locators:
await page.locator('#form').locator('button').click();
3. Typing and filling input fields
Typing text into fields is easy using fill() or type().
await page.fill('#username', 'test_user');
await page.fill('#password', 'SecretPass123');
await page.click('button[type="submit"]');
fill() vs. type()
| Method | Description |
fill() | Clears the input first, then enters text instantly |
type() | Types each character one by one (can simulate typing speed) |
Example of type() with delay:
await page.type('#search', 'Playwright', { delay: 100 }); // 100ms per key
4. Selecting dropdown options
You can handle dropdowns (HTML <select> elements) using selectOption().
Example:
await page.selectOption('#country', 'US');
If your dropdown uses labels instead of values, you can select by label or index:
await page.selectOption('#country', { label: 'India' });
await page.selectOption('#country', { index: 3 });
5. Checking and unchecking checkboxes
To toggle checkboxes or radio buttons:
await page.check('#accept-terms');
await page.uncheck('#subscribe-newsletter');
You can verify their state:
const isChecked = await page.isChecked('#accept-terms');
console.log('Checkbox checked:', isChecked);
6. Hovering over elements
Sometimes you need to hover to reveal dropdowns or tooltips:
await page.hover('text=More Options');
You can combine hover and click:
await page.hover('#menu');
await page.click('#submenu-item');
7. Handling links and navigation
When clicking links that trigger navigation, Playwright automatically waits for the page to load, but you can also handle it manually using Promise.all():
await Promise.all([
page.waitForNavigation(),
page.click('text=About Us')
]);
This ensures Playwright doesn’t move on before the new page loads.
8. Waiting for elements
Although Playwright auto-waits, sometimes you may want to wait explicitly:
await page.waitForSelector('#dashboard');
Or wait for a network event:
await page.waitForResponse('**/api/data');
Avoid using
waitForTimeout()(sleep). It makes tests slow and flaky.
9. Assertions after actions
After performing actions, use assertions to confirm results:
import { test, expect } from '@playwright/test';
test('user can log in', async ({ page }) => {
await page.goto('https://example.com/login');
await page.fill('#username', 'john_doe');
await page.fill('#password', '123456');
await page.click('button[type="submit"]');
await expect(page).toHaveURL(/dashboard/);
await expect(page.locator('h1')).toHaveText('Welcome, John!');
});
This test verifies both navigation and page content.
Putting it all together
Let’s combine everything into a realistic example:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: false, slowMo: 200 });
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://www.demoblaze.com');
// Navigate to login
await page.click('#login2');
// Fill credentials
await page.fill('#loginusername', 'testuser');
await page.fill('#loginpassword', 'password123');
// Submit form
await page.click('button[onclick="logIn()"]');
// Wait and verify login success
await page.waitForTimeout(2000); // demo site delay only
console.log('Login attempted');
await browser.close();
})();
This script launches a real browser, navigates to a demo site, performs login steps, and prints confirmation.
Common pitfalls and solutions
| Issue | Cause | Solution |
| Element not clickable | Overlapping animation or hidden state | Use await locator.scrollIntoViewIfNeeded() or wait for visibility |
| Input not filled | Wrong selector | Use stable data-testid selectors |
| Navigation too early | Click triggers page change | Use Promise.all([page.waitForNavigation(), page.click(...)]) |
Exercise
Task 1: Automate a login form on any sample website.
Task 2: Fill in text fields, click a button, and take a screenshot of the success message.
Bonus: Use hover() and check() in your test.
Cheat Sheet
| Action | Code Example |
| Navigate to URL | await page.goto('https://example.com') |
| Click | await page.click('text=Submit') |
| Fill input | await page.fill('#username', 'john') |
| Type slowly | await page.type('#search', 'Playwright', { delay: 100 }) |
| Select dropdown | await page.selectOption('#country', 'US') |
| Check checkbox | await page.check('#terms') |
| Hover element | await page.hover('#menu') |
| Wait for element | await page.waitForSelector('#dashboard') |
| Assert title | await expect(page).toHaveTitle(/Dashboard/) |
Summary
In this chapter, you learned how to:
- Navigate to pages and perform basic actions (click, type, select).
- Use Playwright’s auto-waiting to avoid flakiness.
- Combine interactions with assertions for reliable tests.
- Handle navigation and form submissions gracefully.
These skills will serve as the building blocks for real-world test automation.
