Chapter 10 · Forms and Complex Component Interaction
Chapter goals: Master automation methods for dropdowns, checkboxes, file uploads, and native dialogs; distinguish the适用 boundaries of
fillvspress_sequentially; learn to handle date pickers — the "hardest professional" of widget automation.
10.1 Dropdown and Selection Controls
Native <select> is handled by select_option, supporting value, label, or index targeting, plus multi-select:
# Single select: match by value or label
page.get_by_label("Choose a color").select_option("blue")
page.get_by_label("Choose a color").select_option(label="Blue")
# Multi-select: pass a list
page.get_by_label("Choose multiple colors").select_option(["red", "green", "blue"])
# By index
page.get_by_label("Choose a color").select_option(index=2)Checkboxes and radio buttons use check() / uncheck() / set_checked(bool) uniformly — set_checked works for input[type=checkbox], input[type=radio], and [role=checkbox]:
page.get_by_label("I agree to the terms above").check()
expect(page.get_by_label("Subscribe to newsletter")).to_be_checked()
page.get_by_label("XL").set_checked(True) # Idempotent: no-op if already in that state10.2 Three Ways to Upload Files
Method 1 (most common): set files directly on <input type="file"> — no system dialog needed:
# Single file
page.get_by_label("Upload file").set_input_files("myfile.pdf")
# Multiple files
page.get_by_label("Upload files").set_input_files(["file1.txt", "file2.txt"])
# Entire directory
page.get_by_label("Upload directory").set_input_files("mydir")
# Clear selected files
page.get_by_label("Upload file").set_input_files([])Method 2: upload a Buffer from memory — especially useful for "generate report then upload" flows:
page.get_by_label("Upload file").set_input_files(
files=[{"name": "test.txt", "mimeType": "text/plain", "buffer": b"hello e2e"}]
)Method 3: the input is dynamically created after a click; catch the system file chooser event with expect_file_chooser:
with page.expect_file_chooser() as fc_info:
page.get_by_text("Choose file").click()
fc_info.value.set_files("myfile.pdf") # Also accepts a list or Buffer10.3 Native Dialogs: alert / confirm / prompt
Playwright auto-dismisses all dialogs by default. To accept input or click OK, you must register a dialog handler before triggering the action:
# Auto-accept all confirms/alerts
page.on("dialog", lambda dialog: dialog.accept())
# prompt requires input text; handle by type separately
def handle(dialog):
if dialog.type == "prompt":
dialog.accept("John")
else:
dialog.accept()
page.on("dialog", handle)
page.get_by_role("button", name="Delete").click()Listeners must actually handle the dialog
The official docs explicitly warn: a callback registered with page.on("dialog") that only prints without calling accept/dismiss will permanently deadlock — web dialogs are modal and block page execution. Reading dialog.message without handling is the most common mistake.
10.4 fill, press_sequentially, and Keyboard Operations
fill sets the value directly and fires input events (clears existing content first) — it is the default choice for <input>, <textarea>, and [contenteditable]. When you need to simulate real keypresses one by one (autocomplete that counts keydown events, mask inputs), use press_sequentially — it is the successor to the deprecated type() method:
page.get_by_role("textbox").fill("Peter") # Set value in one shot
page.locator("#area").press_sequentially("Hello!", delay=50) # Type key by key
# Combo keys and function keys
page.get_by_text("Submit").press("Enter")
page.get_by_role("textbox").press("Control+ArrowRight")
# Hover and drag
page.get_by_text("Item").hover()
source.drag_to(page.get_by_role("listitem", name="done")) # locator.drag_toThe essential difference: fill is "set value"; press_sequentially is a full keyboard event sequence (keydown/keypress/keyup). Typing into a plain input box key-by-key only wastes test time.
10.5 Date Picker Strategies
Date controls fall into two categories with completely different strategies:
- Native
<input type="date">: justfillthe standard format string — do not click the calendar panel:pythonpage.get_by_label("Birth date").fill("2020-02-02") page.get_by_label("Appointment time").fill("13:15") # Time page.get_by_label("Local time").fill("2020-03-02T05:15") # Local datetime - JS calendar components (Element UI, Ant Design, etc.): first check if the input accepts typed input (focus +
fill); if you must click, locate the year/month toggle buttons and loop-click to the target month, thenget_by_role("cell", name=...)to click the specific date. Never hard-code coordinates — they break on any resolution change.
10.6 Chapter Summary
<select>usesselect_option(value/label/index); pass a list for multi-select;- File upload prefers
set_input_files(single, multiple, directory, Buffer, clear); dynamic inputs useexpect_file_chooser; - Dialogs are auto-dismissed by default; custom listeners must call accept/dismiss or the page deadlocks;
fillsets value;press_sequentiallysimulates key-by-key typing (replaces deprecatedtype);- Date controls: native → direct fill; componentized → locate and click.
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. To select multiple options in a <select> element, you pass?
2. Why does page.on("dialog") require the handler to call accept/dismiss?
3. What is the essential difference between fill() and press_sequentially()?
4. For a native <input type="date">, the correct approach is?
🛠️ Hands-On Exercises
- Build a local form with a
<select multiple>, checkboxes, a file input, and a native<input type="date">; automate filling and submitting each. - Trigger an
alert("Delete this?")dialog; register a handler that readsdialog.messagethen callsdialog.dismiss(); assert the page continues. - For a JS calendar component (e.g., Element UI date picker), write a helper that types the date into the input field via
fill(); compare with the click-based approach.
Proceed to Chapter 11: Screenshots, Video, and Trace Viewer.