通用控件方法
下面介绍了每个控件(虚拟控件除外)共有的基础操作和属性方法。无论控件的具体类型如何,这些方法都适用。部分方法模拟用户操作,部分则是基于底层的Accessibility API完成操作。
API 概览
操作方法
| 方法名 | 描述 |
|---|---|
| click | 模拟鼠标点击控件,可指定点击的位置和使用的鼠标键。 |
| dblClick | 模拟鼠标双击控件,可指定双击的位置和使用的鼠标键。 |
| moveMouse | 移动鼠标到控件的指定位置,可指定速度。 |
| wheel | 滚动鼠标滚轮。 |
| exists | 检查控件是否存在,可指定最长等待时间。 |
| hScroll | 在控件上进行水平滚动。 |
| vScroll | 在控件上进行垂直滚动。 |
| pressKeys | 输入组合按键或字符串。 |
| property | 获取控件的指定属性值。 |
| waitProperty | 等待控件的指定属性达到某个值。 |
| checkImage | 校验控件的图像是否与预期的参考图像匹配。 |
| checkProperty | 校验控件的属性是否符合预期值。 |
| drag | 模拟拖拽操作的第一步,按下鼠标。 |
| drop | 模拟拖拽操作的第二步,松开鼠标。 |
| highlight | 突出显示控件,用于调试和验证。 |
| takeScreenshot | 对控件截图,可指定文件路径。 |
| doDefaultAction | 执行控件的默认操作。 |
| scrollIntoView | 滚动到控件的可视位置。 |
| modelImage | 获取控件在模型中缓存的截图快照。 |
| modelProperties | 获取控件在模型中缓存的属性。 |
属性方法
| 方法名 | 描述 |
|---|---|
| type | 获取控件的类型。 |
| text | 获取控件的文本内容。 |
| rawText | 获取控件的内部文本信息。 |
| name | 获取控件的名称。 |
| hwnd | 获取控件所属的窗口句柄。 |
| height | 获取控件的高度。 |
| width | 获取控件的宽度。 |
| enabled | 控件是否可用。 |
| focused | 控件是否被聚焦/被选中。 |
| visible | 控件是否可见且未被遮挡。 |
| helpText | 获取控件的帮助文本。 |
| value | 获取控件的值。 |
| processId | 获取控件所属应用的进程号。 |
| rect | 获取控件的位置和大小。 |
| allProperties | 获取目标控件的所有运行时属性。 |
控件导航方法
| 方法名 | 描述 |
|---|---|
| firstChild | 获取控件的第一个子控件。 |
| lastChild | 获取控件的最后一个子控件。 |
| next | 获取控件的下一个兄弟控件。 |
| previous | 获取控件的上一个兄弟控件。 |
| parent | 获取控件的父控件。 |
| all | 获取所有匹配的同级控件。 |
| findControls | 根据条件查找控件。 |
类型定义
这些方法都写在控件的基类上,可以点击leanpro.win库查看,定义如下:
export interface IWinControl extends IWinContainer {
//methods
click(x?: number, y?: number, mousekey?: MouseKey): Promise<void>;
dblClick(x?: number, y?: number, mousekey?: MouseKey): Promise<void>;
moveMouse(x?: number, y?: number, seconds?: number): Promise<void>
wheel(value: number): Promise<void>;
exists(time?: number): Promise<boolean>;
hScroll(value: number | ScrollAmount): Promise<void>;
vScroll(value: number | ScrollAmount): Promise<void>;
property(propertyIds: PropertyIds | string): Promise<string | boolean | number | Rect>;
checkImage(options?: CheckImageCompareOptions | string): Promise<void>;
checkProperty(propertyName: string, expectedValue: string | number | boolean | RegExp, message: string): Promise<void>;
checkProperty(propertyName: string, expectedValue: string | number | boolean | RegExp, options: {message: string, operation: any}): Promise<void>;
waitProperty(propertyIds: PropertyIds, value: string, timeoutSeconds?: number/* default value 5 seconds */): Promise<boolean>;
drop(x?: number, y?: number, seconds?: number): Promise<void>;
drag(x?: number, y?: number): Promise<void>;
pressKeys(keys: string, opt?: PressKeysOptions | number): Promise<void>;
takeScreenshot(filePath?: string): Promise<void | string>;
highlight(duration?: number);
//properties
type(): Promise<string>;
text(): Promise<string>;
name(): Promise<string>;
hwnd(): Promise<number>;
x(): Promise<number>;
y(): Promise<number>;
height(): Promise<number>;
width(): Promise<number>;
enabled(): Promise<boolean>;
focused(): Promise<boolean>;
helpText(): Promise<string>;
labeledText(): Promise<string>;
value(): Promise<string | number>;
processId(): Promise<number>;
rect(): Promise<Rect>;
visible(): Promise<boolean>;
//navigation methods
firstChild(controlType?: ControlType): Promise<IWinControl>;
lastChild(controlType?: ControlType): Promise<IWinControl>;
next(controlType?: ControlType): Promise<IWinControl>;
previous(controlType?: ControlType): Promise<IWinControl>;
parent(): Promise<IWinControl>;
all(): Promise<IWinControl[]>;
findControls(...conditions: ConditionFilter[]): Promise<IWinControl[]>; //used to be getControls
modelImage(options?: {encoding: 'buffer' | 'base64'}): Promise<string | Buffer>; //base64 is the default
modelProperties(all?: boolean): {[x: string]: any};
allProperties(): Promise<object>;
doDefaultAction(): Promise<void>;
rawText(): Promise<string>;
scrollIntoView(): Promise<void>;
}class WinControl(WinContainer):
def click(x: Optional[int]=None, y: Optional[int]=None, mousekey: Optional[int]=None) -> None
def dblClick(x: Optional[int]=None, y: Optional[int]=None, mousekey: Optional[int]=None) -> None
def moveMouse(x: Optional[int]=None, y: Optional[int]=None, seconds: Optional[int]=None) -> None
def wheel(value: int) -> None
def exists(time: Optional[int]=None) -> bool
def hScroll(value: int) -> None
def vScroll(value: int) -> None
def property(propertyds: str) -> Union[str, int, bool, Rect]
def waitProperty(propertyds: str, value: str, timeoutSeconds: Optional[int]=None) -> bool
def checkProperty(propertyName: str, expectedValue: Union[str, int, bool], optionsOrMessage: Optional[Union[str, TypedDict]]=None) -> "bool"
def checkImage(options: Optional[any]=None) -> None
def drop(x: Optional[int]=None, y: Optional[int]=None) -> None
def drag(x: Optional[int]=None, y: Optional[int]=None) -> None
def pressKeys(keys: str, opt: Optional[Union[int, PressKeysOptions]]=None) -> None
def takeScreenshot(filePath: Optional[str]=None) -> Union[str, None]
def highlight(duration: Optional[int]=None) -> None
def type() -> str
def text() -> str
def name() -> str
def hwnd() -> int
def x() -> int
def y() -> int
def height() -> int
def width() -> int
def enabled() -> bool
def focused() -> bool
def visible() -> bool
def helpText() -> str
def labeledText() -> str
def value() -> Union[str, int]
def processId() -> int
def rect() -> "Rect"
def firstChild(controlType: Optional[str]=None) -> "WinControl"
def lastChild(controlType: Optional[str]=None) -> "WinControl"
def next(controlType: Optional[str]=None) -> "WinControl"
def previous(controlType: Optional[str]=None) -> "WinControl"
def parent() -> "WinControl"
def findControls(*conditions: List[Union[str, Dict]]) -> List[WinControl]
def modelmage(encoding: Optional[str]=None) -> Union[str, bytearray]
def modelProperties(all: Optional[bool]=None) -> TypedDict
def all() -> List[WinControl]
def allProperties() -> TypedDict
def doDefaultAction() -> None
def rawText() -> str
def scrollIntoView() -> None可能用到的类定义
以下是调用共有API时可能会使用到的一些类型定义。
控件属性名枚举类: PropertyIds
export enum PropertyIds {
automationId,
name,
text,
url,
title,
handle,
x,
y,
height,
width,
enabled,
focused,
helpText,
value,
labeledText,
processId,
rect,
...
}除了以上列出来的属性外,各个控件还各自维护了一些特有的属性名,可以参考allProperties()方法的返回结果对象中的字段。
控件类型枚举类: ControlType
CukeTest中可以识别到的所有控件类型,可以用于findControls()方法中指定控件类型,或者调用控件的type()方法返回结果的类型也都在这个枚举类中。
enum ControlType {
Button,
Calendar,
CheckBox,
ComboBox,
Custom,
DataGrid,
DataItem,
Document,
Edit,
Group,
Generic,
Header,
HeaderItem,
Hyperlink,
Image,
List,
ListItem,
MenuItem,
MenuBar,
Menu,
Pane,
RadioButton,
ScrollBar,
Slider,
Spinner,
Tab,
TabItem,
Table,
Text,
Thumb,
ToolBar,
Tree,
TreeItem,
Window,
//virtual types
TableRow,
TreeCell,
}控件筛选条件Criteria类
CukeTest使用Criteria对象作为条件对当前环境中的控件进行筛选,来获取目标控件并操作。详见Criteria类。
进程启动选项类SpawnOptions
用于配置进程启动选项的类,支持的属性有,具体可以参考child_processs.spawn:
- cwd:
string类型或URL类型,子进程的工作目录,默认值为运行的项目目录,即process.cwd()的值。 - env:
Object类型,环境变量的键值对。默认值:process.env。 - argv0:
string类型,显式设置发送给子进程的argv[0]的值。如果未指定,这将设置为命令。 - detached:
boolean类型,准备子进程独立于其父进程运行。具体行为取决于平台,请参阅 options.detached)。 - uid:
number类型,设置进程的用户身份(参考 setuid(2))。 - gid:
number类型,设置进程的组标识(参考 setgid(2))。 - serialization:
string类型,指定用于在进程之间发送消息的序列化类型。可能的值是“json”和“高级”。有关详细信息,请参阅高级序列化。默认值:json。 - shell:
boolean类型或string类型如果为true,则会启动终端来运行命令。在Unix上使用 '/bin/sh',在Windows上使用process.env.ComSpec。可以传入string类型来指定终端的路径。默认值:false(无终端)。 - windowsVerbatimArguments:
boolean类型在Windows上不会引用或转义参数。在Unix上被忽略。当指定shell并且是CMD时,它会自动设置为 true。默认值:false。 - windowsHide:
boolean类型隐藏通常在Windows 系统上创建的子进程控制台窗口。默认值:false。 - timeout:
number类型,允许进程运行的最长时间,以毫秒为单位。默认值:未定义。 - killSignal:
string类型或int类型,生成的进程将被超时或中止信号杀死时使用的信号值。默认值:“SIGTERM”。
操作方法
click(x, y, mousekey)
模拟鼠标点击控件,可以通过传入参数修改点击的相对位置(偏移量)和使用的鼠标键。
参数:
- x:
number类型,点击位置相对控件左上角的水平像素点,0代表控件的水平中点位置,缺省值为0。 - y:
number类型,点击位置相对控件左上角的垂直像素点,0代表控件的垂直中点位置,缺省值为0。 - mouseKey:
MouseKey类型,操作的鼠标键,缺省为1,即鼠标左键。
返回值:
- 不返回任何值的异步方法。
使用示例
最简单的调用方式是不传入任何参数,直接点击控件的正中心:
// 点击按钮的中心位置
await model.getButton("Button").click();# 点击按钮的中心位置
model.getButton("Button").click()如果需要点击控件的指定坐标位置,可以传入相对控件左上角的水平像素值(x)和垂直像素值(y):
// 点击按钮上距离左上角水平590像素、垂直10像素的位置
await model.getButton("Button").click(590, 10);# 点击按钮上距离左上角水平590像素、垂直10像素的位置
model.getButton("Button").click(590, 10)注意:click(0, 0)不会点击控件左上角原点,而是点击控件正中心;如果期望点击左上角,请用click(1, 1)。
如果需要右击控件,则需要传入第三个参数并设置为2:
// 右键点击按钮的指定位置
await model.getButton("Button").click(590, 10, 2);# 右键点击按钮的指定位置
model.getButton("Button").click(590, 10, 2)如果需要右键点击控件正中心,可以使用以下方式:
// 右键点击按钮中心
await model.getButton("Button").click(0, 0, 2);
await model.getButton("Button").click(null, null, 2);# 右键点击按钮中心
model.getButton("Button").click(0, 0, 2)
model.getButton("Button").click(None, None, 2)dblClick(x, y, mousekey)
模拟鼠标双击控件。与click()方法的调用方式一致。
参数:
- x:
number类型,双击位置相对控件左上角的水平像素点,缺省值为0。 - y:
number类型,双击位置相对控件左上角的垂直像素点,缺省值为0。 - mouseKey:
MouseKey类型,操作的鼠标键,缺省为1。
返回值:
- 不返回任何值的异步方法。
使用示例
双击控件的正中心:
// 双击按钮中心
await model.getButton("Button").dblClick();# 双击按钮中心
model.getButton("Button").dblClick()moveMouse(x, y, seconds)
移动鼠标光标到控件的指定位置。
参数:
- x:
number类型,移动位置相对控件左上角的水平像素点,缺省值为0。 - y:
number类型,移动位置相对控件左上角的垂直像素点,缺省值为0。 - seconds:
number类型,鼠标移动的持续时间,单位为秒。
返回值:
- 不返回任何值的异步方法。
使用示例
移动鼠标到控件的中心位置:
// 移动鼠标到Pane控件中心
await model.getPane("Pane").moveMouse();# 移动鼠标到Pane控件中心
model.getPane("Pane").moveMouse()如果需要移动鼠标到控件的指定位置并控制速度:
// 在5秒内移动鼠标到指定位置(500, 70)
await model.getPane("Pane").moveMouse(500, 70, 5);# 在5秒内移动鼠标到指定位置(500, 70)
model.getPane("Pane").moveMouse(500, 70, 5)wheel(value)
滚动鼠标滚轮,输入参数的单位为滚轮滚动的刻度。最多翻一页,如果需要滚动多页,请循环调用。
参数:
- value:
number类型,滚轮刻度。
返回值:
- 不返回任何值的异步方法。
使用示例
向上滚动鼠标滚轮一个刻度:
// 在Pane控件上向上滚动一个刻度
await model.getPane("Pane").wheel(1);# 在Pane控件上向上滚动一个刻度
model.getPane("Pane").wheel(1)exists(time)
这个方法用来判断一个控件是否存在。你可以指定一个最大等待时间,如果在指定的时间内找到了控件,就返回 true,否则返回 false。缺省调用只会检查一次而不会重试与等待。
参数:
- time:
number类型,等待控件出现的最大秒数。如果省略,默认等待0秒,也就是只检查一次。
返回值:
- 异步的返回控件是否存在,
true为存在,false为不存在。
使用示例
- 不指定等待时间
// 立即检查控件是否存在
let exists = await model.getApplication("dirview").exists();# 立即检查控件是否存在
exists = model.getApplication("dirview").exists()exists 的值为 true,否则为 false。
- 指定等待时间
// 等待最多10秒,直到控件出现
let bool = await model.getApplication("dirview").exists(10);
assert.strictEqual(bool, true);# 等待最多10秒,直到控件出现
bool = model.getApplication("dirview").exists(10)
assert bool == Truebool 的值为 true,否则为 false。
hScroll(value)
在控件上进行水平滚动,即Horizontal Scroll,参数为滚动的百分比。
参数:
- value:
number类型,为滚动的百分比,0为滚动到最左侧,100为滚动到最右侧。
返回值:
- 不返回任何值的异步方法。
使用示例
// 将控件水平滚动到中间位置(50%)
await model.getPane("Pane").hScroll(50);# 将控件水平滚动到中间位置(50%)
model.getPane("Pane").hScroll(50)vScroll(value)
在控件上进行垂直滚动,即Vertical Scroll,参数为滚动的百分比。
参数:
- value:
number类型,为滚动的百分比,0为滚动到顶部,100为滚动到底部。
返回值:
- 不返回任何值的异步方法。
使用示例
// 将控件垂直滚动到底部
await model.getPane("Pane").vScroll(100);# 将控件垂直滚动到底部
model.getPane("Pane").vScroll(100)property(propertyIds)
获取控件的指定属性值。你可以根据需要获取控件的文本、是否可见、位置等各种属性。比如对于某个控件,调用方法.property("rect")其实就等同于直接调用属性方法.rect(),两个操作返回的值始终是相同的。
参数:
- propertyIds:
PropertyIds类型,要获取的属性名。
返回值:
- 异步的返回属性名对应的各种类型的属性值,包括
string、number、boolean、Rect类型等等,取决于propertyIds。
使用示例
获取控件的文本内容:
// 获取按钮的文本属性
let text = await model.getButton("Button").property("text");
console.log("按钮文本:", text);# 获取按钮的文本属性
text = model.getButton("Button").property("text")
print(f"按钮文本: {text}")也可以直接使用allProperties()方法中的字段:
// 获取控件的自定义属性
let objectName = await model.getButton("Button").property('objectName');# 获取控件的自定义属性
objectName = model.getButton("Button").property('objectName')waitProperty(propertyIds, value, timeoutSeconds)
等待控件的指定属性变为某个特定的值。你可以使用它来判断控件的状态是否符合预期,比如等待一个按钮变为可用状态。
参数:
- propertyIds:
PropertyIds类型,要等待的属性名。 - value:
string类型,要等待的属性值。 - timeoutSeconds:
number类型,等待时间,单位为秒,缺省为5秒,-1将无限等待。
返回值:
boolean类型,等待结果,true是成功等到该值,反之则是超出等待时间。如果报错则代表没有匹配到该控件,有可能是该控件未出现,或者是对象名称有问题。
使用示例
等待按钮由禁用状态变为可点击,然后点击它:
// 等待按钮变为可用状态
await model.getButton("下一步").waitProperty("enabled", true);
// 按钮可用后点击它
await model.getButton("下一步").click();# 等待按钮变为可用状态
model.getButton("下一步").waitProperty("enabled", True)
# 按钮可用后点击它
model.getButton("下一步").click()如果此控件有可能一直被禁用,可以通过判断它的返回值再执行点击或其他操作。
checkImage(options?: CheckImageCompareOptions | string)
用于验证控件的当前图像是否与指定的参考图像匹配。此方法是自动化测试中进行视觉校验的关键工具,确保 UI 控件的视觉表现符合预期。
checkImage()方法支持多种参数配置,更多关于此方法的说明及使用示例,请参考Virtual.checkImage()方法介绍。
参数:
它支持多种参数配置,允许您通过以下方式提供参考图像:
- 直接传递图像文件的路径字符串。
- 使用一个配置对象,在该对象中可以指定:
image: Base64 编码的图像数据。imagePath: 图像文件的路径。- 各种比较选项(如
pixelPercentTolerance,colorTolerance等)来调整比较的灵敏度。
- 若不提供具体的图像源,则默认与模型中该控件预存的参考图像进行比较。
返回值:
Promise<void>: 不返回任何值的异步方法。如果比较失败,则会抛出错误。
使用示例
假设我们有一个控件 Button,我们可以使用 checkImage() 来验证其当前显示的图像是否与预期相符。例如:
await model.getButton("Button").checkImage();model.getButton("Button").checkImage()checkProperty(propertyName, expectedValue, optionsOrMessage)
校验控件的属性值是否符合预期。如果指定的属性值不匹配期望值,则会抛出错误。
你可以在录制过程中快捷生成基于此方法的属性检查脚本,详情请参考录制中添加属性检查点。
参数:
- propertyName:
string类型,需要检查的属性名称。支持的属性名包括enabled、text、value等,以及所有由allProperties()方法返回的字段。 - expectedValue:
string | number | boolean | RegExp类型,期望的属性值。当控件的属性值与期望值匹配时,测试将通过;否则会抛出错误。 - optionsOrMessage:
string | object类型,可选参数。如果是字符串,它将被用作自定义错误信息;如果是对象,则可包含以下字段:- message:
string类型,自定义的错误信息。 - operation:
any类型,指定用于比较控件属性与期望值的运算符。默认值为equal,即验证属性值是否等于期望值。
- message:
返回值:
- 不返回任何值的异步方法。
使用示例
有关在
checkProperty()中使用正则表达式的示例,请参考通过正则表达式检查。
验证文本框控件的 text 属性是否为 "Hello World":
await model.getEdit("textEdit").checkProperty('text', 'Hello World', 'Text does not match expected value');model.getEdit("textEdit").checkProperty('text', 'Hello World', 'Text does not match expected value')如果文本不符合预期,将抛出一个错误,错误信息为 "Text does not match expected value"。
drag(x, y, mouseKey)
在控件位置按下鼠标左键,也就是拖拽操作的第一步,并等待松开鼠标的指令。传入的(x, y)为点击相对控件的坐标,当x和y同时为0或缺省时点击控件中心。
参数:
- x: (可选)
number类型,拖拽的起点相对控件左上角的水平像素点。 - y: (可选)
number类型,拖拽的起点相对控件左上角的垂直像素点。 - mouseKey: (可选)
MouseKey类型,使用的鼠标键,缺省为1。
返回值:
- 不返回任何值的异步方法。
使用示例
从控件中心开始拖拽:
// 在按钮中心按下鼠标,开始拖拽
await model.getButton("sourceButton").drag(0, 0);# 在按钮中心按下鼠标,开始拖拽
model.getButton("sourceButton").drag(0, 0)drop(x, y, options)
在控件位置松开鼠标左键,也就是拖拽操作的第二步。传入的(x, y)为点击相对控件的坐标,当x和y同时为0或缺省时点击控件中心。
可以在
A控件上执行drag()方法,在B控件上执行drop()方法,实现将A控件拖拽到B控件上的效果,具体文档可以查看拖拽控件的方法选择。
参数:
- x: (可选)
number类型,释放鼠标的位置相对控件左上角的水平像素点,缺省为0。 - y: (可选)
number类型,释放鼠标的位置相对控件左上角的垂直像素点,缺省为0。 - options: (可选)
object类型,自定义拖拽行为的配置对象。支持的选项包括:- duration:
number类型,鼠标移动到目标位置的持续时间,单位为秒。默认值为1,即1秒。 - mouseKeys:
number类型,在拖拽操作中使用的鼠标按键。1表示左键,2表示右键。默认值为左键(1)。
- duration:
返回值:
- 不返回任何值的异步方法。
使用示例
完成拖拽操作:
// 将按钮拖拽到另一个控件上
await model.getButton("sourceButton").drag(0, 0);
await model.getButton("targetButton").drop(10, 10);# 将按钮拖拽到另一个控件上
model.getButton("sourceButton").drag(0, 0)
model.getButton("targetButton").drop(10, 10)pressKeys(keys, options?)
通过模拟键盘信号来实现字符串输入或组合键操作,因此不仅可以用于简单的文本输入,还可以进行复杂的键盘操作,如模拟登录、导航、剪切、粘贴等操作。
需要注意,字符串中的某些特殊字符(如
^+~%{}())会被解析为控制键(如 Shift、Ctrl),而非作为字符输入。具体的键指令请参考附录: 输入键对应表。如果希望输入纯文本,无视这些控制键符号,请使用{textOnly: true}选项,这样调用:pressKeys(str, {textOnly: true})。
参数:
- keys:
string类型,要输入的按键、组合键或是字符串,最大支持 1024 个字符。 options:
PressKeysOptions | number(可选)
控制输入模式的可选参数,包含以下内容:- textOnly:
boolean类型,设为true时,将所有字符作为普通文本输入,忽略控制键指令。 - cpm:
number类型,即每分钟输入的字符数,用于控制输入速度。建议cpm值设置在 200 以上。由于不同系统及应用对输入速度的处理方式不同,实际的输入速度可能与设置值有所偏差。
如果直接传入数字作为
options,该值将被视为cpm参数。- textOnly:
返回值:
- 不返回任何值的异步方法。
使用示例
输入纯文本:
// 在输入框中输入文本,忽略特殊字符的控制键功能
await model.getEdit("Edit").pressKeys("Hello, World!", { textOnly: true });# 在输入框中输入文本,忽略特殊字符的控制键功能
model.getEdit("Edit").pressKeys("Hello, World!", { "textOnly": True })更多相关说明或样例,请参照模拟按键输入pressKeys方法。
takeScreenshot(filePath)
对控件截图,可以传入路径来将截图保存到路径位置。
参数:
- filePath:
string类型,截图文件的保存路径,如"./images/screenshot1.png"。
返回值:
- 异步的返回截图的
base64字符串。
使用示例
// 对按钮控件截图并保存到文件
await model.getButton("Button").takeScreenshot("./screenshots/button.png");# 对按钮控件截图并保存到文件
model.getButton("Button").takeScreenshot("./screenshots/button.png")takeScreenshot()方法返回的base64编码图片,可以直接作为图片插入到运行报告中,详细请参考报告附件。
highlight(duration)
控件高亮,用于调试和验证,可以传入高亮框的持续时间(单位为毫秒)。
参数:
- duration:
number类型,突出显示的持续时间,单位为毫秒。
返回值:
- 不返回任何值的异步方法。
使用示例
// 高亮按钮2秒钟,用于调试验证
await model.getButton("Button").highlight(2000);# 高亮按钮2秒钟,用于调试验证
model.getButton("Button").highlight(2000)doDefaultAction()
执行控件内部定义的默认操作,比如复选框的默认操作为切换、输入框的默认操作是编辑等。这些默认操作的定义,可以通过调用控件的allProperties()方法,查看结果中的LegacyIAccessible.defaultAction属性。
返回值:
- 不返回任何值的异步方法。
使用示例
// 执行复选框的默认操作(切换状态)
await model.getCheckBox("CheckBox").doDefaultAction();# 执行复选框的默认操作(切换状态)
model.getCheckBox("CheckBox").doDefaultAction()scrollIntoView()
滚动到控件的可视位置。
返回值:
- 不返回任何值的异步方法。
使用示例
// 将控件滚动到可见区域
await model.getButton("Button").scrollIntoView();# 将控件滚动到可见区域
model.getButton("Button").scrollIntoView()属性方法
需要注意的控件的属性方法都是异步的,在调用后CukeTest会与目标控件通信,获取控件当前的属性,即实时属性,而不是模型对象中的识别属性。下面列出的属性所有控件都支持,但不一定都有值,可以根据建议尝试类似的属性方法来获取目标属性。
type()
控件的类型,可能的值如控件类型枚举类所示。
返回值:
- 异步的返回控件类型字符串。
使用示例
// 获取控件的类型
let controlType = await model.getButton("Button").type();
console.log("控件类型:", controlType); // 输出: "Button"# 获取控件的类型
control_type = model.getButton("Button").type()
print(f"控件类型: {control_type}") # 输出: "Button"text()
控件的文本内容,通常是可编辑的内容,比如文本输入框Edit、多行输入框Document等控件拥有这个属性。如果返回值不符合预期,可以尝试name()或者value()属性方法。
返回值:
- 异步的返回控件文本内容。
使用示例
校验是否符合预期输入文本:
// 获取文本编辑器的内容并校验
let actual = await model.getDocument("文本编辑器").text();
let expected = 'Hello World!';
assert.equal(actual, expected);# 获取文本编辑器的内容并校验
actual = model.getDocument("文本编辑器").text()
expected = 'Hello World!'
assert actual == expectedrawText()
返回控件的内部文本信息。需要插件支持,从系统底层获取目标控件中渲染的文本信息。当name()、value()和text()方法都返回空结果时,可以尝试用rawText()方法获取文本。
此方法仅在通过“启动Windows应用”菜单启动的被测应用上能取到值,因为通过这种方式启动的被测应用会加载相应的插件。
返回值:
- 异步的返回控件的内部文本信息。
使用示例
// 当其他方法无法获取文本时,尝试使用rawText
let text = await model.getGeneric("CustomControl").rawText();
console.log("控件内部文本:", text);# 当其他方法无法获取文本时,尝试使用rawText
text = model.getGeneric("CustomControl").rawText()
print(f"控件内部文本: {text}")name()
控件的名称,这个名称通常情况下与模型管理器中对象的识别属性Name相一致,因此几乎所有的控件都有这一属性的值。如果返回值不符合预期,可以尝试text()或者value()属性方法。
返回值:
- 异步的返回控件名称。
使用示例
校验获取子元素是否符合预期:
// 滚动到列表的第一项并验证其名称
let item = await model.getList("List").scrollTo(0);
assert.strictEqual(await item.name(), 'First Normal Item');# 滚动到列表的第一项并验证其名称
item = model.getList("List").scrollTo(0)
assert item.name() == 'First Normal Item'hwnd()
控件所属的窗口句柄(Handle of WiNDow)。
返回值:
- 异步的返回窗口句柄的数值。
使用示例
// 获取窗口句柄
let handle = await model.getWindow("Window").hwnd();
console.log("窗口句柄:", handle);# 获取窗口句柄
handle = model.getWindow("Window").hwnd()
print(f"窗口句柄: {handle}")height()
控件的高度,返回值为number类型,单位为像素点。
返回值:
- 异步的返回控件高度(像素)。
使用示例
// 获取控件高度
let height = await model.getButton("Button").height();
console.log("控件高度:", height, "像素");# 获取控件高度
height = model.getButton("Button").height()
print(f"控件高度: {height} 像素")width()
控件的宽度,返回值为number类型,单位为像素点。
返回值:
- 异步的返回控件宽度(像素)。
使用示例
// 获取控件宽度
let width = await model.getButton("Button").width();
console.log("控件宽度:", width, "像素");# 获取控件宽度
width = model.getButton("Button").width()
print(f"控件宽度: {width} 像素")enabled()
控件是否可用。
返回值:
- 异步的返回控件是否可用的布尔值。
使用示例
// 检查按钮是否可用
let isEnabled = await model.getButton("Button").enabled();
if (isEnabled) {
console.log("按钮可用,可以点击");
}# 检查按钮是否可用
is_enabled = model.getButton("Button").enabled()
if is_enabled:
print("按钮可用,可以点击")focused()
控件是否被聚焦/被选中,当控件被选中时会返回true,通常会用于验证控件是否被操作到。
返回值:
- 异步的返回控件是否被聚焦的布尔值。
使用示例
// 检查输入框是否被聚焦
let isFocused = await model.getEdit("Edit").focused();
if (isFocused) {
console.log("输入框已聚焦,可以输入文本");
}# 检查输入框是否被聚焦
is_focused = model.getEdit("Edit").focused()
if is_focused:
print("输入框已聚焦,可以输入文本")visible()
控件是否可见且未被遮挡,当控件被选中时会返回true,通常会用于验证控件是否可以被操作。比如在以下场景中,此方法会返回false:
- 控件被其它控件或窗口/对话框遮住;
- 控件在可视区域外;
- 控件在桌面外;
如果控件不存在,此方法会抛找不到对象的错误。如果希望不抛错,可以结合exists()方法来使用,如:
if await control.exists() && await control.visible(){
// 执行操作
}if control.exists() and control.visible():
# 执行操作helpText()
控件的帮助文本,即鼠标悬停在控件上时出现的浮动提示消息的内容,通常在WPF、WinForm框架的应用中会遇到。
value()
控件的值,比如滑动条控件Slider、滚动条控件ScrollBar会返回对应的数值。如果希望取得控件显示的名称或者提示文字,可以尝试text()或者name()属性方法。
返回值:
- 异步的返回控件的值,可能是字符串或数字。
使用示例
校验控件值:
// 获取输入框的值并校验
let actual = await model.getEdit("Edit").value();
let expected = 'Hello World!';
assert.equal(actual, expected);# 获取输入框的值并校验
actual = model.getEdit("Edit").value()
expected = 'Hello World!'
assert actual == expectedprocessId()
控件所属应用的进程号(Process Id)。
返回值:
- 异步的返回进程号。
使用示例
// 获取控件所属进程的ID
let pid = await model.getWindow("Window").processId();
console.log("进程ID:", pid);# 获取控件所属进程的ID
pid = model.getWindow("Window").processId()
print(f"进程ID: {pid}")rect()
控件的描述矩形,返回Rect类型,包含控件的x、y、height和width信息,定义如Rect 类型所示。
返回值:
- 异步的返回包含控件位置和尺寸信息的
Rect对象。
使用示例
// 获取控件的位置和尺寸信息
let rect = await model.getButton("Button").rect();
console.log(`控件位置: (${rect.x}, ${rect.y}), 尺寸: ${rect.width}x${rect.height}`);# 获取控件的位置和尺寸信息
rect = model.getButton("Button").rect()
print(f"控件位置: ({rect['x']}, {rect['y']}), 尺寸: {rect['width']}x{rect['height']}")allProperties()
获取目标控件的所有运行时属性,以对象的形式返回。如果希望直接返回指定属性的值,参考property(propertyIds)方法。
返回值:
- 异步的返回目标模型对象的属性组成的对象
object。
使用示例
// 获取按钮的所有运行时属性
let properties = await model.getButton("Button").allProperties();
console.log(properties);
// 只获取其中的一个属性,如objectName
console.log('objectName=' + properties['objectName']);# 获取按钮的所有运行时属性
properties = model.getButton("Button").allProperties()
print(properties)
# 只获取其中的一个属性,如objectName
print('objectName=' + properties['objectName'])会获取按钮的所有属性,并打印:
{
"name": "Normal",
"className": "CheckBox",
"automationId": "",
"accessKey": "",
"enabled": true,
"hasKeyboardFocus": false,
...
"interfaces": [
"Toggle",
"LegacyIAccessible"
],
"Toggle.toggleState": 0,
"LegacyIAccessible.defaultAction": "选定",
"LegacyIAccessible.description": "",
"LegacyIAccessible.help": "",
"LegacyIAccessible.keyboardShortcut": "",
"LegacyIAccessible.name": "Normal",
"LegacyIAccessible.role": 44,
"LegacyIAccessible.state": 1048576,
"LegacyIAccessible.value": ""
}
其中,interfaces字段用于返回控件的模式信息(UIA Pattern Names),帮助用户确认控件支持的操作行为。LegacyIAccessible.defaultAction是这个控件的缺省操作,如果不为空,那么用户可以通过调用doDefaultAction来执行这个缺省操作。
modelImage(options?)
控件在模型中缓存的截图快照。默认返回快照的base64字符串。
参数:
- options:
object类型,可选参数,包含以下字段:- encoding:
"buffer"或"base64"字符串参数,控制图片返回的编码,默认为"base64"。
- encoding:
返回值:
string类型或Buffer类型,根据指定的options.encoding选项异步的返回图片数据,默认为string类型。
使用示例
// 获取模型中的截图(base64格式)
let imageBase64 = await model.getButton("Button").modelImage();# 获取模型中的截图(base64格式)
image_base64 = model.getButton("Button").modelImage()modelProperties(all?)
控件在模型中缓存的属性。默认仅返回识别属性,传入true参数同时获取不用于识别的其它属性。
参数:
- all:
boolean类型,可选参数,是否获取所有属性。默认为false,只获取识别属性。
返回值:
- 属性对象。
使用示例
// 获取窗口的模型属性
let modelProperties = await model.getWindow("Standard_Dialogs").modelProperties();
console.log(modelProperties);
assert.equal('Window', modelProperties.type);# 获取窗口的模型属性
modelProperties = model.getWindow("Standard_Dialogs").modelProperties()
print(modelProperties)
assert modelProperties['type'] == 'Window'输出的modelProperties为:
{ type: 'Window', className: 'Dialog', text: 'Standard Dialogs' }
高级方法:控件导航(Navigation)
CukeTest提供了一系列的控件导航方法,使得用户可以使用导航方法检索到目标控件的父控件、子控件以及兄弟控件。通过导航方法可以借助一个锚点控件索引到整棵控件树中所有的控件,常用于输入框定位、控件遍历等场景。
导航方法都是异步方法,也就是需要一定时间在应用里面检索到被导航的控件并返回,并不是直接在模型管理器的树中进行导航,这点需要区分不要混淆。
有关控件导航的使用,可以参考附录H:CukeTest自带样例中的"文件浏览器遍历"。
firstChild(controlType?)
获取控件在应用中的第一个子控件,可以通过传入参数controlType指定子控件类型,可以实现筛选的效果,即获取应用中的第一个controlType类型的子控件,controlType为字符串,可选值可以参考ControlType。如果没有任何满足条件的子控件则返回null。
同时,child仅代表直系的子控件,不会检索到孙控件,如果没有在子控件中检索到满足条件的控件,会直接返回null而不是继续在孙控件中搜索。如果仍希望获得某个控件下的所有控件,可以使用findControls方法。
注意,如果某些控件是不可见或还未加载的,那么是不会被计入的,准确来说,
firstChild()方法只是拿到可以拿到的子对象中的第一个,下面的lastChild()方法同样。
参数:
- controlType: (可选)
string类型,可选参数,可选值可以参考ControlType。
返回值:
- 异步的任意控件类型,具体类型取决于导航到的控件类型。没有导航到任何控件时返回
null。
使用示例
// 获取容器的第一个子控件
let firstChild = await model.getPane("Container").firstChild();
if (firstChild) {
console.log("找到第一个子控件");
}# 获取容器的第一个子控件
first_child = model.getPane("Container").firstChild()
if first_child:
print("找到第一个子控件")lastChild(controlType?)
获取控件在应用中的最后一个子控件,可以通过传入参数controlType指定子控件类型,可以实现筛选的效果,即获取应用中的最后一个controlType类型的子控件,controlType为字符串,可选值可以参考ControlType。如果没有任何满足条件的子控件则返回null。
注意,如果某些控件是不可见或还未加载的,那么是不会被计入的,准确来说,
lastChild()方法只是拿到可以拿到的子对象中的最后一个。
参数:
- controlType: (可选)
string类型,可选参数,可选值可以参考ControlType。
返回值:
- 异步的任意控件类型,具体类型取决于导航到的控件类型。没有导航到任何控件时返回
null。
使用示例
// 获取容器的最后一个子控件
let lastChild = await model.getPane("Container").lastChild();
if (lastChild) {
console.log("找到最后一个子控件");
}# 获取容器的最后一个子控件
last_child = model.getPane("Container").lastChild()
if last_child:
print("找到最后一个子控件")next(controlType?)
获取控件在应用的下一个兄弟控件,通常为相邻的右侧/下方节点,取决于容器的布局方向。可以通过传入参数controlType指定兄弟控件类型,可以实现筛选的效果,即获取应用中的下一个controlType类型的兄弟控件,controlType为字符串,可选值可以参考ControlType。如果没有任何满足条件的兄弟控件则返回null,比如当控件作为父控件的lastChild时会返回null。
参数:
- controlType: (可选)
string类型,可选参数,可选值可以参考ControlType。
返回值:
- 异步的任意控件类型,具体类型取决于导航到的控件类型。没有导航到任何控件时返回
null。
使用示例
// 获取当前控件的下一个兄弟控件
let nextControl = await model.getButton("Button1").next();
if (nextControl) {
await nextControl.click();
}# 获取当前控件的下一个兄弟控件
next_control = model.getButton("Button1").next()
if next_control:
next_control.click()previous(controlType?)
与next()方法相反,获取控件在应用的上一个兄弟控件,通常为相邻的左侧/上方节点,取决于容器的布局方向。可以通过传入参数controlType指定兄弟控件类型,可以实现筛选的效果,即获取应用中的上一个controlType类型的兄弟控件,controlType为字符串,可选值可以参考ControlType。如果没有任何满足条件的兄弟控件则返回null,比如当控件作为父控件的firstChild时会返回null。
参数:
- controlType: (可选)
string类型,可选参数,可选值可以参考ControlType。
返回值:
- 异步的任意控件类型,具体类型取决于导航到的控件类型。没有导航到任何控件时返回
null。
使用示例
// 获取当前控件的上一个兄弟控件
let prevControl = await model.getButton("Button2").previous();
if (prevControl) {
await prevControl.click();
}# 获取当前控件的上一个兄弟控件
prev_control = model.getButton("Button2").previous()
if prev_control:
prev_control.click()parent()
与firstChild()和lastChild()方法相反,获取控件的父控件,如果控件为最顶层控件则返回null。
返回值:
- 异步的任意控件类型,具体类型取决于导航到的控件类型。没有导航到任何控件时返回
null。
使用示例
// 获取控件的父控件
let parentControl = await model.getButton("Button").parent();
if (parentControl) {
console.log("找到父控件");
}# 获取控件的父控件
parent_control = model.getButton("Button").parent()
if parent_control:
print("找到父控件")all()
all()方法返回与当前控件的“标识属性”相匹配的所有同级控件数组,无需指定任何筛选条件。这个方法适用于在测试中实现对同一层级多个控件的批量操作,如表格、列表或一组按钮。详细用法参见获取对象API。
返回值:
- 异步的控件数组,包含所有同级控件对象。如果没有找到任何控件,则返回空数组。
使用示例
// 获取所有同级的按钮控件
let controls = await model.getButton("Normal").all();
console.log('控件数量:', controls.length);
// 遍历所有控件
for (let control of controls) {
console.log(await control.name());
}# 获取所有同级的按钮控件
controls = model.getButton("Normal").all()
print(f"控件数量: {len(controls)}")
# 遍历所有控件
for control in controls:
print(control.name())findControls(...conditions)
findControls()方法是一个强大的查询工具,用于根据一系列条件筛选出满足这些条件的控件集合。它接受一个或多个ConditionFilter对象作为参数,这些对象定义了控件筛选的条件。
此方法适用于需要根据特定条件从应用中检索控件的场景。例如,在具有动态内容的界面上,您可能需要找到所有具有特定属性或状态的控件。findControls()方法可以根据您提供的条件动态地识别并返回这些控件。详细用法参见获取对象API。
参数:
- conditions:
ConditionFilter[]类型,一个或多个筛选条件。
返回值:
- 异步返回一个
IWinControl数组,该数组包含满足提供的筛选条件的所有控件。如果没有找到符合条件的控件,则返回空数组。
使用示例
// 查找所有按钮类型的控件
let buttons = await model.getPane("MainPane").findControls({type: "Button"});
console.log(`找到${buttons.length}个按钮`);
// 遍历并操作所有找到的按钮
for (let button of buttons) {
await button.click();
}# 查找所有按钮类型的控件
buttons = model.getPane("MainPane").findControls({"type": "Button"})
print(f"找到{len(buttons)}个按钮")
# 遍历并操作所有找到的按钮
for button in buttons:
button.click()控件导航应用场景
例1: 输入框定位
在部分应用中存在需要填写的表单,即:
表单:
[标签1]: [输入框1]
[标签2]: [输入框2]
[标签3]: [输入框3]
[标签4]: [输入框4]
对于一些应用的输入框可能没有足够的属性用于识别,而所有的标签和输入框又属于同一个容器(表单)中没有隔离,那么CukeTest可能会将输入框1-4当作相同的输入框,这个时候就可以通过添加标签对象,接着使用导航方法获得其右侧的输入框控件,就可以得到目标输入框:
let labels = ["标签1", "标签2", "标签3", "标签4"]
for(let label of labels){
let input = await model.getText(label).next();
await input.set("需要输入的值");
}labels = ["标签1", "标签2", "标签3", "标签4"]
for label in labels:
input = model.getText(label).next()
input.set("需要输入的值")例2: 控件遍历
可以通过递归调用导航方法的方式,遍历到整个应用中的所有控件。