对象共有的方法和属性

下面介绍是每个控件(虚拟控件除外)都有的基础的操作和属性方法。这些方法不管被操作控件是何种控件(或者说都会被当作自定义控件Custom来对待),部分方法是基于模拟用户操作,部分是基于系统提供的底层Accessibility API完成的操作。

类型定义文件

这些方法都写在控件的基类上,可以点击leanpro.win库查看,定义如下:

JavaScript
Python
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?: CompareOptions): 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>
}
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

可能用到的类定义

以下是调用共有API时可能会使用到的一些类型定义。

Rect类

用于描述控件形状与位置信息的对象。在CukeTest中,所有控件都可以用一个矩形(Bounding Rectangle)来描述位置和形状信息,Rect对象包含以下属性:

  • x: number类型,相对坐标的水平像素;
  • y: number类型,相对坐标的垂直像素;
  • width: number类型,水平宽度,单位为像素;
  • height: number类型,垂直高度,单位为像素;

鼠标键枚举类:MouseKey

用于鼠标单击方法click()与双击方法dblClick()的一个枚举类,可以指定点击所使用鼠标按键使用时传入对应的数字即可。

这个枚举类中也包含部分键盘的控制键,但是通常不会用到。
类似的枚举类在鼠标操作库Mouse中也能看到。

JavaScript
enum MouseKey {
    LButton = 1, // 鼠标左键
    RButton = 2, // 鼠标右键
    MButton = 4, // 鼠标中键/滚轮键
    Ctrl = 8, // 键盘CTRL键 
    Shift = 16, // 键盘SHIFT键
    Alt = 32 // 键盘ALT键
}

控件属性名枚举类: PropertyIds

JavaScript
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()方法返回结果的类型也都在这个枚举类中。

JavaScript
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): Promise<void>

鼠标点击控件,可以通过传入参数修改点击的相对位置(偏移量)和使用的鼠标键。

  • x: number类型,点击位置相对控件左上角的水平像素点,0代表控件的水平中点位置,缺省值为0;
  • y: number类型,点击位置相对控件左上角的垂直像素点,0代表控件的垂直中点位置,缺省值为0;
  • mouseKey: MouseKey类型,操作的鼠标键,缺省为1,即鼠标左键。

最简单的调用方式就是不使用任何参数调用,效果是鼠标左键点击目标控件的正中心。

这里假设目标控件为按钮控件Button

JavaScript
Python
await model.getButton("Button").click()
model.getButton("Button").click()

如果需要点击控件的指定坐标位置,可以传入相对控件左上角的水平像素值(x)和垂直像素值(y

JavaScript
Python
await model.getButton("Button").click(590, 10)
model.getButton("Button").click(590, 10)

需要注意的是,click(0, 0)并不会点击控件左上角原点,而是点击控件正中心;如果期望点击左上角,可以用click(1, 1)代替。

如果需要右击控件,则需要传入第三个参数并设置为2:

JavaScript
Python
await model.getButton("Button").click(590, 10, 2)
model.getButton("Button").click(590, 10, 2)
如果需要右键点击控件正中心,也可以使用下面这种语法:

JavaScript
Python
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): Promise<void>

鼠标双击控件,与click()方法的调用方式一致,通过传入参数修改点击的相对位置(偏移量)和使用的鼠标键。

  • x: number类型,点击位置相对控件左上角的水平像素点,0代表控件的水平中点位置,缺省值为0;
  • y: number类型,点击位置相对控件左上角的垂直像素点,0代表控件的垂直中点位置,缺省值为0;
  • mouseKey: MouseKey类型,操作的鼠标键,缺省为1,即鼠标左键。

使用方法可参考上面的click()

moveMouse(x, y): Promise<void>

移动鼠标光标到控件的相对位置,缺省移动到控件中心。

  • x: number类型,点击位置相对控件左上角的水平像素点,0代表控件的水平中点位置,缺省值为0;
  • y: number类型,点击位置相对控件左上角的垂直像素点,0代表控件的垂直中点位置,缺省值为0;

使用 不传入任何参数调用会默认将鼠标移动到控件中心位置。

这里假设目标控件为按钮控件Pane

