Swacblooms🦋

Making the Moves
Menu
  • Home
  • Motivation
  • Education
  • Programming
  • About
  • Contact
  • Privacy Policy
Home
Programming
Part 3 — Actions and Auto-Waiting: Putting Locators to Work
Programming

Part 3 — Actions and Auto-Waiting: Putting Locators to Work

Samson Amaugo April 13, 2026

Introduction

In Part 2 you learned how to find elements on the page. In this article, you will put those locators to work by performing actions on them — clicking, typing, hovering, selecting, uploading files, and more.

You will also learn one of Playwright’s most important features: auto-waiting. Playwright does not blindly fire an action the moment you call it. It waits until the element is ready. This is why Playwright tests are far less flaky than tests written with older tools.


Auto-Waiting — Why You Rarely Need waitFor

Before covering individual actions, it is worth understanding what happens under the hood every time you call one.

When you write:

await page.getByRole('button', { name: 'Submit' }).click();

Playwright does not just fire a click immediately. It first checks that the element:

  • Exists in the DOM
  • Is visible (not hidden with display: none or visibility: hidden)
  • Is stable (not animating or moving)
  • Is enabled (not disabled)
  • Is not obscured by another element

Only when all of those conditions are met does Playwright act. If the element is not ready yet, Playwright keeps retrying until the configured timeout is reached before failing.

This means you rarely need to write:

await page.waitForSelector('.submit-button'); // rarely needed
await page.waitForTimeout(2000);              // almost never needed

Just write the action. Playwright handles the waiting.


Clicking

click() is the most common action. It simulates a real mouse click — move, press, release.

// single click
await page.getByRole('button', { name: 'Submit' }).click();

// double click
await page.getByRole('button', { name: 'Edit' }).dblclick();

// right click (context menu)
await page.getByRole('listitem', { name: 'File' }).click({ button: 'right' });

// click a specific position within an element
await page.getByRole('canvas').click({ position: { x: 100, y: 200 } });

If the element is covered by an overlay like a cookie banner, Playwright will throw rather than silently clicking the wrong thing. Fix the root cause — dismiss the overlay first.


Typing and Filling Inputs

There are two ways to put text into an input: fill() and pressSequentially().

fill() — Use This First

fill() clears the current value and sets the new one in a single operation. It is fast and reliable.

await page.getByLabel('Email address').fill('user@example.com');
await page.getByLabel('Password').fill('secret123');

pressSequentially() — When You Need Key-by-Key Input

Some inputs respond to individual keystrokes — autocomplete dropdowns, for example. pressSequentially() types character by character, triggering keyboard events as it goes.

await page.getByLabel('Search').pressSequentially('play', { delay: 50 });

The delay option adds a pause between keystrokes in milliseconds. Without it the typing is instantaneous, which some inputs do not handle correctly.

clear() — Emptying a Field

await page.getByLabel('Username').clear();

press() — Single Key Presses

Use press() when you need to hit a specific key — Enter, Tab, Escape, or an arrow key.

await page.getByLabel('Search').press('Enter');
await page.getByRole('textbox').press('Tab');
await page.getByRole('dialog').press('Escape');

Key names follow the KeyboardEvent.key standard. Common ones:

KeyString to use
Enter'Enter'
Tab'Tab'
Escape'Escape'
Arrow keys'ArrowUp' / 'ArrowDown' / 'ArrowLeft' / 'ArrowRight'
Backspace'Backspace'
Modifier + key'Control+a', 'Meta+c'

Checkboxes and Radio Buttons

Use check() and uncheck() rather than click() for checkboxes and radio buttons. They are more explicit and Playwright verifies the resulting state.

// check a checkbox
await page.getByLabel('Remember me').check();

// uncheck it
await page.getByLabel('Remember me').uncheck();

// select a radio button
await page.getByLabel('Credit card').check();

To verify the current state:

await expect(page.getByLabel('Remember me')).toBeChecked();
await expect(page.getByLabel('Remember me')).not.toBeChecked();


