跳到主要内容

操作交互

简介

Playwright 可以与 HTML 输入元素进行交互,包括文本输入框、复选框、单选按钮、选择选项、鼠标点击、字符输入、按键和快捷键操作,以及文件上传和元素聚焦等功能。

文本输入

使用 locator.fill() 是填充表单字段最简单的方式。该方法会聚焦元素并触发带有输入文本的 input 事件。适用于 <input><textarea>[contenteditable] 元素。

// 文本输入
await page.getByRole('textbox').fill('Peter');

// 日期输入
await page.getByLabel('Birth date').fill('2020-02-02');

// 时间输入
await page.getByLabel('Appointment time').fill('13:15');

// 本地日期时间输入
await page.getByLabel('Local time').fill('2020-03-02T05:15');

复选框和单选按钮

使用 locator.setChecked() 是勾选或取消勾选复选框和单选按钮最简单的方式。此方法适用于 input[type=checkbox]input[type=radio][role=checkbox] 元素。

// 勾选复选框
await page.getByLabel('I agree to the terms above').check();

// 验证选中状态
expect(page.getByLabel('Subscribe to newsletter')).toBeChecked();

// 选择单选按钮
await page.getByLabel('XL').check();

选择选项

使用 locator.selectOption()<select> 元素中选择一个或多个选项。可以通过指定选项的 valuelabel 进行选择。支持多选操作。

// 通过值或标签匹配进行单选
await page.getByLabel('选择颜色').selectOption('blue');

// 通过标签匹配进行单选
await page.getByLabel('选择颜色').selectOption({ label: '蓝色' });

// 多选操作
await page.getByLabel('选择多个颜色').selectOption(['red', 'green', 'blue']);

鼠标点击

模拟真实用户的点击行为。

// 普通点击
await page.getByRole('button').click();

// 双击
await page.getByText('项目').dblclick();

// 右键点击
await page.getByText('项目').click({ button: 'right' });

// Shift + 点击
await page.getByText('项目').click({ modifiers: ['Shift'] });

// Windows/Linux系统下 Ctrl + 点击
// macOS系统下 Meta + 点击
await page.getByText('项目').click({ modifiers: ['ControlOrMeta'] });

// 鼠标悬停
await page.getByText('项目').hover();

// 点击左上角位置
await page.getByText('项目').click({ position: { x: 0, y: 0 } });

