全球化测试中利用 Selenium 定位 Web 元素难点解析(2)
- UID
- 1066743
|
全球化测试中利用 Selenium 定位 Web 元素难点解析(2)
CSS 选择器CSS 选择器是由关系符分开的一个或多个简单选择器序列组成的选择器序列链,最后一个简单选择器序列的后面还可以添加一个伪元素。简单选择器序列是单纯由简单选择器组成的选择器链,它通常由一个标签选择器或者通配符选择器开头,之后序列中不允许再出现其他标签选择器和通配符选择器。简单选择器可以是 ID 选择器、类选择器、类型(标签)选择器、通配符选择器、属性选择器和伪类选择器。关系符可以是空格、大于号、加号和波浪符。关系符和简单选择器周围允许出现空白(空格符、tab 符、换行符、回车符、换页符)。多个 CSS 选择器还可以用逗号拼接为一个组合选择器,满足任意其中一个选择器的元素都会被该组合选择器选中,逗号的前后允许出现空白。某些选择器支持命名空间前缀,命名空间前缀的声明机制应该由使用选择器的语言指定,如果使用选择器的语言没有指定命名空间前缀声明机制,那么就没有前缀声明。在 CSS 中,命名空间通过 @namespace 规则声明。
清单 4. HTML 示例 21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| (01)<html>
(02) <body>
(03) <form id="loginForm" name="loginFrom">
(04) <input class="required" name="username" type="text" />
(05) <input class="required passfield" name="password" type="password" />
(06) <input name="continue" type="submit" value="Login" />
(07) </form>
(08) <p class="ask">Are you sure you want to do this?</p>
(09) <a href="continue.html">Continue</a>
(10) <a href="cancel.html" hreflang=en-US>Cancel</a>
(11) <div>
(12) <ul id="structure">
(13) <li>Cat</li>
(14) <li>Dog</li>
(15) <p>fish</p>
(16) <li>Car</li>
(17) <li>Goat</li>
(18) </ul>
(19) </div>
(20)</body>
(21)<html>
简单选择器
ID、类、类型(标签)、通配符选择器
|
文档中可能包含被声明为 ID 类型的属性,ID 类型的属性的特殊之处在于一份文档中的任意两个元素不会有相同的 ID 值。无论文档语言是什么,ID 类型的属性可以用来唯一地标识它所在的元素。ID 选择器由数目符号 (U+0023, #) 和合法的 ID 值组成,ID 选择器指代具有与定位器匹配的 ID 值的文档元素,如清单 5 所示 (行末括号中的数字显示当前行定位器将定位到清单 4HTML 文档中的第几行元素)。当在 HTML 中表示 class 属性时通常将句点符号 ( U+002E) 作为~=的替代符号,因此在 HTML 中 div.value 与 div[class~=value] 具有相同的意义,均定位到 class 为 value 的 div 元素。需要特别注意的是形如 p.pastoral.marine{color:green} 的选择器将匹配到 class 属性既包含 pastoral 又包含 marine 且二者用空格分隔的 p 标签,例如匹配到 class="pastoral blue aqua marine"而匹配不到 class="pastoral blue"。类型选择器中的类型是元素类型的名称,类型选择器指代文档树中具有相同类型的元素,如清单 5 所示。通配符选择器使用星号 (* U+002A) 指代任意元素类型的合法名称。如果星号表示的通配符选择器不是简单选择器序列的唯一组件或者它的后面紧跟着一个伪元素,那么可以省略该星号而暗指含有一个通配符选择器,然而有些情况下不推荐省略,比如 div *:first-child 就比 div :first-child 更易读,不至于和 div:first-child 混淆。另外类型选择器和通配符选择器都支持命名空间前缀,命名空间前缀使用竖线 (U+007C, |) 与选择器分隔,可以为空也可以为通配符星号。在没有命名空间前缀和分隔符的情况下,若没有声明命名空间则表示任意命名空间,若已声明默认命名空间则表示默认命名空间。
属性选择器
属性选择器通过对元素属性进行匹配来进行选择和定位。属性选择器又分为存在和值选择器以及子串匹配属性选择器。前者又分为四种:[att] 指代具有 att 属性的元素,而不论属性的值是什么;[att=val] 指代属性的值为 val 的元素;[att~=val] 指代这样的元素,其属性值由空格分隔的多个值组成,其中一个值和 val 完全匹配;[att|=val] 指代属性值为 val 或者前缀为“val-”。子串匹配属性选择器提供了匹配属性值子串的能力,比如 [att^=val] 指代属性值前缀为 val 的元素;[att$=val] 指代属性值后缀为 val 的元素;[att*=val] 指代属性值中含有 val 字符串的元素。在这两种属性选择器中属性值必须为 CSS 合法字符,大小写敏感度与具体的文档语言有关。详细示例如清单 5 所示。属性选择器也支持命名空间前缀,与类型和通配符选择器不同的是对于没有命名空间前缀或者命名空间前缀为空的属性选择器,其只匹配到没有命名空间前缀的元素。
伪类选择器
伪类选择器可以说是定位 Web 元素的最后救命稻草,它允许使用文档树以外的信息选取元素,这能完成很多其它选择器不能完成的工作。伪类总是由一个前面加了冒号的伪类名组成,伪类可以存在于所有的选择器序列中,它可以位于主选择器或者通配符选择器之后。伪类区分大小写,有些伪类是互斥的,有些伪类则可以同时使用。伪类可以是动态的,某种意义上说随着用户与文档的交互一个伪类可以获得或者失去对一个元素的匹配。伪类从实现方式可分为动态伪类(如互斥的:link 和:visited, :hover, :active, :focus),目的伪类(:target),语言伪类(:lang),元素状态伪类(:enabled, :disabled, :checked, :indeterminate),结构伪类,内含伪类和否定伪类,若以定位元素为目的的话这里只有结构伪类和内含伪类才对我们有用,其他伪类主要应用在元素样式渲染领域特别是随着用户操作自动改变元素样式的场景。
结构伪类可以基于文档树的结构定位元素,其中标准文本和其它非节点元素没有被算进父节点的子节点列表中,子节点的位置索引从 1 开始计算。结构伪类包含十二种::root 伪类指代文档的根节点,在 Html4 中通常指 HTML 元素;:nth-child(an+b), n>=0 伪类指代在第 an+b 个孩子节点,即其之前有 an+b-1 个兄弟节点的元素,举例来说:nth-child(2n) 指代第偶数个孩子节点,:nth-child(2n+1) 指代第奇数个孩子节点,:nth-child(4) 指代第 4 个元素孩子节点;tag:nth-of-type(an+b), n>=0 指代第 an+b 个类型为 tag 的孩子节点,非 tag 类型的节点不参与计数;:nth-last-child(an+b),n>=0 伪类指代从后往前数第 an+b 个孩子节点,即其后有 an+b-1 个兄弟节点;:nth-last-of-type 指代从后往前数第 an+b 个类型为 tag 的节点;:first-child,:last-child,:first-of-type,:last-of-type 分别是上述四种伪类的特例,指代第一个或者最后一个孩子节点;nly-child 伪类指代没有兄弟节点的孩子节点;nly-of-type 伪类指代没有相同类型的兄弟节点的孩子节点;:empty 伪类指代没有孩子节点的节点。详细示例见清单 5。
内含伪类(:contains())通过元素上包含的文本来定位元素,由于在翻译验证性测试的特殊性,该定位方法需配合英文文本与本地化翻译文本的映射才能有效使用。
清单 5. CSS 简单选择器1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| //by ID selector
#loginForm(03)
//by Class selector
.ask(08)
/by Type selector
p.ask(08)
//by Universal selector
*|*(all)
//by attribute presence and value selector
input[value](06)
input[name="continue"](06)
input[class~="required"][name="password"](05)
a[hreflang|="en"](10)
//by substring matching attribute selector
a[href^="cancel"](10)
a[name$="name"](04)
a[name*="pass"](05)
//by structural pseudo-classes
ul#structure li:nth-child(4)//只有当第四个子元素是 li 时才可成功定位到 (16)
ul#structure li:nth-of-type(4)(17)
ul#structure nth-last-child(3)(15)
ul#structure li:nth-last-of-type(3)(14)
//by contains pseudo-class
li:contains("Cat")(13)
关系选择器
|
由于编码不规范等问题,仅仅通过简单选择器有时候并不能唯一定位到我们预期得到的元素,这时我们还可以通过元素间的代继关系,首先定位到目标元素的祖先或父亲或兄弟节点,然后借助关系选择器进行定位。常见的关系选择器有后代选择器、子选择器和兄弟选择器三种:后代选择器使用空格分隔两个简单选择器以代表二者具有祖先、后代关系,形如“A B”的后代选择器代表目标元素 B 为 A 的任意后代元素;子选择器使用大于号分隔两个简单选择器以代表其父子关系,形如“A B”的子选择器代表目标元素 B 为 A 的子元素;兄弟选择器分为两种,相邻兄弟选择器和一般兄弟选择器。相邻兄弟选择器使用加号分隔两个简单选择器以代表二者具有相同的父元素且位置临近,形如“A + B”的兄弟选择器代表目标元素 B 为紧随 A 后面的兄弟元素。一般兄弟选择器使用波浪号分隔两个简单选择器以代表后者与前者具有相同的父元素,而并不要求这两个元素位置临近。如清单 6 所示:
清单 6. 关系选择器1
2
3
4
5
6
7
| //by Descendant combinator
div p(15)
//by Child combinators
body > p(08)
//by General sibling combinator
form + p 或者 div ~ p(08)
|
|
|
|
|
|
|