HarmonyOS鸿蒙Next UI测试,基于UiTest的元素定位(API version 18)
HarmonyOS鸿蒙Next UI测试,基于UiTest的元素定位(API version 18) 举个例子:

这是配置IP时的DOM结构,每个Row下的第二个Text无id。
Column - id_column1
└── Text - IPv4地址
├── Row - id_column1_row
│ ├── Text - MAC地址
│ └── Text - b2:df:......
├── Row - id_column1_row
│ ├── Text - IP地址
│ └── Text - 10.61.......
├── Row - id_column1_row
│ ├── Text - 子网掩码
│ └── Text - 255.255.......
├── Row - id_column1_row
│ └── Text - 网关
│ └── Text - 10.61.......
├── Row - id_column1_row
│ ├── Text - DNS1
│ └── Text - 10.61.......
└── Row - id_column1_row
├── Text - DNS2
└── Text - 10.60.......
Column - id_column2
└── Text - IPv6地址
├── Row - id_column2_row
│ ├── Text - MAC地址
│ └── Text - b2:df:fd:......
├── Row - id_column2_row
│ ├── Text - IP地址
│ └── Text - 2409:8970:11c6:......
├── Row - id_column2_row
│ ├── Text - 子网掩码
│ └── Text - ffff:ffff:......
├── Row - id_column2_row
│ └── Text - 网关
│ └── Text - 10.61.......
├── Row - id_column2_row
│ ├── Text - DNS1
│ └── Text - 2409:8970:......
└── Row - id_column2_row
├── Text - DNS2
└── Text - 2409:8970:......
这是没配置IP时的DOM结构。
Column - id_column1
└── Text - IPv4地址
├── Row - id_column1_row
│ ├── Text - MAC地址
├── Row - id_column1_row
│ ├── Text - IP地址
├── Row - id_column1_row
│ ├── Text - 子网掩码
├── Row - id_column1_row
│ └── Text - 网关
├── Row - id_column1_row
│ ├── Text - DNS1
└── Row - id_column1_row
├── Text - DNS2
Column - id_column2
└── Text - IPv6地址
├── Row - id_column2_row
│ ├── Text - MAC地址
├── Row - id_column2_row
│ ├── Text - IP地址
├── Row - id_column2_row
│ ├── Text - 子网掩码
├── Row - id_column2_row
│ └── Text - 网关
├── Row - id_column2_row
│ ├── Text - DNS1
└── Row - id_column2_row
├── Text - DNS2
现在利用ON方法,有什么好的方式能定位、获取各个字段后的值? (例:定位IPV4的MAC地址的值;定位IPV6的MAC地址的值)
这是我的策略:
//找到IPV4 MAC地址这一行的所有Text,findComponents返回一个list。
let IPV4MACAddress = await commonUtils.base.findComponents(
ON.type("Text").within(ON.id("id_column1_row")).isBefore(ON.text("MAC地址"))
)
//如果list的长度为1,证明MAC地址后没有Text组件,证明MAC地址的值为null。
//反之,证明MAC地址后有Text组件,再获取到它的Text文本。
if (IPV4MACAddress.length = 1) {
return
} else {
let IPV4MACAddressText = await IPV4MACAddress[2].getText()
return IPV4MACAddressText
}
我现在的主要疑问是,再ArkTS的uitest架构下,有没有类似python中的Xpath相对定位的方法。 能够让我做到类似 //[id_column1_row(1)][2] 也就是直接定位到第二个
更多关于HarmonyOS鸿蒙Next UI测试,基于UiTest的元素定位(API version 18)的实战教程也可以访问 https://www.itying.com/category-93-b0.html
开发者您好,如果您期望在ArkTS的UiTest架构中提供类似python中的Xpath相对定位的方法,您方便的话,麻烦您补充提供下以下信息:
方便的话说明下能力不满足可能带来的影响:什么时间用到?是否高频?有无三方库可以做到?若提供该能力,是否会造成大工作量返工?请您注意提供的内容不要包含您或第三方的非公开信息,如给您带来不便,敬请谅解。
更多关于HarmonyOS鸿蒙Next UI测试,基于UiTest的元素定位(API version 18)的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
1.什么时间用到: 编写鸿蒙UI自动化测试的时候。
2.是否高频: 高频,涉及到类表格的元素定位时用的多。
3.有无第三方库可用: 目前我发现无,希望有。
4.若提供该能力,是否会造成大工作量返工: 不会,只要修改或删除以前的On类、driver类、component类、Driver类中的函数等等,只是添加一种新的定位方式,不会造成大量返工,只会在之后的编写鸿蒙UI自动化测试中使用。
指定目标控件位于给出的特征属性控件之后,返回On对象自身。
https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-uitest#isafter9
鸿蒙Next UI测试
在鸿蒙Next UI测试中,UiTest通过findComponent方法定位元素。该方法支持使用ID、type、text等多种属性进行定位。
示例:
findComponent(On.id('id')).click()
API version 18的改进:
- 强化了组件树遍历能力。
- 增强了异步操作的稳定性。
在HarmonyOS Next的UiTest框架(API version 18)中,虽然没有直接等同于XPath语法的定位方式,但ON选择器提供了强大的链式组合能力,可以实现精确的相对定位。针对你描述的DOM结构,要定位每个Row下的第二个Text(即字段值),可以结合使用parent、child、sibling等关系选择器。
以下是一种更直接和稳定的定位策略:
1. 定位特定字段的值(例如IPv4的MAC地址)
你可以通过组合条件,先定位到包含“MAC地址”标签的Row,然后在该Row内查找第二个Text组件。
// 定位IPv4 Column下,文本为“MAC地址”的Text组件
let macLabel = await ON.type('Text').text('MAC地址').within(ON.id('id_column1')).findOne();
// 获取其父组件(即Row)
let parentRow = await macLabel.parent();
// 在父Row内查找第二个Text组件(即值)
let macValueComponent = await ON.type('Text').within(parentRow).index(1).findOne();
// 获取文本值
let macValue = await macValueComponent.getText();
2. 通用方法:根据字段名获取对应值
可以封装一个函数,根据传入的字段名(如“IP地址”、“子网掩码”)和所属Column的id,来动态获取其值。
async function getFieldValue(columnId: string, fieldName: string): Promise<string | null> {
try {
// 1. 在指定Column内,找到字段名对应的Text标签
let fieldLabel = await ON.type('Text')
.text(fieldName)
.within(ON.id(columnId))
.findOne();
// 2. 获取其父Row
let row = await fieldLabel.parent();
// 3. 获取该Row下的所有Text子组件
let textComponents = await ON.type('Text').within(row).find();
// 4. 如果Row内有两个Text,则第二个是值;如果只有一个,则值为空
if (textComponents.length >= 2) {
let valueComponent = textComponents[1];
return await valueComponent.getText();
} else {
return null; // 或返回空字符串 ''
}
} catch (error) {
// 处理未找到组件的情况
console.error(`Failed to find field "${fieldName}" in column ${columnId}: ${error}`);
return null;
}
}
// 使用示例:获取IPv4的MAC地址
let ipv4Mac = await getFieldValue('id_column1', 'MAC地址');
// 获取IPv6的IP地址
let ipv6Ip = await getFieldValue('id_column2', 'IP地址');
3. 使用isAfter选择器进行相对定位
你的思路中使用isBefore是可行的,但isAfter在这个场景下更直观。可以定位字段标签,然后找到它后面的兄弟Text节点。
// 定位“MAC地址”标签之后的第一个Text组件(即其值)
let macValueComponent = await ON.type('Text')
.within(ON.id('id_column1')) // 限定范围
.isAfter(ON.type('Text').text('MAC地址')) // 在“MAC地址”之后
.findOne();
let value = await macValueComponent.getText();
关键点总结:
parent()、child()、sibling():这些方法是实现相对定位的核心,允许你在组件树中导航。within():用于限定搜索范围,提高定位准确性和性能。在你的场景中,先限定在id_column1或id_column2内非常重要。index():当使用find()获取到多个组件时,你可以通过index()来按顺序选择。例如,在Row内,index(0)是字段标签,index(1)是字段值。isBefore()/isAfter():基于组件在布局中的位置顺序进行定位,非常适合你这种标签-值并排的结构。
你的策略是有效的,但通过上述方法,代码会更简洁、易读,且更符合UiTest API的设计模式。对于动态变化的UI(如配置IP前后),通用函数getFieldValue能很好地处理值存在与否的情况。