底层实现中,该方法及其他指针相关操作会:

  • 等待指定选择器的元素出现在DOM中
  • 等待元素变为可见状态(非空、无display:none、无visibility:hidden
  • 等待元素停止移动(例如CSS过渡动画完成)
  • 将元素滚动至可视区域
  • 等待元素在操作点可接收指针事件(例如等待元素不再被其他元素遮挡)
  • 在上述任何检查过程中如果元素被移除,会自动重试操作

强制点击

有时,应用程序会使用复杂的逻辑,当悬停在元素上时会用另一个拦截点击的元素覆盖它。这种行为与元素被覆盖导致点击被分发到其他位置的 bug 难以区分。如果你确认这种情况正在发生,可以绕过可操作性检查并强制点击:

await page.getByRole('button').click({ force: true });

编程式点击

如果你不关心在真实条件下测试应用程序,而是想通过任何可能的方式模拟点击,可以通过locator.dispatchEvent()直接在元素上触发HTMLElement.click()行为:

await page.getByRole('button').dispatchEvent('click');

逐个字符输入

警告

大多数情况下,你应该使用locator.fill()来输入文本。请参阅上文的文本输入部分。只有当页面有特殊键盘处理时,才需要逐个字符输入。

使用locator.pressSequentially()逐个字符输入到字段中,就像用户使用真实键盘一样。

// 逐个按键输入
await page.locator('#area').pressSequentially('Hello World!');

此方法会触发所有必要的键盘事件,包括所有keydownkeyupkeypress事件。你甚至可以指定按键之间的可选delay来模拟真实用户行为。

按键与快捷键

// 按下 Enter 键
await page.getByText('Submit').press('Enter');

// 发送 Control+右箭头组合键
await page.getByRole('textbox').press('Control+ArrowRight');

// 在键盘上按下 $ 符号键
await page.getByRole('textbox').press('$');

locator.press() 方法会使选定元素获得焦点并触发单个按键事件。它接受键盘事件 keyboardEvent.key 属性中定义的逻辑键名:

Backquote, Minus, Equal, Backslash, Backspace, Tab, Delete, Escape,
ArrowDown, End, Enter, Home, Insert, PageDown, PageUp, ArrowRight,
ArrowUp, F1 - F12, Digit0 - Digit9, KeyA - KeyZ, 等
  • 也可以直接指定要触发的单个字符,如 "a""#"
  • 支持以下修饰键组合:Shift, Control, Alt, Meta

简单版本触发单个字符。字符区分大小写,因此 "a""A" 会产生不同结果。

// <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" 这样的组合快捷键。当指定修饰键时,修饰键会被按下并保持,同时触发后续按键。

请注意在 Shift-A 中仍需指定大写 A 才能生成大写字符。Shift-a 会产生小写字符,就像启用了 CapsLock 一样。

文件上传

您可以使用 locator.setInputFiles() 方法选择要上传的输入文件。该方法期望第一个参数指向一个类型为 "file"input 元素。可以通过数组传递多个文件。如果某些文件路径是相对路径,它们将相对于当前工作目录进行解析。空数组会清除已选择的文件。

// 选择单个文件
await page.getByLabel('Upload file').setInputFiles(path.join(__dirname, 'myfile.pdf'));

// 选择多个文件
await page.getByLabel('Upload files').setInputFiles([
path.join(__dirname, 'file1.txt'),
path.join(__dirname, 'file2.txt'),
]);

// 选择整个目录
await page.getByLabel('Upload directory').setInputFiles(path.join(__dirname, 'mydir'));

// 移除所有已选文件
await page.getByLabel('Upload file').setInputFiles([]);

// 从内存上传缓冲区
await page.getByLabel('Upload file').setInputFiles({
name: 'file.txt',
mimeType: 'text/plain',
buffer: Buffer.from('this is test')
});

如果您没有现成的 input 元素(它是动态创建的),可以处理 page.on('filechooser') 事件,或者在操作时使用相应的等待方法:

// 在点击前开始等待文件选择器。注意不需要 await。
const fileChooserPromise = page.waitForEvent('filechooser');
await page.getByLabel('Upload file').click();
const fileChooser = await fileChooserPromise;
await fileChooser.setFiles(path.join(__dirname, 'myfile.pdf'));

元素聚焦

对于处理焦点事件的动态页面,您可以使用 locator.focus() 方法将焦点设置到指定元素。

await page.getByLabel('Password').focus();

拖放操作

您可以使用 locator.dragTo() 方法执行拖放操作。该方法会:

  1. 悬停在待拖动元素上
  2. 按下鼠标左键
  3. 移动鼠标到接收放置的元素
  4. 释放鼠标左键
await page.locator('#item-to-be-dragged').dragTo(page.locator('#item-to-drop-at'));

手动拖放

如果需要更精确地控制拖放操作,可以使用底层方法如 locator.hover()mouse.down()mouse.move()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() 两次。操作顺序应为:悬停拖动元素 → 鼠标按下 → 悬停放置元素 → 再次悬停放置元素 → 鼠标释放。

滚动操作

大多数情况下,Playwright 在执行任何操作前会自动进行滚动。因此,您通常不需要显式地执行滚动操作。

// 自动滚动使按钮可见
await page.getByRole('button').click();

但在极少数情况下,您可能需要手动滚动。例如,您可能希望强制"无限列表"加载更多元素,或者为特定截图定位页面位置。这种情况下,最可靠的方法是找到一个您希望显示在底部的元素,并将其滚动到视图中。

// 将页脚滚动到视图中,强制"无限列表"加载更多内容
await page.getByText('Footer text').scrollIntoViewIfNeeded();

如果您需要更精确地控制滚动,可以使用 mouse.wheel()locator.evaluate():

// 定位鼠标并用滚轮滚动
await page.getByTestId('scrolling-container').hover();
await page.mouse.wheel(0, 10);

// 或者以编程方式滚动特定元素
await page.getByTestId('scrolling-container').evaluate(e => e.scrollTop += 100);