设为首页收藏本站
 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

Firepath 自动获取定位的改进

2015-12-31 16:16| 发布者: webdriver| 查看: 4100| 评论: 0|原作者: Alex

摘要: 用webdriver做自动化的人都应该对css和xpath定位熟悉,单纯通过id,name,classname这些属性有时候并不能定位到我们想要的元素,css和xpath就很方便可以通过dom里的层级关系来帮助我们定位。Firepath也是一款很棒的 ...

  用webdriver 做自动化的人都应该对cssxpath定位熟悉, 单纯通过idname classname这些属性有时候并不能定位到我们想要的元素,cssxpath就很方便可以通过dom里的层级关系来帮助我们定位。 Firepath也是一款很棒的工具可以辅助调试css/xpath来帮我们提高分析效率, 特别是firepath里的自动生成css/xpath功能,有时候确实能帮助我们省事,生成的定位大部分时候也够用了。

 

我们今天就来分析下firepath的自动生成定位这块。Firepath生成定位的过程一般是,我们通过点击inspect , 然后移动鼠标到我们想要查看的元素上,再点击确认,Firepath就会给我们生成定位这个元素的css/xpath了, 那这个过程中,针对生成元素selector的逻辑是什么呢?

 

我们来看下github上的项目源码: https://github.com/zzhengjian/firepath

更详细变更可以看这个 commit: https://github.com/zzhengjian/firepath/commit/88933e4cd38f6edfacadf6dc22f4dba14e4280d6


我们把主要代码截取出来:

 FBL.getXPathFromNode = function(node, context) {

var result = "";

var stop = false;

var absolute = Firebug.getPref(Firebug.prefDomain, "firepath.generateAbsoluteXPath");


var parent = context || node.ownerDocument;

while (node && node != parent && !stop) {

var str = "";

var position = getNodePosition(node);

switch (node.nodeType) {

case Node.DOCUMENT_NODE:

break;

case Node.ATTRIBUTE_NODE:

str = "@" + node.name;

break;

case Node.COMMENT_NODE:

str = "comment()";

break;

case Node.TEXT_NODE:

str = "text()";

break;

case Node.ELEMENT_NODE:


var name = getTagName(node);


if(!absolute && node.id && node.id != "") {

str = ".//*[@id='" + node.id + "']";

position = null;

stop = true;

} else {

str = name;

}

break;

}

result = str + (position ? "[" + position + "]" : "") + (result? "/": "") + result;

if(node instanceof Attr) node = node.ownerElement;

else node = node.parentNode;


}


return result;

}


const firepathClass = /\s*firepath-matching-node\s*/g;

const multipleSpace = /\s+/g;


FBL.getCssSelectorFromNode = function (node, context) {

var result = '',

node,

parent = context || node.ownerDocument,

stop = false,

str;

while (node && node != parent && !stop) {

if(node.nodeType === Node.ELEMENT_NODE) {

if(node.id) {

str = '#' + node.id;

stop = true;

} else if(node.className && node.className.replace(firepathClass, '')) {

str = '.' + node.className.replace(firepathClass, ' ').trim()

.replace(multipleSpace, ' ').split(' ').join('.');

stop = true;

} else {

str = node.localName.toLowerCase();

}

result = str + (result? '>' + result: ''); 

}

if(node instanceof Attr) {

node = node.ownerElement;

} else {

node = node.parentNode;

}

}

return result;

}

 

我们关注上面主要的东西,一般页面定位的话一定要有一个相对固定而且唯一参考值,比如一般默认id都是唯一的,firepath 里的css/xpath也是基于这个基础上来生成,先是判断当前节点有无id, 有则返回,没有则继续上一层来判断,如果都没有id, 那最后就会从根节点开始, dom里也就是/html/xxx 来开头。 Css选择器的话倒是多了一个判断class属性的,但是Firepath自动生成的css当当前节点有多个类似节点的时候不能唯一定位,而是匹配到同一层级的多个元素。

 

