1. What Are Actions and Interactions?
Automation is not only about finding elements. A real test must interact with the application exactly as a real user would: click buttons, enter information, select values, upload files, navigate between pages, and interact with dynamic components.
2. Types of Playwright Actions
Click
Click buttons, links, cards and controls.
CoreFill
Quickly enter values into input controls.
CoreType
Simulate sequential keyboard input when required.
UsefulCheck / Uncheck
Interact with checkboxes and similar controls.
FormsRadio Buttons
Select a single option from a group.
FormsSelect Option
Select values from native HTML select controls.
FormsHover
Trigger menus, tooltips and hover-based components.
UIKeyboard
Press Enter, Tab, Escape, shortcuts and key combinations.
AdvancedMouse
Perform low-level mouse movements, clicks and coordinates.
AdvancedDrag & Drop
Move an element from one location to another.
InteractionFile Upload
Upload documents, images and test files.
Real-TimeDialogs
Handle alerts, confirmations and prompts.
Advanced3. Click Action
Clicking is one of the most common browser interactions.
page.get_by_role(
"button",
name="Login"
).click()
Click a Link
page.get_by_role(
"link",
name="Dashboard"
).click()
4. Fill Text Input
For most text inputs, fill() is the preferred way
to enter a value.
page.get_by_label("Username").fill("john.smith")
page.get_by_label("Password").fill("TestPassword123")
5. Type Text Character by Character
Use keyboard typing when the application specifically needs individual key events or typing behavior.
page.get_by_label(
"Search"
).press_sequentially("Playwright")
fill().
Use sequential keyboard input when the application's behavior
depends on individual key events.
6. Clear Existing Text
search = page.get_by_placeholder(
"Search products"
)
search.fill("Laptop")
search.fill("")
Using fill("") is usually simpler than manually
selecting and deleting the existing value.
7. Checkbox Interaction
Playwright provides dedicated methods for checkbox controls.
page.get_by_label(
"Accept Terms"
).check()
Uncheck
page.get_by_label(
"Accept Terms"
).uncheck()
Verify State
from playwright.sync_api import expect
expect(
page.get_by_label("Accept Terms")
).to_be_checked()
8. Radio Button Interaction
page.get_by_label("Credit Card").check()
page.get_by_label("PayPal").check()
9. Select Dropdown Option
For a native HTML <select> element,
Playwright provides select_option().
page.get_by_label(
"Country"
).select_option("IN")
Select by Visible Label
page.get_by_label(
"Country"
).select_option(
label="India"
)
<select> controls. For custom dropdowns,
interact with the visible component just as the user would.
10. Custom Dropdown Interaction
Modern applications often use custom dropdown components instead of native select elements.
page.get_by_role(
"combobox",
name="Country"
).click()
page.get_by_role(
"option",
name="India"
).click()
11. Hover Interaction
Hover is useful for menus, tooltips and actions that appear when the mouse moves over an element.
page.get_by_role(
"button",
name="Products"
).hover()
page.get_by_role(
"link",
name="Laptops"
).click()
12. Keyboard Actions
Press Enter
page.get_by_placeholder(
"Search"
).press("Enter")
Press Escape
page.keyboard.press("Escape")
Keyboard Shortcut
page.keyboard.press("Control+A")
page.keyboard.press("Control+C")
13. Mouse Actions
Playwright also exposes a mouse API for advanced interactions.
page.mouse.move(500, 300) page.mouse.click(500, 300)
14. Double Click
page.get_by_text(
"Customer Report"
).dblclick()
Useful for applications where double-click opens an editor, record, document or detail view.
15. Right Click / Context Menu
page.get_by_text(
"Customer Record"
).click(button="right")
16. Drag and Drop
Drag-and-drop is common in dashboards, kanban boards and file management applications.
source = page.get_by_text("Task A")
target = page.get_by_text("Done")
source.drag_to(target)
drag_to() when the application supports a
standard draggable interaction. It is clearer and more maintainable
than manually calculating mouse coordinates.
17. File Upload
Playwright can upload files without interacting with the operating system's native file picker.
page.get_by_label(
"Upload Document"
).set_input_files(
"test-data/invoice.pdf"
)
Multiple Files
page.get_by_label(
"Upload Documents"
).set_input_files([
"test-data/invoice.pdf",
"test-data/receipt.pdf"
])
18. File Download
Downloads can be captured using Playwright's download event.
with page.expect_download() as download_info:
page.get_by_role(
"button",
name="Download Report"
).click()
download = download_info.value
download.save_as(
"downloads/report.pdf"
)
19. Browser Dialogs — Alert, Confirm and Prompt
JavaScript dialogs such as alert(),
confirm() and prompt() are handled
using the dialog event.
Accept Dialog
def handle_dialog(dialog):
print(dialog.message)
dialog.accept()
page.on("dialog", handle_dialog)
page.get_by_role(
"button",
name="Delete"
).click()
Dismiss Confirmation
def handle_dialog(dialog):
dialog.dismiss()
page.on("dialog", handle_dialog)
20. New Tab / Popup Interaction
Applications often open reports, payment pages or external systems in a new tab.
with page.expect_popup() as popup_info:
page.get_by_role(
"link",
name="Open Report"
).click()
popup = popup_info.value
popup.wait_for_load_state()
print(popup.title())
21. Multiple Tabs
pages_before = len(context.pages)
page.get_by_role(
"link",
name="Open Report"
).click()
page.wait_for_timeout(500)
pages_after = len(context.pages)
print(
"Pages:",
pages_after
)
expect_popup() when the action is known to open a popup.
Avoid fixed sleeps as the synchronization mechanism.
22. Interaction Inside iframe
Embedded payment forms, support widgets and third-party components can live inside an iframe.
payment = page.frame_locator(
"#payment-frame"
)
payment.get_by_label(
"Card number"
).fill("4111111111111111")
payment.get_by_label(
"Expiry"
).fill("12/30")
23. Scrolling
Playwright can scroll an element into view as part of interaction. You can also explicitly scroll a locator when needed.
footer = page.get_by_text(
"Terms and Conditions"
)
footer.scroll_into_view_if_needed()
footer.click()
24. What Happens When an Element Is Hidden?
Suppose the button exists in the DOM but is initially hidden.
page.get_by_role(
"button",
name="Submit"
).click()
Playwright waits for the locator's target to satisfy the conditions required for the action. It does not mean that every arbitrary page condition will automatically be understood, so application-specific state may still need explicit assertions or event synchronization.
25. Disabled Elements
If an element is disabled, a normal interaction should not silently pretend that the user successfully clicked it.
from playwright.sync_api import expect
submit = page.get_by_role(
"button",
name="Submit"
)
expect(submit).to_be_disabled()
After the required information is entered:
page.get_by_label(
"Email"
).fill("user@example.com")
expect(submit).to_be_enabled()
submit.click()
26. How Playwright Makes Actions Robust
Before performing an action, Playwright performs actionability checks appropriate to that action.
27. Auto-Waiting vs Hard Sleep
❌ Fragile Approach
import time
time.sleep(5)
page.get_by_role(
"button",
name="Submit"
).click()
✅ Better Approach
from playwright.sync_api import expect
submit = page.get_by_role(
"button",
name="Submit"
)
expect(submit).to_be_enabled()
submit.click()
28. Should You Use force=True?
Playwright provides a force option for some actions.
page.get_by_role(
"button",
name="Submit"
).click(force=True)
29. Real-Time Example — Login Interaction
from playwright.sync_api import expect
def login(page, username, password):
page.get_by_label(
"Username"
).fill(username)
page.get_by_label(
"Password"
).fill(password)
page.get_by_role(
"button",
name="Sign In"
).click()
expect(
page.get_by_role(
"heading",
name="Dashboard"
)
).to_be_visible()
30. Real-Time Example — E-Commerce Checkout
product = page.locator(
".product-card"
).filter(
has_text="Laptop"
)
product.get_by_role(
"button",
name="Add to Cart"
).click()
page.get_by_role(
"link",
name="Cart"
).click()
page.get_by_role(
"button",
name="Checkout"
).click()
page.get_by_label(
"Address"
).fill("123 Main Street")
page.get_by_role(
"button",
name="Place Order"
).click()
expect(
page.get_by_text(
"Order placed successfully"
)
).to_be_visible()
31. Real-Time Example — Kanban Board
Imagine a project management application with columns: To Do, In Progress and Done.
task = page.get_by_text(
"Implement Login API"
)
done_column = page.get_by_test_id(
"kanban-done"
)
task.drag_to(done_column)
Then verify the result:
expect(
done_column.get_by_text(
"Implement Login API"
)
).to_be_visible()
32. Real-Time Example — Upload Document
page.get_by_label(
"Upload Document"
).set_input_files(
"test-data/customer-contract.pdf"
)
page.get_by_role(
"button",
name="Upload"
).click()
expect(
page.get_by_text(
"Upload completed"
)
).to_be_visible()
33. Professional Interaction Pattern
A scalable automation framework separates locating, interaction and verification into reusable page objects or components.
from playwright.sync_api import Page
class LoginPage:
def __init__(self, page: Page):
self.page = page
self.username = page.get_by_label(
"Username"
)
self.password = page.get_by_label(
"Password"
)
self.sign_in = page.get_by_role(
"button",
name="Sign In"
)
def login(self, username, password):
self.username.fill(username)
self.password.fill(password)
self.sign_in.click()
Test
def test_login(page):
login = LoginPage(page)
login.login(
"testuser",
"TestPassword123"
)
34. Playwright Action Cheat Sheet
| Interaction | Playwright Python | Typical Usage |
|---|---|---|
| Click | locator.click() |
Buttons, links, controls |
| Double Click | locator.dblclick() |
Editors, records |
| Fill | locator.fill() |
Text inputs |
| Sequential typing | locator.press_sequentially() |
Keyboard-driven UI |
| Check | locator.check() |
Checkbox/radio controls |
| Uncheck | locator.uncheck() |
Checkbox controls |
| Select | locator.select_option() |
Native select |
| Hover | locator.hover() |
Menus/tooltips |
| Keyboard | locator.press() |
Keys and shortcuts |
| Mouse | page.mouse.* |
Advanced interaction |
| Drag & Drop | locator.drag_to() |
Kanban/components |
| Upload | set_input_files() |
File upload |
| Download | expect_download() |
File download |
| Popup | expect_popup() |
New tab/window |
| iframe | frame_locator() |
Embedded application |
| Dialog | page.on("dialog") |
Alert/confirm/prompt |
35. How to Build Robust Interactions
- Use stable locators before performing actions.
- Prefer user-facing roles, labels and intentional test IDs.
- Let Playwright perform its normal actionability checks.
- Use web-first assertions to verify dynamic application state.
- Avoid fixed sleeps as the normal synchronization mechanism.
- Avoid coordinate-based mouse actions unless they are genuinely required.
- Use event-based synchronization for popups and downloads.
-
Use
frame_locator()for iframe content. -
Use dedicated methods such as
check(),select_option()andset_input_files()rather than simulating unnecessary low-level operations. -
Treat
force=Trueas an exceptional tool, not a standard workaround.
36. Fragile vs Robust Interaction
❌ Fragile
import time time.sleep(5) page.mouse.click(834, 612)
✅ Robust
page.get_by_role(
"button",
name="Submit Order"
).click()
37. Complete Real-Time Workflow
from playwright.sync_api import expect
def test_customer_order(page):
# 1. Navigate
page.goto("https://example.com/login")
# 2. Fill
page.get_by_label(
"Username"
).fill("testuser")
page.get_by_label(
"Password"
).fill("TestPassword123")
# 3. Click
page.get_by_role(
"button",
name="Sign In"
).click()
# 4. Wait through a web-first assertion
expect(
page.get_by_role(
"heading",
name="Dashboard"
)
).to_be_visible()
# 5. Interact with application
page.get_by_role(
"link",
name="Orders"
).click()
# 6. Locate specific order
order = page.locator(
"tr"
).filter(
has_text="ORD-10025"
)
# 7. Open order
order.get_by_role(
"button",
name="View"
).click()
# 8. Verify result
expect(
page.get_by_role(
"heading",
name="Order Details"
)
).to_be_visible()
38. Professional Mindset for Actions
❌ Don't
Click coordinates because the button happens to be at a specific screen location.
❌ Don't
Add five seconds of sleep before every action just because the application is dynamic.
✅ Do
Locate the intended element and let Playwright handle normal actionability waiting.
❌ Don't
Use force-click to hide an underlying UI problem.
❌ Don't
Treat every interaction as a low-level mouse operation.
✅ Do
Use Playwright's high-level APIs such as click, fill, check, select_option and drag_to.
39. Final Mental Model
The goal is to make the test interact with the application in a predictable, readable and user-oriented way while allowing Playwright to handle normal synchronization and actionability.
40. Next Learning Step
Next → Assertions
Learn web-first assertions for text, visibility, URLs, attributes, values, state and application behavior.
Then → Waits
Understand auto-waiting, explicit waits, network synchronization, events and dynamic application behavior.
Professional → Page Object Model
Build reusable components and page objects that combine robust locators, actions and assertions.