JavaScript
Python
await model.getPane("Pane").moveMouse()
model.getPane("Pane").moveMouse()
如果需要移动鼠标到控件的指定坐标位置,可以传入相对控件左上角的水平像素值(x)和垂直像素值(y

JavaScript
Python
await model.getPane("Pane").moveMouse(500, 70)
model.getPane("Pane").moveMouse(500, 70)

同样,moveMouse(0, 0)鼠标并不会移动到控件左上角原点,而是移动到控件正中心;如果期望是左上角,可以用moveMouse(1, 1)代替。

如果需要移动鼠标的同时控制鼠标移动的速度,第三个参数可以传入持续时间多少秒。

JavaScript
Python
await model.getPane("Pane").moveMouse(500, 70, 5)
model.getPane("Pane").moveMouse(500, 70, 5)

wheel(value): Promise<void>

滚动鼠标滚轮,输入参数的单位为滚轮滚动的刻度。最多翻一页,如果需要滚动多页,请循环调用。

  • value: number类型,单位为一个滚轮刻度。

exists(time): Promise<boolean>

检查控件是否存在,输入参数为检查等待的最长时间(超时时间)。缺省调用只会检查一次而不会重试与等待。

  • time: number类型,超时时间,单位为,当为0时不会重试和等待,缺省参数为0
  • 返回值: 异步的返回控件是否存在,true为存在,false为不存在。

使用 不传入参数缺省重试为0秒,即只检查1次。

JavaScript
Python
await model.getApplication("dirview").exists();
model.getApplication("dirview").exists()

传入最长等待时间,如果在设置的最长等待时间内检测到控件存在则直接返回true 控件匹配结果出错或者是超过传入的最长等待时间则返回false

JavaScript
Python
let bool = await model.getApplication("dirview").exists(10);
assert.strictEqual(bool, true);
bool = model.getApplication("dirview").exists(10)
assert bool == True

hScroll(value): Promise<void>

在控件上进行水平滚动,即Horizontal Scroll,参数为滚动的百分比。

  • value: number类型,为滚动的百分比,0为滚动到顶部,100为滚动到底部。

vScroll(value): Promise<void>

在控件上进行垂直滚动,即Vertical Scroll,参数为滚动的百分比。

  • value: number类型,为滚动的百分比,0为滚动到顶部,100为滚动到底部。

property(propertyIds): Promise<string | boolean | number | Rect>

这个方法比较特殊,虽然属于操作方法,但是却是获取指定属性的方法,传入属性名,返回对应的属性值。比如对于某个控件,调用方法.property("rect")其实就等同于直接调用属性方法.rect(),两个操作返回的值始终是相同的。 同时也支持直接使用allProperties()方法中的字段,详见下面的代码示例。

如果传入了一个不存在的属性名,则会返回undefined,而不会出错。

  • propertyIds: propertyIds类型,控件属性的名称。
  • 返回值: 异步的返回属性名对应的各种类型的属性值,包括stringnumberbooleanRect类型等等,取决于propertyIds

JavaScript
Python
let properties = await model.getButton("Button").allProperties();
console.log(properties['objectName']); //只获取其中的一个属性,如objectName
properties = model.getButton("Button").allProperties()
print(properties['objectName']); #只获取其中的一个属性,如objectName

可以直接调用property()获得:

JavaScript
Python
let objectName = await model.getButton("Button").property('objectName');
objectName = model.getButton("Button").property('objectName')

waitProperty(propertyIds, value, timeoutSeconds): Promise<boolean>

与上面的property()方法类似,但是会等待直到属性出现某值,返回值表示是否成功等到该值出现。

  • propertyIds: PropertyIds类型,控件属性的名称。
  • value: string类型,期望的值。
  • timeoutSeconds: number类型,超时时间,单位为秒。等待超时秒设置,缺省为10秒,-1将无限等待。
  • 返回值: boolean类型,等待结果,true是成功等到该值,反之则是超出等待时间。如果报错则代表没有匹配到该控件,有可能是该控件未出现,或者是对象名称有问题。

下面的样例代码等待按钮由禁用状态变为可点击,然后点击它:

JavaScript
Python
await model.getButton("下一步").waitProperty("enabled", true);
await model.getButton("下一步").click();
model.getButton("下一步").waitProperty("enabled", true)
model.getButton("下一步").click()
如果此控件有可能一直被禁用,可以通过判断它的返回值再执行点击或其他操作。

checkImage(options?: CompareOptions): Promise<void>

用于验证控件的当前图像与预先定义或录制的参考图像是否匹配。如果存在差异,测试会抛出错误并显示图像间的差异。这个方法可用于自动化测试中的视觉校验,确保 UI 控件的视觉展现符合预期。

  • options (可选): 用于配置图像比较的选项。这些选项与 Image.imageEqual 方法的参数相同,包含以下属性:
    • colorTolerance: number 类型,定义了在颜色匹配时允许的最大差异容忍度。默认值为 0.1。
    • pixelPercentTolerance: number 类型,定义了允许的最大像素百分比差异容忍度。默认值为 1,表示最多允许 1% 的像素差异。
    • pixelNumberTolerance: number 类型,定义了允许的像素数量差异容忍度。如果设置为0,则无差异容忍。
    • ignoreExtraPart: boolean 类型,用于指定是否忽略图像中的额外部分。默认为 false。
    • auto:boolean类型,如果设置为true,则根据图像特征自动识别两幅图片,并将它们缩放到一致的比例进行比较,默认适应到较小尺寸那张图片的比例。
  • 返回值:不返回任何值的异步方法。

使用示例

假设我们有一个控件 Button,我们可以使用 checkImage() 来验证其当前显示的图像是否与预期相符。例如:

JavaScript
Python
await Button.checkImage({
    colorTolerance: 0.05,
    pixelPercentTolerance: 0.5
});
Button.checkImage({
    "colorTolerance": 0.05,
    "pixelPercentTolerance": 0.5
})

在这个例子中,checkImage 方法将会验证 Button 控件的图像与预期的参考图像在颜色容忍度为 0.05 和像素百分比差异容忍度为 0.5% 的条件下是否相匹配。如果图像存在超出这些指定容忍度的差异,测试将会抛出错误。

checkProperty(propertyIds, expectedValue, message): Promise<void>

方法提供了一种方便的方式来添加对控件属性的校验点。如果控件的指定属性不满足预期值,则会抛出错误。

  • propertyIds: 需要检查的属性名,PropertyIds类型。支持的属性名有enabled, text, value等,以及所有 allProperties() 方法返回的字段。具体可参见可选属性字段
  • expectedValue: string | number | boolean | RegExp类型,期望值。当控件属性与期望值匹配时,测试会通过;否则会抛出错误。
  • optionsOrMessage:string | object类型,可选参数。如果是字符串,会被作为错误信息;如果是对象,可以包含以下字段:
    • message:string类型,错误信息。
    • operation:any类型,比较控件属性与期望值的运算符。默认为 equal,即验证两者是否相等。

基于本方法的属性检查脚本可在录制过程中快捷生成,详情参考录制中添加属性检查点

使用示例

假设我们有一个文本框控件 Edit,我们可以使用checkProperty()来验证其text属性是否等于预期的值。例如:

JavaScript
Python
await Edit.checkProperty('text', 'Hello World');
Edit.checkProperty('text', 'Hello World')

上述代码会验证文本框的文本是否为"Hello World",如果不是,则会抛出错误。

如果我们想要添加自定义的错误信息,可以这样做:

JavaScript
Python
await Edit.checkProperty('text', 'Hello World', 'Text does not match expected value');
Edit.checkProperty('text', 'Hello World', 'Text does not match expected value')

如果文本框的文本不是"Hello World",那么会抛出一个错误,错误信息为Text does not match expected value

drag(x, y): Promise<void>

在控件位置按下鼠标左键,也就是拖拽操作的第一步,并等待松开鼠标的指令。传入的(x, y)为点击相对控件的坐标,当xy同时为0或缺省时点击控件中心。

  • x: (可选)number类型,相对于控件水平中心的偏移像素,默认值为控件水平中心。
  • y: (可选)number类型,相对于控件垂直中心的偏移像素,默认值为控件垂直中心。
  • mouseKey:(可选)number类型,拖拽时使用的鼠标键,1表示左键,2表示右键。默认值为左键(1)。
  • 返回值: 不返回任何值的异步方法。

可以参考拖拽控件的方式选择

drop(x, y, seconds): Promise<void>

在控件位置松开鼠标左键,也就是拖拽操作的第二步。传入的(x, y)为点击相对控件的坐标,当xy同时为0或缺省时点击控件中心。可以在A控件上执行drag()方法,在B控件上执行drop()方法,实现将A控件拖拽到B控件上的效果,具体文档可以查看拖拽控件的方法选择

  • x: (可选)number类型,相对于控件水平中心的偏移像素,左为负值,右为正值。默认值为0
  • y: (可选)number类型, 相对于控件垂直中心的偏移像素,上为负值,下为正值。默认值为0
  • options:(可选)object类型,自定义拖拽行为的配置对象。支持的选项包括:
    • duration: number类型,鼠标移动到目标位置的持续时间,单位为秒。默认值为1,即1秒;
    • mouseKeys: number类型,在拖拽操作中使用的鼠标按键。1表示左键,2表示右键。默认值为左键(1)。
  • 返回值: 不返回任何值的异步方法。

可以参考拖拽控件的方式选择

pressKeys(keys, options?): Promise<void>

输入按键或字符串,输入前会聚焦目标控件。传入字符串时,字符串中的一些特殊字符(^+~%{}())会被当作控制键(Shift键、CTRL键等)来执行,而不会输入相应的符号,具体可以参考附录: 输入键对应表。如果希望输入纯文本,无视这些控制键符号,则可以使用{textOnly: true}选项,这样调用:pressKeys(str, {textOnly: true})

  • keys: string类型,要输入的按键、组合键或是字符串,最大支持1024个字符。
  • options: (可选)控制输入模式的一些可选参数。
    • textOnly: 仅输入字符串,并将控制字符也当作文本进行输入。效果等同于调用Keyboard.typeString()
    • cpm: 即每分钟输入字符数,用于控制文本输入速度。自动化操作时建议cpm值设置在200以上。由于方法的内部实现,以及各个系统、应用对文本输入的处理不相同,实际输入速度不一定能达到设置的cpm。 当options为数字时相当于cpm参数。
  • 返回值: 不返回任何值的异步方法。 更多相关说明或样例,请参照模拟按键输入pressKeys方法

takeScreenshot(filePath): Promise<string>

控件截图,可以传入路径来将截图保存到路径位置。

  • filePath: (可选)string类型,截图的保存路径和文件名,如"./images/screenshot1.png"
  • 返回值: 异步的返回截图的base64字符串。

使用示例

截取整个屏幕图片,以png格式保存,并返回截图的base64编码,可以直接作为运行报告的报告附件

highlight(miliseconds?: number): Promise<void>

控件高亮,可以传入高亮框的持续时间(单位为毫秒)。

  • miliseconds: number类型,高亮框的持续时间,单位为毫秒(ms)。
  • 返回值:不返回任何值的异步方法。

doDefaultAction(): Promise<void>

执行控件内部定义的默认操作,比如复选框的默认操作为切换、输入框的默认操作是编辑等。这些默认操作的定义,可以通过调用控件的allProperties()方法,查看结果中的LegacyIAccessible.defaultAction属性。

  • 返回值:不返回任何值的异步方法。

属性方法定义

需要注意的控件的属性方法都是异步的,在调用后CukeTest会与目标控件通信,获取控件当前的属性,即实时属性,而不是模型对象中的识别属性。下面列出的属性所有控件都支持,但不一定都有值,可以根据建议尝试类似的属性方法来获取目标属性。

type(): Promise<string>

控件的类型,可能的值如控件类型枚举类所示。

text(): Promise<string>

控件的文本内容,通常是可编辑的内容,比如文本输入框Edit、多行输入框Document等控件拥有这个属性。如果返回值不符合预期,可以尝试name()或者value()属性方法。

校验是否符合预期输入文本

JavaScript
Python
let actual = await model.getDocument("文本编辑器").text();
let expected = 'Hello World!'
assert.equal(actual, expected);

rawText(): Promise<string>

返回控件的内部文本信息。需要插件支持,从系统底层获取目标控件中渲染的文本信息。当name()value()text()方法都返回空结果时,可以尝试用rawText()方法获取文本。

此方法仅在通过“启动Windows应用”菜单启动的被测应用上能取到值,因为通过这种方式启动的被测应用会加载相应的插件。

name(): Promise<string>

控件的名称,这个名称通常情况下与模型管理器中对象的识别属性Name相一致,因此几乎所有的控件都有这一属性的值。如果返回值不符合预期,可以尝试text()或者value()属性方法。

校验获取子元素是否符合预期

JavaScript
Python
let item = await model.getList("List").scrollTo(0);
assert.strictEqual(await item.name(), 'First Normal Item');
item = await model.getList("List").scrollTo(0)
assert await item.name() == 'First Normal Item'

hwnd(): Promise<number>

控件所属的窗口句柄(Handle of WiNDow)。

x(): Promise<number>

控件的水平桌面坐标,返回值为number类型,单位为像素点。

y(): Promise<number>

控件的垂直桌面坐标,返回值为number类型,单位为像素点。

height(): Promise<number>

控件的高度,返回值为number类型,单位为像素点。

width(): Promise<number>

控件的宽度,返回值为number类型,单位为像素点。

enabled(): Promise<boolean>

控件是否可用。

focused(): Promise<boolean>

控件是否被聚焦/被选中,当控件被选中时会返回true,通常会用于验证控件是否被操作到。

visible(): Promise<boolean>

控件是否可见且未被遮挡,当控件被选中时会返回true,通常会用于验证控件是否可以被操作。比如在以下场景中,此方法会返回false

  • 控件被其它控件或窗口/对话框遮住;
  • 控件在可视区域外;
  • 控件在桌面外;

如果控件不存在,此方法会抛找不到对象的错误。如果希望不抛错,可以结合exists()方法来使用,如:

JavaScript
Python
if await control.exists() && await control.visible(){
  // 执行操作
}
if control.exists() and control.visible():
  # 执行操作

helpText(): Promise<string>

控件的帮助文本,即鼠标悬停在控件上时出现的浮动提示消息的内容,通常在WPF、WinForm框架的应用中会遇到。

value(): Promise<string | number>

控件的值,比如滑动条控件Slider、滚动条控件ScrollBar会返回对应的数值。如果希望取得控件显示的名称或者提示文字,可以尝试text()或者name()属性方法。

校验控件值

JavaScript
let actual = await modelQt.getEdit("Edit").value();
let expected = 'Hello World!';
assert.equal(actual, expected);

processId(): Promise<number>

控件所属应用的进程号(Process Id)。

rect(): Promise<Rect>

控件的描述矩形,返回Rect类型,包含控件的xy``heightwidth信息,定义Rect类型所示。

allProperties(): Promise<object>

获取目标控件的所有运行时属性,以对象的形式返回。如果希望直接返回指定属性的值,参考property(propertyIds)方法

  • 返回值: 异步的返回目标模型对象的属性组成的对象object。 例如:

JavaScript
Python
let properties = await model.getButton("Button").allProperties();
console.log(properties);
console.log('objectName=' + properties['objectName']); //只获取其中的一个属性,如objectName
properties = model.getButton("Button").allProperties()
print(properties)
print('objectName=' + properties['objectName']); #只获取其中的一个属性,如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?: {encoding: 'buffer' | 'base64'}): Promise<string|Buffer>

控件的在模型中缓存的截图快照。默认返回快照的base64字符串。

  • options:(可选)选项:
    • encoding: "buffer""base64"字符串参数,控制图片返回的编码,默认为"base64"
  • 返回值: string类型或Buffer类型,根据指定的options.encoding选项异步的返回图片数据,默认为string类型。

modelProperties(all?: boolean): object

控件在模型中缓存的属性。默认仅返回识别属性,传入true参数同时获取不用于识别的其它属性。

  • all: (可选)boolean类型,是否获取所有属性。默认为false,只获取识别属性。
  • 返回值:属性对象。

使用示例

JavaScript
Python
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' }

CukeTest提供了一系列的控件导航方法,使得用户可以使用导航方法检索到目标控件的父控件、子控件以及兄弟控件。通过导航方法可以借助一个锚点控件索引到整棵控件树中所有的控件,常用于输入框定位、控件遍历等场景。

导航方法都是异步方法,也就是需要一定时间在应用里面检索到被导航的控件并返回,并不是直接在模型管理器的树中进行导航,这点需要区分不要混淆。

有关控件导航的使用,可以参考附录H:CukeTest自带样例中的"文件浏览器遍历"。

firstChild(controlType?: string): Promise<IWinControl>

获取控件在应用中的第一个子控件,可以通过传入参数controlType指定子控件类型,可以实现筛选的效果,即获取应用中的第一个controlType类型的子控件,controlType为字符串,可选值可以参考ControlType。如果没有任何满足条件的子控件则返回null。 同时,child仅代表直系的子控件,不会检索到孙控件,如果没有在子控件中检索到满足条件的控件,会直接返回null而不是继续在孙控件中搜索。如果仍希望获得某个控件下的所有控件,可以使用findControls方法。

注意,如果某些控件是不可见或还未加载的,那么是不会被计入的,准确来说,firstChild()方法只是拿到可以拿到的子对象中的第一个,下面的lastChild()方法同样。

  • controlType: (可选)字符串类型,可选值可以参考ControlType
  • 返回值: 异步的任意控件类型,具体类型取决于导航到的控件类型。没有导航到任何控件时返回null

lastChild(controlType?: string): Promise<IWinControl>

获取控件在应用中的最后一个控件,可以通过传入参数controlType指定子控件类型,可以实现筛选的效果,即获取应用中的最后一个controlType类型的子控件,controlType为字符串,可选值可以参考ControlType。如果没有任何满足条件的子控件则返回null

注意,如果某些控件是不可见或还未加载的,那么是不会被计入的,准确来说,firstChild()方法只是拿到可以拿到的子对象中的第一个,下面的lastChild()方法同样。

  • controlType: (可选)字符串类型,可选值可以参考ControlType
  • 返回值: 异步的任意控件类型,具体类型取决于导航到的控件类型。没有导航到任何控件时返回null

next(controlType?: string): Promise<IWinControl>

获取控件的在应用的下一个兄弟控件,通常为相邻的右侧/下方节点,取决于容器的布局方向。可以通过传入参数controlType指定兄弟控件类型,可以实现筛选的效果,即获取应用中的下一个controlType类型的兄弟控件,controlType为字符串,可选值可以参考ControlType。如果没有任何满足条件的兄弟控件则返回null,比如当控件作为父控件的lastChild时会返回null

  • controlType: (可选)字符串类型,可选值可以参考ControlType
  • 返回值: 异步的任意控件类型,具体类型取决于导航到的控件类型。没有导航到任何控件时返回null

previous(controlType?: string): Promise<IWinControl>

next()方法相反,获取控件的在应用的上一个兄弟控件,通常为相邻的左侧/上方节点,取决于容器的布局方向。可以通过传入参数controlType指定兄弟控件类型,可以实现筛选的效果,即获取应用中的下一个controlType类型的兄弟控件,controlType为字符串,可选值可以参考ControlType。如果没有任何满足条件的兄弟控件则返回null,比如当控件作为父控件的firstChild时会返回null

  • controlType: (可选)字符串类型,可选值可以参考ControlType
  • 返回值: 异步的任意控件类型,具体类型取决于导航到的控件类型。没有导航到任何控件时返回null

parent(): Promise<IWinControl>

firstChild()lastChild()方法相反,获取控件的父控件,如果控件为最顶层控件则返回null

  • 返回值: 异步的任意控件类型,具体类型取决于导航到的控件类型。没有导航到任何控件时返回null

all(): Promise<IWinControl[]>

all()方法返回与当前控件的“标识属性”相匹配的所有同级控件数组,无需指定任何筛选条件。这个方法适用于在测试中实现对同一层级多个控件的批量操作,如表格、列表或一组按钮。详细用法参见获取对象API

  • 返回值: 异步的控件数组,包含所有子控件对象。如果当前控件下没有任何子控件,则返回空数组。

findControls(...conditions: ConditionFilter[]): Promise<IWinControl[]>

findControls()方法是一个强大的查询工具,用于根据一系列条件筛选出满足这些条件的控件集合。它接受一个或多个ConditionFilter对象作为参数,这些对象定义了控件筛选的条件。

此方法适用于需要根据特定条件从应用中检索控件的场景。例如,在具有动态内容的界面上,您可能需要找到所有具有特定属性或状态的控件。findControls()方法可以根据您提供的条件动态地识别并返回这些控件。详细用法参见获取对象API

  • 返回值: 异步返回一个IWinControl数组,该数组包含满足提供的筛选条件的所有控件。如果没有找到符合条件的控件,则返回空数组。

控件导航应用场景

例1: 输入框定位

在部分应用中存在需要填写的表单,即:

表单:
    [标签1]: [输入框1]
    [标签2]: [输入框2]
    [标签3]: [输入框3]
    [标签4]: [输入框4]

对于一些应用的输入框可能没有足够的属性用于识别,而所有的标签和输入框又属于同一个容器(表单)中没有隔离,那么CukeTest可能会将输入框1-4当作相同的输入框,这个时候就可以通过添加标签对象,接着使用导航方法获得其右侧的输入框控件,就可以得到目标输入框:

JavaScript
Python
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: 控件遍历

可以通过递归调用导航方法的方式,遍历到整个应用中的所有控件。

results matching ""

    No results matching ""