当然,如果对于css/Xpath语法较为熟悉的测试人员来说,自己手写是最好的选择,根据项目可以自己判断写出相对稳定的定位,以增强脚本的稳定性。但我这里讨论的是,如果对于初学者,或者说想提高效率,直接利用firepath生成的css/Xpath来定位元素,那我们就有了必要对这个自动生成函数做必要的优化.

 

目前主要优化的有几点,增加更多的唯一性和固定值, 比如一般来说id是唯一的,可以用来做定位参考,classname, 也是可以是作为定位的参考的,只要他们是页面里唯一的,还有元素标签等等…  另外这里也将修复自动生成的css选择器匹配不唯一的情况。

 

 

优化后的主要代码:

FBL.getXPathFromNode = function(node, context) {

var result = "";

var stop = false;

var usingClass = true

var absolute = Firebug.getPref(Firebug.prefDomain, "firepath.generateAbsoluteXPath");

var classname = '';

var parent = context || node.ownerDocument;

while (node && node != parent && !stop) {

var str = "";

var position = getNodePosition(node);

switch (node.nodeType) {

case Node.DOCUMENT_NODE:

break;

case Node.ATTRIBUTE_NODE:

str = "@" + node.name;

break;

case Node.COMMENT_NODE:

str = "comment()";

break;

case Node.TEXT_NODE:

str = "text()";

break;

case Node.ELEMENT_NODE:


var name = node.tagName.toLowerCase();


if(!absolute && node.id && node.id != "") {

str = ".//*[@id='" + node.id + "']";

position = null;

stop = true;

} else if(!absolute && node.tagName == 'LABEL' && isInForm(node) && (_for = getForAttribute(node))){

str = ".//*[@for='" + _for + "']";

stop = true;

}else if(!absolute && (classname = isClassNameUnique(node)) && usingClass) {

str = ".//*[@class='" + classname + "']";

position = null;

stop = true;

}else if(!absolute && isTagNameUnique(node)) {

str = ".//" + name;

position = null;

stop = true;

} else {

str = name;

}

break;

}

result = str + (position ? "[" + position + "]" : "") + (result? "/": "") + result;

node = node.parentElement;

}


return result;

}



const firepathClass = /\s*firepath-matching-node\s*/g;

const multipleSpace = /\s+/g;


FBL.getCssSelectorFromNode = function (node, context) {

var result = '',

node,

parent = context || node.ownerDocument,

stop = false,

str;

var classpath = '';

while (node && node != parent && !stop) {

if(node.nodeType === Node.ELEMENT_NODE) {

if(node.id) {

str = '#' + node.id;

stop = true;

} else if(node.tagName == 'LABEL' && isInForm(node) && (_for = getForAttribute(node))){

str = "[for='" + _for + "']";

stop = true;

} else if(classpath = getUniqueClassPath(node)) {

str = classpath;

stop = true;

} else if(isTagNameUnique(node)) {

str = node.tagName.toLowerCase();

stop = true;

else {

        

        var position = getNodePosition(node);

        if(position)

        {

           str = node.tagName.toLowerCase() + ':nth-of-type(' + getNodePosition(node) +  ')';

        }

        else

        {

           str = node.tagName.toLowerCase()

        }       

}

result = str + (result? '>' + result: ''); 


}

    

node = node.parentElement;


}

return result;

} 

 


优化过firepath可以到这里下载,希望能帮助大家. 点击下载

安装: 将下载到的xpi文件直接拖动到firefox浏览器里就可以了,如果因为签名问题不能使用,可以进入about:config, 将key值为 xpinstall.signatures.required 的value设置成false就可以了.


改进前后主要功能对比

Demo: 

1. 优化自动生成的css 选择器匹配不唯一问题.

 

2. 如果除有id外唯一的class属性, 则可以选择该class属性作为基准,避免了更多层级定位

 

3. 同上如果除有id外唯一的class属性, 则可以选择该class属性作为基准,避免了更多层级定位,利用绝对路径定位更是应该避免。

 

鲜花
鲜花
握手
握手
雷人
雷人
路过
路过
鸡蛋
鸡蛋
收藏 分享 邀请

最新评论