我有一个仅限Internet Explorer的Web应用程序。

我正在探索如何自动化测试。

Selenium看起来是一个很好的工具,但是为了能够激活链接等,我需要告诉它它们在哪里。应用程序没有考虑到这种测试,因此关键元素通常没有 id 属性。

没问题,我想,我可以使用XPath表达式。但是,如果通过检查页面的来源来完成,那么找一个正确的XPath,比如一个按钮,是一种巨大的痛苦。

使用Firefox / Firebug,我可以选择元素,然后使用“复制XPath”。得到表达。

我有IE开发人员工具栏,它令人沮丧地接近。我可以单击以选择感兴趣的元素并显示有关它的各种信息。但我看不出有任何方便的方法来确定XPath。

那么有没有办法用IE做这个?

有帮助吗?

解决方案

我会使用bookmarklet。我有一个XPath相关,但我不知道它是否适用于IE。我得走了,但我会测试它,如果它适用于IE,就给它。

我的书签为Web开发人员提供了两个bookmarklet站点: Subsimple的bookmarklet Squarefree的Bookmarklets 。那里有很多有用的东西......

[编辑]好的,我回来了。我的小书签仅用于FF,并不是最佳的。我终于改写了它,尽管使用了原始的想法。找不到我发现的地方。

扩展JS:

function getNode(node)
{
  var nodeExpr = node.tagName;
  if (nodeExpr == null)  // Eg. node = #text
    return null;
  if (node.id != '')
  {
    nodeExpr += "[@id='" + node.id + "']";
    // We don't really need to go back up to //HTML, since IDs are supposed
    // to be unique, so they are a good starting point.
    return "/" + nodeExpr;
  }
// We don't really need this
//~   if (node.className != '')
//~   {
//~     nodeExpr += "[@class='" + node.className + "']";
//~   }
  // Find rank of node among its type in the parent
  var rank = 1;
  var ps = node.previousSibling;
  while (ps != null)
  {
    if (ps.tagName == node.tagName)
    {
      rank++;
    }
    ps = ps.previousSibling;
  }
  if (rank > 1)
  {
    nodeExpr += '[' + rank + ']';
  }
  else
  {
    // First node of its kind at this level. Are there any others?
    var ns = node.nextSibling;
    while (ns != null)
    {
      if (ns.tagName == node.tagName)
      {
        // Yes, mark it as being the first one
        nodeExpr += '[1]';
        break;
      }
      ns = ns.nextSibling;
    }
  }
  return nodeExpr;
}

var currentNode;
// Standard (?)
if (window.getSelection != undefined) 
  currentNode = window.getSelection().anchorNode;
// IE (if no selection, that's BODY)
else 
  currentNode = document.selection.createRange().parentElement();
if (currentNode == null)
{
  alert("No selection");
  return;
}
var path = [];
// Walk up the Dom
while (currentNode != undefined)
{
  var pe = getNode(currentNode);
  if (pe != null)
  {
    path.push(pe);
    if (pe.indexOf('@id') != -1)
      break;  // Found an ID, no need to go upper, absolute path is OK
  }
  currentNode = currentNode.parentNode;
}
var xpath = "/" + path.reverse().join('/');
alert(xpath);
// Copy to clipboard
// IE
if (window.clipboardData) clipboardData.setData("Text", xpath);
// FF's code to handle clipboard is much more complex 
// and might need to change prefs to allow changing the clipboard content.
// I omit it here as it isn't part of the original request.

您必须选择元素并激活书签以获取其XPath。

现在,书签版本(感谢 Bookmarklet Builder ):

IE,点击 (我不得不分两部分,因为IE不喜欢很长的书签(最大尺寸因IE版本而异!)。你必须激活第一个(功能def)然后第二个。用IE6测试。 )

javascript:function getNode(node){var nodeExpr=node.tagName;if(!nodeExpr)return null;if(node.id!=''){nodeExpr+="[@id='"+node.id+"']";return "/"+nodeExpr;}var rank=1;var ps=node.previousSibling;while(ps){if(ps.tagName==node.tagName){rank++;}ps=ps.previousSibling;}if(rank>1){nodeExpr+='['+rank+']';}else{var ns=node.nextSibling;while(ns){if(ns.tagName==node.tagName){nodeExpr+='[1]';break;}ns=ns.nextSibling;}}return nodeExpr;}
javascript:function o__o(){var currentNode=document.selection.createRange().parentElement();var path=[];while(currentNode){var pe=getNode(currentNode);if(pe){path.push(pe);if(pe.indexOf('@id')!=-1)break;}currentNode=currentNode.parentNode;}var xpath="/"+path.reverse().join('/');clipboardData.setData("Text", xpath);}o__o();

FF