Dropdowns — selectOption()

For a native <select> element, use selectOption().

// select by visible text
await page.getByLabel('Country').selectOption('United Kingdom');

// select by value attribute
await page.getByLabel('Country').selectOption({ value: 'uk' });

// select by index (zero-based)
await page.getByLabel('Country').selectOption({ index: 2 });

// select multiple options (if the select allows it)
await page.getByLabel('Interests').selectOption(['Music', 'Sport']);


Hovering

hover() moves the mouse over an element without clicking. Use it to trigger tooltips, reveal dropdown menus, or test hover states.

await page.getByRole('button', { name: 'More options' }).hover();


Focus and Blur

// move keyboard focus to an element
await page.getByLabel('Email').focus();

// remove focus
await page.getByLabel('Email').blur();


File Uploads

setInputFiles() sets files on an <input type="file"> element.

// upload a single file
await page.getByLabel('Upload document').setInputFiles('path/to/file.pdf');

// upload multiple files
await page.getByLabel('Upload photos').setInputFiles([
  'photo1.jpg',
  'photo2.jpg',
]);

// clear a previously selected file
await page.getByLabel('Upload document').setInputFiles([]);

For upload dialogs triggered by a button rather than a direct file input:

const [fileChooser] = await Promise.all([
  page.waitForEvent('filechooser'),
  page.getByRole('button', { name: 'Upload' }).click(),
]);
await fileChooser.setFiles('path/to/file.pdf');

Drag and Drop

await page.getByRole('listitem', { name: 'Task A' }).dragTo(
  page.getByRole('region', { name: 'Done' })
);

For fine-grained control:

await page.getByRole('slider').dragTo(
  page.getByRole('slider'),
  { targetPosition: { x: 200, y: 0 } }
);


Scrolling

Playwright scrolls automatically when it needs to bring an element into view before acting. For explicit scrolling:

// scroll an element into view
await page.getByRole('heading', { name: 'Pricing' }).scrollIntoViewIfNeeded();

// scroll the page by a pixel amount
await page.mouse.wheel(0, 500);


Summary

In Part 3, you learned how to interact with the page in a reliable way.

  • Playwright waits for elements to be ready before it performs an action.
  • fill() is the default choice for text inputs, while pressSequentially() is useful when key-by-key typing is required.
  • check() and uncheck() are the right tools for checkboxes and radio buttons.
  • selectOption() is used for native <select> dropdowns.
  • press() lets you send single keys and key combinations such as Control+a.
  • setInputFiles() works for file inputs, and the filechooser event pattern works for upload buttons.
  • In most tests, you can skip manual waits like waitForTimeout.

What’s Next

In Part 4 you will learn assertions — how to verify that the right things appear on the page after your actions. Playwright’s web-first assertions retry automatically, and you will learn why that matters and how to use them correctly.

Prev Article
Next Article

Related Articles

reference
Hey guys I’m back and banging and in today’s post …

React Refs the easy way

prisma and azure
Hello peeps, so in this writeup, I would be talking …

Using Prisma in Azure Functions

About The Author

Samson Amaugo

I am Samson Amaugo. I am a full-stack developer and I specialize in DotNet and the MERN stack.

Search Site

Recent Posts

  • Cloudflare Tunnel to Postgres, plus Swarm’s static IP problem
  • The Topological Sort
  • Building a Perceptron in .NET
  • Part 4 — Assertions: Verifying What You See
  • Part 3 — Actions and Auto-Waiting: Putting Locators to Work

Categories

  • EDUCATION
  • Motivation
  • Programming
  • Uncategorized

Get more stuff

Subscribe to our mailing list and get interesting stuff and updates to your email inbox.

Thank you for subscribing.

Something went wrong.

we respect your privacy and take protecting it seriously

RSS feed: Swacblooms Swacblooms

Swacblooms🦋

Making the Moves
Copyright © 2026 Swacblooms🦋
Swacblooms - Making the Moves