行动
介绍
¥Introduction
Playwright 可以与 HTML 输入元素进行交互,例如文本输入、复选框、单选按钮、选择选项、鼠标单击、键入字符、按键和快捷键以及上传文件和焦点元素。
¥Playwright can interact with HTML Input elements such as text inputs, checkboxes, radio buttons, select options, mouse clicks, type characters, keys and shortcuts as well as upload files and focus elements.
文本输入
¥Text input
使用 locator.fill() 是填写表单字段的最简单方法。它聚焦元素并使用输入的文本触发 input
事件。它适用于 <input>
、<textarea>
和 [contenteditable]
元素。
¥Using locator.fill() is the easiest way to fill out the form fields. It focuses the element and triggers an input
event with the entered text. It works for <input>
, <textarea>
and [contenteditable]
elements.
// Text input
await page.getByRole('textbox').fill('Peter');
// Date input
await page.getByLabel('Birth date').fill('2020-02-02');
// Time input
await page.getByLabel('Appointment time').fill('13:15');
// Local datetime input
await page.getByLabel('Local time').fill('2020-03-02T05:15');
复选框和单选按钮
¥Checkboxes and radio buttons
使用 locator.setChecked() 是选中和取消选中复选框或单选按钮的最简单方法。此方法可用于 input[type=checkbox]
、input[type=radio]
和 [role=checkbox]
元素。
¥Using locator.setChecked() is the easiest way to check and uncheck a checkbox or a radio button. This method can be used with input[type=checkbox]
, input[type=radio]
and [role=checkbox]
elements.
// Check the checkbox
await page.getByLabel('I agree to the terms above').check();
// Assert the checked state
expect(page.getByLabel('Subscribe to newsletter')).toBeChecked();
// Select the radio button
await page.getByLabel('XL').check();
选择选项
¥Select options
使用 locator.selectOption() 选择 <select>
元素中的一个或多个选项。你可以指定选项 value
或 label
进行选择。可以选择多个选项。
¥Selects one or multiple options in the <select>
element with locator.selectOption(). You can specify option value
, or label
to select. Multiple options can be selected.
// Single selection matching the value or label
await page.getByLabel('Choose a color').selectOption('blue');
// Single selection matching the label
await page.getByLabel('Choose a color').selectOption({ label: 'Blue' });
// Multiple selected items
await page.getByLabel('Choose multiple colors').selectOption(['red', 'green', 'blue']);
鼠标点击
¥Mouse click
执行简单的人工点击。
¥Performs a simple human click.
// Generic click
await page.getByRole('button').click();
// Double click
await page.getByText('Item').dblclick();
// Right click
await page.getByText('Item').click({ button: 'right' });
// Shift + click
await page.getByText('Item').click({ modifiers: ['Shift'] });
// Ctrl + click or Windows and Linux
// Meta + click on macOS
await page.getByText('Item').click({ modifiers: ['ControlOrMeta'] });
// Hover over element
await page.getByText('Item').hover();
// Click the top left corner
await page.getByText('Item').click({ position: { x: 0, y: 0 } });
在底层,这个方法和其他与指针相关的方法:
¥Under the hood, this and other pointer-related methods:
-
等待具有给定选择器的元素出现在 DOM 中
¥wait for element with given selector to be in DOM
-
等待它显示出来,即不为空,不存在
display:none
,不存在visibility:hidden
¥wait for it to become displayed, i.e. not empty, no
display:none
, novisibility:hidden
-
等待它停止移动,例如,直到 css 转换完成
¥wait for it to stop moving, for example, until css transition finishes
-
将元素滚动到视图中
¥scroll the element into view
-
等待它在操作点接收指针事件,例如,等待元素变得不被其他元素遮挡
¥wait for it to receive pointer events at the action point, for example, waits until element becomes non-obscured by other elements
-
如果在上述任何检查期间该元素被分离,则重试
¥retry if the element is detached during any of the above checks
强制点击
¥Forcing the click
有时,应用使用不平凡的逻辑,其中悬停元素会将其与拦截点击的另一个元素重叠。此行为与元素被覆盖且点击被分派到其他地方的错误没有区别。如果你知道正在发生这种情况,则可以绕过 actionability 检查并强制单击:
¥Sometimes, apps use non-trivial logic where hovering the element overlays it with another element that intercepts the click. This behavior is indistinguishable from a bug where element gets covered and the click is dispatched elsewhere. If you know this is taking place, you can bypass the actionability checks and force the click:
await page.getByRole('button').click({ force: true });
程序化点击
¥Programmatic click
如果你对在真实条件下测试应用不感兴趣,并且希望通过任何可能的方式模拟点击,则可以通过简单地使用 locator.dispatchEvent() 在元素上调度点击事件来触发 HTMLElement.click()
行为:
¥If you are not interested in testing your app under the real conditions and want to simulate the click by any means possible, you can trigger the HTMLElement.click()
behavior via simply dispatching a click event on the element with locator.dispatchEvent():
await page.getByRole('button').dispatchEvent('click');
输入字符
¥Type characters
大多数时候,你应该使用 locator.fill() 输入文本。请参阅上面的 文本输入 部分。仅当页面上有特殊键盘处理时才需要键入字符。
¥Most of the time, you should input text with locator.fill(). See the Text input section above. You only need to type characters if there is special keyboard handling on the page.
在字段中逐个字符输入,就好像用户使用 locator.pressSequentially() 的真实键盘一样。
¥Type into the field character by character, as if it was a user with a real keyboard with locator.pressSequentially().
// Press keys one by one
await page.locator('#area').pressSequentially('Hello World!');
此方法将触发所有必要的键盘事件,以及所有 keydown
、keyup
、keypress
事件。你甚至可以在按键之间指定可选的 delay
以模拟真实的用户行为。
¥This method will emit all the necessary keyboard events, with all the keydown
, keyup
, keypress
events in place. You can even specify the optional delay
between the key presses to simulate real user behavior.
按键和快捷键
¥Keys and shortcuts
// Hit Enter
await page.getByText('Submit').press('Enter');
// Dispatch Control+Right
await page.getByRole('textbox').press('Control+ArrowRight');
// Press $ sign on keyboard
await page.getByRole('textbox').press('$');
locator.press() 方法聚焦所选元素并产生单个击键。它接受在键盘事件的 keyboardEvent.key 属性中触发的逻辑键名称:
¥The locator.press() method focuses the selected element and produces a single keystroke. It accepts the logical key names that are emitted in the keyboardEvent.key property of the keyboard events:
Backquote, Minus, Equal, Backslash, Backspace, Tab, Delete, Escape,
ArrowDown, End, Enter, Home, Insert, PageDown, PageUp, ArrowRight,
ArrowUp, F1 - F12, Digit0 - Digit9, KeyA - KeyZ, etc.
-
你也可以指定要生成的单个字符,例如
"a"
或"#"
。¥You can alternatively specify a single character you'd like to produce such as
"a"
or"#"
. -
还支持以下修改快捷方式:
Shift, Control, Alt, Meta
。¥Following modification shortcuts are also supported:
Shift, Control, Alt, Meta
.
简单版本产生单个字符。该字符区分大小写,因此 "a"
和 "A"
将产生不同的结果。
¥Simple version produces a single character. This character is case-sensitive, so "a"
and "A"
will produce different results.
// <input id=name>
await page.locator('#name').press('Shift+A');
// <input id=name>
await page.locator('#name').press('Shift+ArrowLeft');
还支持 "Control+o"
或 "Control+Shift+T"
等快捷方式。当使用修饰符指定时,修饰符将被按下并在按下后续键的同时保持不变。
¥Shortcuts such as "Control+o"
or "Control+Shift+T"
are supported as well. When specified with the modifier, modifier is pressed and being held while the subsequent key is being pressed.
请注意,你仍然需要在 Shift-A
中指定大写 A
来生成大写字符。Shift-a
产生一个小写字母,就像你切换了 CapsLock
一样。
¥Note that you still need to specify the capital A
in Shift-A
to produce the capital character. Shift-a
produces a lower-case one as if you had the CapsLock
toggled.
上传文件
¥Upload files
你可以使用 locator.setInputFiles() 方法选择要上传的输入文件。它期望第一个参数指向类型为 "file"
的 输入元素。可以在数组中传递多个文件。如果某些文件路径是相对的,则它们将相对于当前工作目录进行解析。空数组会清除选定的文件。
¥You can select input files for upload using the locator.setInputFiles() method. It expects first argument to point to an input element with the type "file"
. Multiple files can be passed in the array. If some of the file paths are relative, they are resolved relative to the current working directory. Empty array clears the selected files.
// Select one file
await page.getByLabel('Upload file').setInputFiles(path.join(__dirname, 'myfile.pdf'));
// Select multiple files
await page.getByLabel('Upload files').setInputFiles([
path.join(__dirname, 'file1.txt'),
path.join(__dirname, 'file2.txt'),
]);
// Select a directory
await page.getByLabel('Upload directory').setInputFiles(path.join(__dirname, 'mydir'));
// Remove all the selected files
await page.getByLabel('Upload file').setInputFiles([]);
// Upload buffer from memory
await page.getByLabel('Upload file').setInputFiles({
name: 'file.txt',
mimeType: 'text/plain',
buffer: Buffer.from('this is test')
});
如果你手头没有输入元素(它是动态创建的),你可以处理 page.on('filechooser') 事件或在操作时使用相应的等待方法:
¥If you don't have input element in hand (it is created dynamically), you can handle the page.on('filechooser') event or use a corresponding waiting method upon your action:
// Start waiting for file chooser before clicking. Note no await.
const fileChooserPromise = page.waitForEvent('filechooser');
await page.getByLabel('Upload file').click();
const fileChooser = await fileChooserPromise;
await fileChooser.setFiles(path.join(__dirname, 'myfile.pdf'));
焦点元素
¥Focus element
对于处理焦点事件的动态页面,你可以使用 locator.focus() 将给定元素聚焦。
¥For the dynamic pages that handle focus events, you can focus the given element with locator.focus().
await page.getByLabel('Password').focus();
拖放
¥Drag and Drop
你可以使用 locator.dragTo() 执行拖放操作。该方法将:
¥You can perform drag&drop operation with locator.dragTo(). This method will:
-
将鼠标悬停在要拖动的元素上。
¥Hover the element that will be dragged.
-
按鼠标左键。
¥Press left mouse button.
-
将鼠标移动到将接收掉落的元素。
¥Move mouse to the element that will receive the drop.
-
释放鼠标左键。
¥Release left mouse button.
await page.locator('#item-to-be-dragged').dragTo(page.locator('#item-to-drop-at'));
手动拖动
¥Dragging manually
如果你想精确控制拖动操作,请使用更底层的方法,例如 locator.hover()、mouse.down()、mouse.move() 和 mouse.up()。
¥If you want precise control over the drag operation, use lower-level methods like locator.hover(), mouse.down(), mouse.move() and mouse.up().
await page.locator('#item-to-be-dragged').hover();
await page.mouse.down();
await page.locator('#item-to-drop-at').hover();
await page.mouse.up();
如果你的页面依赖于正在调度的 dragover
事件,则你需要至少移动两次鼠标才能在所有浏览器中触发它。要可靠地触发第二次鼠标移动,请重复 mouse.move() 或 locator.hover() 两次。操作顺序为:将鼠标悬停在拖动元素上,鼠标向下,将鼠标悬停在放置元素上,第二次将鼠标悬停在放置元素上,将鼠标向上悬停。
¥If your page relies on the dragover
event being dispatched, you need at least two mouse moves to trigger it in all browsers. To reliably issue the second mouse move, repeat your mouse.move() or locator.hover() twice. The sequence of operations would be: hover the drag element, mouse down, hover the drop element, hover the drop element second time, mouse up.
滚动
¥Scrolling
大多数情况下,Playwright 会在执行任何操作之前自动为你滚动。因此,你不需要明确滚动。
¥Most of the time, Playwright will automatically scroll for you before doing any actions. Therefore, you do not need to scroll explicitly.
// Scrolls automatically so that button is visible
await page.getByRole('button').click();
但是,在极少数情况下,你可能需要手动滚动。例如,你可能希望强制 "无限列表" 加载更多元素,或将页面定位到特定的屏幕截图。在这种情况下,最可靠的方法是找到你想要在底部显示的元素,然后将其滚动到视图中。
¥However, in rare cases you might need to manually scroll. For example, you might want to force an "infinite list" to load more elements, or position the page for a specific screenshot. In such a case, the most reliable way is to find an element that you want to make visible at the bottom, and scroll it into view.
// Scroll the footer into view, forcing an "infinite list" to load more content
await page.getByText('Footer text').scrollIntoViewIfNeeded();
如果你想更精确地控制滚动,请使用 mouse.wheel() 或 locator.evaluate():
¥If you would like to control the scrolling more precisely, use mouse.wheel() or locator.evaluate():
// Position the mouse and scroll with the mouse wheel
await page.getByTestId('scrolling-container').hover();
await page.mouse.wheel(0, 10);
// Alternatively, programmatically scroll a specific element
await page.getByTestId('scrolling-container').evaluate(e => e.scrollTop += 100);