javascript:function o__o(){function getNode(node){var nodeExpr=node.tagName;if(nodeExpr==null)return null;if(node.id!=''){nodeExpr+="[@id='"+node.id+"']";return "/"+nodeExpr;}var rank=1;var ps=node.previousSibling;while(ps!=null){if(ps.tagName==node.tagName){rank++;}ps=ps.previousSibling;}if(rank>1){nodeExpr+='['+rank+']';}else{var ns=node.nextSibling;while(ns!=null){if(ns.tagName==node.tagName){nodeExpr+='[1]';break;}ns=ns.nextSibling;}}return nodeExpr;}var currentNode=window.getSelection().anchorNode;if(currentNode==null){alert("No selection");return;}var path=[];while(currentNode!=undefined){var pe=getNode(currentNode);if(pe!=null){path.push(pe);if(pe.indexOf('@id')!=-1)break;}currentNode=currentNode.parentNode;}var xpath="/"+path.reverse().join('/');alert(xpath);}o__o();

其他提示

由于书签使用困惑的保罗,我虽然我应该添加一些他们的用法介绍。我是在单独的信息中做的,以避免混合。

Bookmarklets(也称为favlet)是一些JavaScript脚本(sic),设计用于粘贴在浏览器的地址栏中(与任何其他URL一样),因此可以在当前页面上运行。
运行它(粘贴,按Enter键)后,您可以将其加入书签以供重复使用(将其添加到IE中的收藏夹)。请注意,浏览器可能会将原始URL添加为书签,然后您可以编辑书签并将URL替换为您的脚本 当然,您也可以将其添加到URL栏以便快速访问。

这些脚本就像是当前页面的一部分,访问全局JS变量和函数,Dom对象等 它们可以是超级简单的,比如开创性的 javascript:alert(“Hello world!”); 或者像上面那样非常复杂。如果它返回一个值(或者如果最后一个表达式具有值),则该值将替换当前页面。为避免这种情况,您可以使用 alert (显示结果)完成脚本或将脚本包装在函数定义中并调用此函数,就像我上面所做的那样。 (有些人也把无效(0);最后,但我看到它被认为是不好的做法。)

函数解决方案的优点是可以使脚本的所有变量都是applet的本地变量(当然,如果用 var 声明),避免了本地页面上脚本的干扰/副作用。这也是包装函数的名称不太可能与本地脚本冲突的原因。

请注意,某些浏览器(读取:“IE”)可以限制favlet的大小,最大值。长度因版本而异(趋于减少)。这就是为什么删除所有无用的空格(上面链接的bookmarlet构建器对此有好处)并且我删除了与通常做的null和undefined的explict比较。我还要将favlet分成两部分,第一部分定义一个函数(只要页面没有更改/刷新就会生效),第二部分使用它。

有用的工具,特别是在不允许用户脚本(à la Greasemonkey)或没有此扩展程序的浏览器上。

我已将bookmarklet代码重写为C#,所以如果你发现它有用,请使用它; - )

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace Anotation.Toolbar
{
    class XPath
    {
        public static string getXPath(mshtml.IHTMLElement element)
        {
            if (element == null)
                return "";
            mshtml.IHTMLElement currentNode = element;
            ArrayList path = new ArrayList();

            while (currentNode != null)
            {
                string pe = getNode(currentNode);
                if (pe != null)
                {
                    path.Add(pe);
                    if (pe.IndexOf("@id") != -1)
                        break;  // Found an ID, no need to go upper, absolute path is OK
                }
                currentNode = currentNode.parentElement;
            }
            path.Reverse();
            return join(path, "/");
        }

        private static string join(ArrayList items, string delimiter)
        {
          StringBuilder sb = new StringBuilder();
          foreach (object item in items)
          {
            if (item == null)
                continue;

            sb.Append(delimiter);
            sb.Append(item);
          }
          return sb.ToString();
        }

        private static string getNode(mshtml.IHTMLElement node)
        {
            string nodeExpr = node.tagName;
            if (nodeExpr == null)  // Eg. node = #text
                return null;
            if (node.id != "" && node.id != null)
            {
                nodeExpr += "[@id='" + node.id + "']";
                // We don't really need to go back up to //HTML, since IDs are supposed
                // to be unique, so they are a good starting point.
                return "/" + nodeExpr;
            }

            // Find rank of node among its type in the parent
            int rank = 1;
            mshtml.IHTMLDOMNode nodeDom = node as mshtml.IHTMLDOMNode;
            mshtml.IHTMLDOMNode psDom = nodeDom.previousSibling;
            mshtml.IHTMLElement ps = psDom as mshtml.IHTMLElement;
            while (ps != null)
            {
                if (ps.tagName == node.tagName)
                {
                    rank++;
                }
                psDom = psDom.previousSibling;
                ps = psDom as mshtml.IHTMLElement;
            }
            if (rank > 1)
            {
                nodeExpr += "[" + rank + "]";
            }
            else
            { // First node of its kind at this level. Are there any others?
                mshtml.IHTMLDOMNode nsDom = nodeDom.nextSibling;
                mshtml.IHTMLElement ns = nsDom as mshtml.IHTMLElement;
                while (ns != null)
                {
                    if (ns.tagName == node.tagName)
                    { // Yes, mark it as being the first one
                        nodeExpr += "[1]";
                        break;
                    }
                    nsDom = nsDom.nextSibling;
                    ns = nsDom as mshtml.IHTMLElement;
                }
            }
            return nodeExpr;
        }
    }
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top