2008-10-18 9 views
11

Ich habe eine Internet Explorer nur Web-Anwendung.Entspricht Firebug "XPath kopieren" im Internet Explorer?

Ich erkunde, was wir tun können, um das Testen zu automatisieren.

Selen sieht wie ein gutes Werkzeug aus, aber um Links aktivieren zu können usw. muss ich sagen, wo sie sind. Die Anwendung wurde nicht mit dieser Art von Tests im Hinterkopf gebaut, so dass es in der Regel keine id Attribute auf den Schlüsselelementen gibt.

Kein Problem, ich denke, ich kann XPath Ausdrücke verwenden. Den richtigen XPath zum Beispiel für einen Button zu finden, ist ein roher Schmerz, wenn man die Quelle der Seite überprüft.

Mit Firefox/Firebug kann ich das Element auswählen und dann "XPath kopieren" verwenden, um den Ausdruck zu erhalten.

Ich habe die IE Developer Toolbar und es ist frustrierend nah. Ich kann klicken, um das Element von Interesse auszuwählen und alle möglichen Informationen darüber anzuzeigen. aber ich kann keine bequeme Möglichkeit sehen, den XPath dafür zu bestimmen.

Also gibt es eine Möglichkeit, dies mit IE zu tun?

+0

Sie "nur Internet-Explorer" sagen. Bedeutet das, dass Sie die Anwendung nicht einmal in Firefox öffnen können? Oder nur, dass es im IE einwandfrei funktionieren muss, egal ob es in anderen Browsern funktioniert? – pkaeding

+0

Meine Antwort aktualisiert, um Code zu geben. Beachten Sie, dass Sie ein Element auswählen müssen, um seinen XPath zu erhalten, was für einige aktive Komponenten lästig sein kann, aber ich denke, dass es sowieso ein guter Ausgangspunkt sein kann. – PhiLho

+0

Ja, es ist wirklich nur IE. Es wird nicht einmal in Firefox geladen (die App sucht explizit nach dem Browsertyp) –

Antwort

7

Ich würde Bookmarklets verwenden. Ich habe einen XPath bezogen, aber ich weiß nicht, ob es in IE funktioniert. Ich muss gehen, aber ich werde es testen und es geben, wenn es auf IE funktioniert.

Zwei Bookmarklet-Sites für Web-Entwickler aus meinen Lesezeichen: Subsimple's bookmarklets und Squarefree's Bookmarklets. Viele nützliche Dinge gibt es ...

[EDIT] OK, ich bin zurück. Das Bookmarklet, das ich hatte, war nur für FF und war nicht optimal. Ich habe es schließlich neu geschrieben, obwohl ich Ideen aus dem Original verwendet habe. Kann nicht finden, wo ich es gefunden habe.

JS Expanded:

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. 

Sie haben das Element auswählen und aktivieren das Bookmarklet seine XPath zu bekommen.

Nun werden die Bookmarklet Versionen (dank Bookmarklet Builder):

IE
(ich hatte es in zwei Teile zu brechen, weil IE nicht mag sehr lange Bookmarklets (maximale Größe je nach IE-Versionen variiert!). Sie haben die erste (Funktion def) dann die zweite mit IE6 getestet zu aktivieren..)

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(); 
+0

Sieht interessant aus, aber ich habe keine Ahnung, wie man ein Bookmarklet hinzufügt :(Kannst du mich auf etwas hinweisen, das das erklärt? –

+0

Ich hoffe du bekommst Eine solche Antwort ... Um ein Bookmarklet hinzuzufügen, ist das einfach: kopiere die javascript: -Zeile (bei meinen IE-Marklets einzeln) und füge sie in die Adressleiste des Browsers ein (und drücke Return) füge sie zu den Favoriten hinzu (sie heißen auch favlets), um sie zurückzurufen. JS wird dann ausgeführt. – PhiLho

+0

Ich bekomme "Fehler: ps ist null. Quelldatei: javascript: function% ..." Ist dieser Code in FF nicht mehr vorhanden? 3.5.5? – Photodeus

3

Da Bookmarklet verwendet verwirrt Paul, ich sollte ich eine kleine Einführung in ihre Verwendung hinzufügen. Ich mache es in einer separaten Nachricht, um zu vermeiden, dass man etwas vermischt.

Bookmarklets (auch favlets genannt) sind kleine JavaScript-Skripte (sic), die in die Adressleiste des Browsers (wie jede andere URL) eingefügt werden und somit auf der aktuellen Seite ausgeführt werden.
Nach dem Ausführen (Einfügen, drücken Sie die Eingabetaste), können Sie ein Lesezeichen für die Wiederverwendung (fügen Sie es zu den Favoriten in IE). Beachten Sie, dass der Browser stattdessen die ursprüngliche URL mit einem Lesezeichen versehen kann. Sie müssen dann das Lesezeichen bearbeiten und die URL durch Ihr Skript ersetzen.
Natürlich können Sie es für einen schnellen Zugriff auch der URL-Leiste hinzufügen.

Diese Skripte wirken wie ein Teil der aktuellen Seite zu sein, den Zugriff auf globale JS Variablen und Funktionen, Dom Objekte usw.
Sie können super einfach sein, wie die Samen javascript: alert("Hello world!"); oder ziemlich komplex wie die oben. Wenn es einen Wert zurückgibt (oder wenn der letzte Ausdruck einen Wert hat), ersetzt der Wert die aktuelle Seite. Um dies zu vermeiden, können Sie das Skript mit alert abschließen (um ein Ergebnis anzuzeigen) oder das Skript in eine Funktionsdefinition umbrechen und diese Funktion aufrufen, wie oben beschrieben. (Einige stellen auch void (0); am Ende, aber ich sah es als schlechte Praxis gesehen.)

Die Funktionslösung hat den Vorteil, alle Variablen des Skripts lokal zum Applet zu machen (wenn mit var deklariert (natürlich), um Interferenzen/Nebeneffekte mit Skripten auf der lokalen Seite zu vermeiden. Aus diesem Grund sollte die Umbruchfunktion einen Namen haben, der wahrscheinlich nicht mit einem lokalen Skript kollidiert.

Beachten Sie, dass einige Browser (sprich: "IE") die Größe von Favlets einschränken können, die max. Länge variiert mit der Version (Tendenz abnehmend). Das ist der Grund, warum alle nutzlosen Leerzeichen entfernt wurden (der oben verlinkte Bookmarlet-Builder ist dafür gut geeignet) und ich entfernte die explicit-Vergleiche mit null und undefined, was ich normalerweise tue. Ich musste das favlet auch in zwei teilen, ersten Teil, der eine Funktion definiert (Leben, solange die Seite nicht geändert/aufgefrischt wird), zweiter Teil, der es benutzt.

Nützliches Tool, insbesondere in Browsern, die keine Benutzer-Skripte (à la Greasemonkey) oder ohne diese Erweiterung erlauben.

2

ich das Bookmarklet-Code in C# geschrieben haben, also wenn Sie es nützlich finden, verwenden Sie es ;-)

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; 
     } 
    } 
} 
+0

Wie würden Sie dann diese C# Version verwenden? – David

+0

Ich habe versucht, diesen Code und es funktioniert gut, außer es schlägt fehl, das COM-Objekt in IHTMLElement zu konvertieren, wenn das HTML-Element ist INPUT kann jemand den Grund angeben? – Tejas