Container API
Container APIs are those APIs used to get Test Object from the model, or APIs that generate objects through attributes in descriptive programming, as follows:
type definition file
export interface IWinContainer {
/* get a single object */
getButton(objectName:string, property?: Criteria): IWinButton;
getButton(property: Criteria): IWinButton;
getEdit(objectName:string, property?: Criteria): IWinEdit;
getEdit(property: Criteria): IWinEdit;
// ... //
// ... //
// ... //
/* get multiple objects */
findControls(objectName:string, property?: Criteria): Promise<IWinControl[]>;
findControls(property: Criteria): Promise<IWinControl[]>;
}
Control filter condition Criteria
class
CukeTest uses the Criteria
object as a condition to filter the controls in the current environment to obtain the target control and operate it.
interface Criteria {
accessKey?: string;
attachedtext?: string;
automationId?: string;
boundingRectangle?: string;
className?: string;
className~?: string;
helptext?: string;
hwnd?: number;
index?: number;
name?: string;
name~?: string;
text?: string;
text~?: string;
value?: string;
value~?: string;
processid?: number;
type?: ControlType
title?: string;
url?: string;
}
class Criteria():
accessKey: str
appName: str
attachedtext: str
automationd: str
className: str
index: int
helptext: str
hwnd: int
name: str
processid: int
type: str
title: str
url: str
As can be seen from the definition of the above control option type, you can pass in an object name; you can also pass in an object representing identification attribute; at the same time pass in object name and identification Attribute is also available.
Internally, the Get Object API behaves differently for the object name and the identifying property:
- Only pass in the object name: Read the identification attribute in the target Test Object in the model. If it does not exist in the model file, an error of could not find the test object in the model file is thrown
1009:CannotFindTestObjectInModel
. - Only pass in identification attributes: Match all controls that meet the conditions in the tested application and return them. Except for the
findControls()
method, all object acquisition APIs only return the first visible control that meets the conditions. If there is no Controls that meet the conditions returnnull
. - Pass in the object name and identification attributes at the same time: the test object will be used to match the target control in the application under test and return it. Except for the
findControls()
method, all object acquisition APIs will only return the first one that satisfies the conditions. Visible **control. Returnsnull
if a control is matched or there is no control that satisfies the condition.
Use fuzzy matching (regular expression matching) to get controls
Observing the Criteria object
used to get the object, you can find that there are several special attributes in it, they are suffixed with ~
, and there are attributes with the same name in the Criteria object
.
These attributes with a ~
suffix mean that these attributes allow fuzzy matching, or regular matching. You can manually enable fuzzy matching for controls in the Model Manager. You can also Use the following method to match in the script:
// full text match
await model.getButton({"name": "number5"}).click();
// Matches all controls whose name attribute contains "number"
await model.getButton({"name~": "number"}).click();
// Matches all controls whose name attribute ends with "5"
await model.getButton({"name~": "number$"}).click();
# full text match
model.getButton({"name": "数字5"}).click()
# Matches all controls whose name attribute contains "number"
model.getButton({"name~": "数字"}).click()
# Matches all controls whose name attribute ends with "5"
model.getButton({"name~": "数字$"}).click()
These attributes can be directly generated in the model manager through the "[Copy Node Attribute]" function, and do not necessarily need to be manually constructed.
get[ControlType]
CukeTest provides a method for each control type, which returns Test Object for this type of control. For example, the button control Button
can be passed to getButton
method, the list view control List
can be obtained by getList
method.
After these API objects are called, another sub-container object is returned, which means that these container APIs can be cascaded to these objects to obtain objects at a deeper level of the control tree.
conditions have the following two types of parameters:
- object name,
string
,Is the name of an object in the model file. At runtime, the identification properties in the object will be obtained from the model and used for filtering. - Identification attribute,
Object
,Contains multiple key/value pairs. These properties are used for filtering to filter out objects that meet all conditions. If an object name is specified at the same time, it will be concatenated and override (same field) the identified properties in the model to filter.
The calling methods are as follows:
Default: only the object name is passed in
Only provide the object name to the get[ControlType]
method, and the calling format is as follows:
await model.getButton("5").click();
model.getButton("5").click()
Since this calling method is based on the object model, it is first necessary to detect and add the control in the model manager.
Descriptive programming: only pass in the identification attribute object
In declarative programming, you can directly construct objects from properties without loading the model. The optional values of these properties refer to Criteria class.
const { WinAuto } = require('leanpro.win');
await WinAuto.getWindow({
"className": "ApplicationFrameWindow",
"title": "calculator "
}).getWindow({
"className": "Windows.UI.Core.CoreWindow",
"title": "calculator"
}).getGeneric({
"type": "Group",
"automationId": "NumberPad",
"name": "numeric keypad"
}).getButton({
"automationId": "num5Button"
}).click();
from leanproAuto import Auto
Auto.getWindow({
"className": "ApplicationFrameWindow",
"title": "calculator "
}).getWindow({
"className": "Windows.UI.Core.CoreWindow",
"title": "calculator"
}).getGeneric({
"type": "Group",
"automationId": "NumberPad",
"name": "numeric keypad"
}).getButton({
"automationId": "num5Button"
}).click()
In the above example, each call is passed an object parameter, which contains multiple key/value pairs, which are combined to form filter conditions to find objects.
For more information about the development of the description mode, please refer to Description Mode.
Mixed mode: pass in object name and object properties at the same time
In the default mode, the first parameter is the object name, and then the second parameter is passed in to become a mixed mode. The second parameter indicates the identification attribute, and the optional value refers to Criteria class.
- The object name parameter is used to get the object from the model and its identifying properties in the model;
- The identification attribute parameter is used to cover or supplement the identification attribute on the object, and then the formed attribute set is used to find the object. For example, if the call is overridden with the following usage:
await model.getButton("5", {automationId: "num6Button"}).click();
model.getButton("5", {automationId: "num6Button"}).click()
Then the clicked button is "6" on the calculator instead of "5", because the automationId has been overwritten by the second parameter to a new value. The container object API is synchronous, which means that there is no need to use await
when calling prefix.
The following call is complementary usage:
await model.getButton("Button", {index: 2}).click();
model.getButton("Button", {index: 2}).click()
It will click the matched third Button
control (assuming that 3 or more controls can be matched).
findControls
findControls(objectName:string, property?: Criteria): Promise<IWinControl[]>;
findControls(property: Criteria): Promise<IWinControl[]>;
objectName
, or a filter object Criteria
.
It returns all control objects that meet the conditions in the form of an array. It can obtain all matching controls on the application in real time according to the incoming conditions, and return a Promise of the object array. This API can be used when there are multiple similar controls on the interface. Return this set of objects at the same time, so as to operate on all these corresponding controls.
The findControls
method is often used in the following scenarios:
Scenario 1: There is a set of controls for collection operations
For example, there is a group of CheckBox controls on the interface, and they all need to be selected. Take the built-in sample SimpleStyles as an example:
In order to mark all the above checkboxes as selected, you can first add the following model objects:
Note that the "Name" attribute has been removed from the identity attribute to match all CheckBox objects.
Use this object in the
findControls
call,
(async function() {
let controls = await model.findControls("Normal");
console.log('controls', controls.length) //Match the number of controls
for(let control of controls) {
console.log(await control.name()); //print checkbox name
await control.check(); //Check the checkbox control
}
})()
Appendix: Complete Type Definitions
In the types file, the type definition for the container object:
export interface IWinContainer {
findControls(...conditions: ConditionFilter[]): Promise<IWinControl[]>;
getWindow(...conditions: ConditionFilter[]): IWinWindow;
getButton(...conditions: ConditionFilter[]): IWinButton;
getCheckBox(...conditions: ConditionFilter[]): IWinCheckBox;
getComboBox(...conditions: ConditionFilter[]): IWinComboBox;
getCustom(...conditions: ConditionFilter[]): IWinCustom;
getDataItem(...conditions: ConditionFilter[]): IWinControl;
getDataGrid(...conditions: ConditionFilter[]): IWinDataGrid
getDocument(...conditions: ConditionFilter[]): IWinDocument;
getEdit(...conditions: ConditionFilter[]): IWinEdit;
getGeneric(...conditions: ConditionFilter[]): IWinGeneric;
getImage(...conditions: ConditionFilter[]): IWinImage;
getList(...conditions: ConditionFilter[]): IWinList;
getListItem(...conditions: ConditionFilter[]): IWinListItem;
getMenuBar(...conditions: ConditionFilter[]): IWinMenuBar;
getMenuItem(...conditions: ConditionFilter[]): IWinMenuItem
getMenu(...conditions: ConditionFilter[]): IWinMenu;
getPane(...conditions: ConditionFilter[]): IWinPane;
getRadioButton(...conditions: ConditionFilter[]): IWinRadioButton;
getScrollBar(...conditions: ConditionFilter[]): IWinScrollBar;
getSlider(...conditions: ConditionFilter[]): IWinSlider;
getSpinner(...conditions: ConditionFilter[]): IWinSpinner;
getTab(...conditions: ConditionFilter[]): IWinTab;
getTabItem(...conditions: ConditionFilter[]): IWinTabItem;
getTable(...conditions: ConditionFilter[]): IWinTable;
getTree(...conditions: ConditionFilter[]): IWinTree;
getTreeItem(...conditions: ConditionFilter[]): IWinTreeItem;
getText(...conditions: ConditionFilter[]): IWinText;
getVirtual(...conditions: ConditionFilter[]): IWinVirtual
}
export type ConditionFilter = string | Criteria;
interface Criteria {
accessKey?: string;
attachedtext?: string;
automationId?: string;
boundingRectangle?: string;
className?: string;
helptext?: string;
hwnd?: number;
name?: string;
processid?: number;
type?: ControlType
title?: string;
url?: string;
}
class WinContainer():
def getWindow(*conditions: List[Union[str, Dict]]) -> "WinWindow"
def getButton(*conditions: List[Union[str, Dict]]) -> "WinButton"
def getCheckBox(*conditions: List[Union[str, Dict]]) -> "WinCheckBox"
def getComboBox(*conditions: List[Union[str, Dict]]) -> "WinComboBox"
def getCustom(*conditions: List[Union[str, Dict]]) -> "WinCustom"
def getDataItem(*conditions: List[Union[str, Dict]]) -> "WinTableCell"
def getDataGrid(*conditions: List[Union[str, Dict]]) -> "WinDataGrid"
def getDocument(*conditions: List[Union[str, Dict]]) -> "WinDocument"
def getEdit(*conditions: List[Union[str, Dict]]) -> "WinEdit"
def getGeneric(*conditions: List[Union[str, Dict]]) -> "WinGeneric"
def getHyperlink(*conditions: List[Union[str, Dict]]) -> "WinHyperlink"
def getmage(*conditions: List[Union[str, Dict]]) -> "WinImage"
def getList(*conditions: List[Union[str, Dict]]) -> "WinList"
def getListtem(*conditions: List[Union[str, Dict]]) -> "WinListItem"
def getMenuBar(*conditions: List[Union[str, Dict]]) -> "WinMenuBar"
def getMenuItem(*conditions: List[Union[str, Dict]]) -> "WinMenuItem"
def getMenu(*conditions: List[Union[str, Dict]]) -> "WinMenu"
def getPane(*conditions: List[Union[str, Dict]]) -> "WinPane"
def getRadioButton(*conditions: List[Union[str, Dict]]) -> "WinRadioButton"
def getScrollBar(*conditions: List[Union[str, Dict]]) -> "WinScrollBar"
def getSlider(*conditions: List[Union[str, Dict]]) -> "WinSlider"
def getSpinner(*conditions: List[Union[str, Dict]]) -> "WinSpinner"
def getTab(*conditions: List[Union[str, Dict]]) -> "WinTab"
def getTabItem(*conditions: List[Union[str, Dict]]) -> "WinTabItem"
def getTable(*conditions: List[Union[str, Dict]]) -> "WinTable"
def getTableRow(*conditions: List[Union[str, Dict]]) -> "WinTableRow"
def getTableCell(*conditions: List[Union[str, Dict]]) -> "WinTableCell"
def getToolBar(*conditions: List[Union[str, Dict]]) -> "WinToolBar"
def getTree(*conditions: List[Union[str, Dict]]) -> "WinTree"
def getTreeItem(*conditions: List[Union[str, Dict]]) -> "WinTreeItem"
def getTreeCell(*conditions: List[Union[str, Dict]]) -> "WinTreeCell"
def getText(*conditions: List[Union[str, Dict]]) -> "WinText"
def getVirtual(*conditions: List[Union[str, Dict]]) -> "Virtual"
def getPattern(*conditions: List[Union[str, Dict]]) -> "Pattern"
class Criteria():
accessKey: str
appName: str
attachedtext: str
automationd: str
className: str
index: int
helptext: str
hwnd: int
name: str
processid: int
type: str
title: str
url: str
In fact, all get object APIs actually have an equivalent way of writing:
model.getWindow("NotePad");
// can write
model.getGeneric("NotePad", {type: "Window"})
model.getWindow("NotePad")
# can write
model.getGeneric("NotePad", {type: "Window"})
Window
control type.