Pregunta

Tengo una aplicación web única de Internet Explorer.

Estoy explorando qué podemos hacer para automatizar las pruebas.

Selenium parece una buena herramienta, pero para poder activar enlaces, etc., necesito decirle dónde están. La aplicación no se creó teniendo en cuenta este tipo de pruebas, por lo que generalmente no hay atributos de id en los elementos clave.

No hay problema, creo que puedo usar expresiones XPath. Pero encontrar el XPath correcto para, por ejemplo, un botón, es un dolor real si se hace al inspeccionar la fuente de la página.

Con Firefox / Firebug, puedo seleccionar el elemento y luego usar " Copy XPath " para obtener la expresión.

Tengo la barra de herramientas del desarrollador de IE y está frustrantemente cerca. Puedo hacer clic para seleccionar el elemento de interés y mostrar todo tipo de información sobre él. pero no veo ninguna forma conveniente de determinar el XPath para ello.

Entonces, ¿hay alguna forma de hacer esto con IE?

¿Fue útil?

Solución

Yo usaría bookmarklets. Tengo un XPath relacionado, pero no sé si funciona en IE. Tengo que irme, pero lo probaré y lo daré si funciona en IE.

Dos sitios de marcadores para desarrolladores web de mis marcadores: bookmarklets de Subsimple y Bookmarkfree's Bookmarklets . Muchas cosas útiles allí ...

[EDITAR] OK, estoy de vuelta. El bookmarklet que tenía era solo para FF, y no era óptimo. Finalmente lo reescribí, aunque utilizando ideas del original. No puedo encontrarlo donde lo encontré.

JS expandido:

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.

Debes seleccionar el elemento y activar el bookmarklet para obtener su XPath.

Ahora, las versiones de bookmarklet (gracias a Bookmarklet Builder ):

IE
(Tuve que dividirlo en dos partes, porque a IE no le gustan los bookmarklets muy largos (¡el tamaño máximo varía según las versiones de IE!). Debes activar el primero (función def) y luego el segundo. Probado con 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();

Otros consejos

Dado que el uso del bookmarklet desconcertó a Paul, pensé que debería agregar una pequeña introducción a su uso. Lo hago en un mensaje separado para evitar mezclar cosas.

Los Bookmarklets (también llamados favlets) son pequeños scripts de JavaScript (sic) diseñados para ser pegados en la barra de direcciones del navegador (como cualquier otra URL) y, por lo tanto, se ejecutan en la página actual.
Después de ejecutarlo (pegar, pulsar Enter), puede marcarlo para volver a utilizarlo (agregarlo a favoritos en IE). Tenga en cuenta que el navegador puede marcar la URL original en su lugar, entonces tiene que editar el marcador y reemplazar la URL con su script. Por supuesto, también puede agregarlo a la barra de URL para un acceso rápido.

Estos scripts actúan como parte de la página actual, accediendo a variables y funciones globales de JS, objetos Dom, etc.
Pueden ser súper simples, como el javascript: alert (" Hello world! & Quot;); , o muy complejos como el de arriba. Si devuelve un valor (o si la última expresión tiene un valor), el valor reemplaza la página actual. Para evitar esto, puede finalizar el script con alert (para mostrar un resultado) o envolver el script en una definición de función y llamar a esta función, como hice anteriormente. (Algunos también ponen void (0); al final, pero vi que se considera una mala práctica).

La solución de función tiene la ventaja de hacer que todas las variables del script sean locales al applet (si se declaran con var , por supuesto), evitando las interferencias / efectos secundarios con los scripts en la página local. Es también por eso que la función de ajuste debe tener un nombre que probablemente no coincida con un script local.

Tenga en cuenta que algunos navegadores (leer: " IE ") pueden limitar el tamaño de los favlets, el máximo. La longitud varía según la versión (tiende a disminuir). Es por eso que se eliminan todos los espacios en blanco inútiles (el generador de bookmarlet vinculado arriba es bueno para eso) y eliminé las comparaciones explícitas con null e indefinido que generalmente hago. También tuve que dividir el favlet en dos, la primera parte definió una función (vivir siempre y cuando la página no se haya cambiado / actualizado), la segunda parte la usó.

Herramienta útil, especialmente en navegadores que no permiten scripts de usuario (à la Greasemonkey) o sin esta extensión.

He reescrito el código del bookmarklet en C #, por lo que si lo encuentras útil, úsalo ;-)

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;
        }
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top