源码教程:点击、输入、键盘与鼠标
本章解释定位如何转为动作。核心辅助方法是 resolveIndex、resolveActionTarget、clickWithMode 和输入执行逻辑;遮挡与重复提交的排障步骤见第 15 篇。
1. 索引、CSS 与语义定位
| 命令 | 定位和执行方式 |
|---|---|
click_element_by_index | 从快照解析 Locator,记录动作前状态,交给点击模式执行器 |
click_element_by_selector | 在指定 Frame 解析 CSS;多匹配优先选择可接收事件的可见元素 |
click_element_by_text | 按文本查找并选择实际目标,结合命中信息判断是否点到过大的父容器 |
click_element_by_role | 使用无障碍 role 和可选 name 定位,不是按 CSS 类名 |
hover_and_click | 定位后先 hover,等待可选延时,再执行点击;适合悬停菜单 |
double_click_element_by_index | 对索引目标执行双击语义,不能简单宣称是两次业务提交 |
hover_element_by_index | 调用 Locator.hover,可能触发浮层和新控件 |
focus_element_by_index | 调用 Locator.focus,后续键盘事件仍需确认实际焦点 |
check_element_by_index、uncheck_element_by_index | 使用勾选/取消勾选语义,避免不加判断地切换状态 |
resolveActionTarget 先 count,0 个匹配立即报告不存在;多个匹配扫描前 20 个候选,通过可见性和中心点命中优先选前景控件。它不是业务语义解析器,仍应写能限定目标的选择器。
2. 点击执行不是无条件重试
auto 先尝试原生点击。在普通失败且未发现遮挡时,根据配置尝试真实鼠标和 JS;已发现遮挡则停止,避免点击背景提交按钮。原生调用遇到对象释放异常时不补点,因为先前操作可能已经生效。
显式 native、mouse、js 分别约束执行方式。鼠标坐标点击不能自动证明目标就是该元素,JS 事件也可能被框架拒绝。回执应记录实际 mode、命中对象与观察结果;不能把“派发成功”写成“业务成功”。
{"id":"1001","method":"click_element_by_selector","params":{"selector":"#preview-button","mode":"native","timeoutMs":3000}}
3. 输入与框架状态
| 命令 | 实现要点 |
|---|---|
input_text | 索引定位后执行覆盖输入,支持 mode;默认优先真实交互 |
input_text_by_selector | CSS 定位,可指定 frame,复用输入执行逻辑 |
input_text_by_label | 按标签定位表单控件,再执行输入 |
type_text | 调用 pressSequentially 逐字符输入,不先清空现有内容;适合依赖按键事件的控件 |
clear_text | 按 index 或 selector 定位并清空;要检查框架是否接受修改 |
真实输入会参与浏览器事件流程;JS 降级通过属性 setter 和 input/change 事件设置值,但不保证框架模型接受,因此有 committed 等说明。只读、禁用、隐藏及不可编辑是不同失败原因,不应全部换成 JS 强写。
{"id":"1001","method":"input_text_by_selector","params":{"selector":"#display-name","text":"示例用户","mode":"type"}}
输入后用 get_form_state 回读,尤其是在 Windows shell 传中文时。传参完整性与浏览器是否成功填值是两个问题。
4. 下拉框、滚动与拖拽
get_dropdown_options 从原生 select 的 options 读取文本;select_dropdown_option 按 label 选择。由 div 模拟的下拉框没有原生 options,应展开后对实际选项点击,不能硬套 select 接口。
scroll 的参数是 down、numPages 和可选 index。没有 index 时循环发 PageDown/PageUp;有 index 时对对应容器执行 scrollBy,距离按视口高度计算。它不是接收任意像素数的接口。scroll_to_text 则定位文字并滚动到可见范围。
drag_element_by_index 解析源索引和 targetIndex,调用拖拽操作。布局变化后要重取两端索引,不能只更新源元素。
5. 键盘与鼠标是更低层的工具
| 命令 | 底层机制与边界 |
|---|---|
send_keys | 发组合键或按键到当前焦点,回执可帮助检查焦点;按 Enter 不代表业务提交成功 |
key_down、key_up | 保持/释放键状态,应成对使用,避免残留修饰键 |
mouse_move | 移动到页面坐标,可能触发 hover |
mouse_down、mouse_up | 按下/释放指定鼠标键,用于连续操作 |
mouse_wheel | 按 deltaY 发滚轮事件 |
mouse_click | 按 x、y 发真实鼠标点击,可指定 button 与 clickCount |
mouse_click_by_selector | 找到目标盒子中心后发真实鼠标点击,不等于原生可操作性检查 |
坐标按浏览器页面坐标使用,不能直接复制经过缩放的截图像素。窗口尺寸、页面视口与截图像素差异见第 10 篇。
6. 回归测试设计
准备背景提交按钮、覆盖层和前景按钮,分别记录点击次数。验证 auto 不触发背景按钮,重复选择器选到前景控件;再注入对象释放异常,确认没有第二次点击。输入测试应检查框架监听器收到的值,而不是仅检查 DOM attribute。原生 select 和自定义下拉框使用不同 fixture,避免错误实现只在一种控件上通过。
注册参数与 Java 入口
以下按 CommandTable 实际读取参数整理。* 表示注册层使用必填读取器;其余字段省略后由服务决定默认行为。带条件的入口仍需满足正文说明,例如上传文件来源、元素定位二选一。外层 id 不重复列出。
| 命令 | params 字段 | Java 入口 |
|---|---|---|
click_element_by_index | index*、mode、timeoutMs | clickElementByIndex |
double_click_element_by_index | index*、mode | doubleClickElementByIndex |
hover_element_by_index | index* | hoverElementByIndex |
focus_element_by_index | index* | focusElementByIndex |
check_element_by_index | index*、mode | checkElementByIndex |
uncheck_element_by_index | index*、mode | uncheckElementByIndex |
input_text | index、text、mode | inputTextByIndex |
type_text | index、text | typeText |
drag_element_by_index | index、targetIndex | dragElementByIndex |
send_keys | keys* | sendKeys |
key_down | keys* | keyDown |
key_up | keys* | keyUp |
get_dropdown_options | index* | getDropdownOptions |
select_dropdown_option | index、text | selectDropdownOption |
scroll | down、numPages*、index | scroll |
scroll_to_text | text* | scrollToText |
click_element_by_selector | selector*、mode、timeoutMs、frame | clickElementBySelector |
input_text_by_selector | selector、text、mode、frame | inputTextBySelector |
click_element_by_text | text*、mode | clickElementByText |
click_element_by_role | role*、name、mode | clickElementByRole |
input_text_by_label | label、text、mode | inputTextByLabel |
clear_text | index、selector | clearText |
hover_and_click | index、selector、hoverDelayMs、mode | hoverAndClick |
mouse_move | x、y | mouseMove |
mouse_down | button | mouseDown |
mouse_up | button | mouseUp |
mouse_wheel | deltaY* | mouseWheel |
mouse_click | x、y、button、clickCount | mouseClick |
mouse_click_by_selector | selector*、button、clickCount、timeoutMs | mouseClickBySelector |
