У меня есть веб-приложение только для Internet Explorer.
Я изучаю, что мы можем сделать для автоматизации тестирования.
Selenium выглядит неплохим инструментом, но чтобы активировать ссылки и т. д., Мне нужно сообщить ему, где они находятся. Приложение не создавалось с учетом такого рода тестирования, поэтому, как правило, у ключевых элементов нет атрибутов id.
Думаю, нет проблем, я могу использовать выражения XPath. Но найти правильный XPath, скажем, для кнопки, очень сложно, если это делается путем проверки источника страницы.
В Firefox / Firebug я могу выбрать элемент, а затем использовать «Копировать XPath», чтобы получить выражение.
У меня есть панель инструментов разработчика IE, и она ужасно близка. Я могу щелкнуть, чтобы выбрать интересующий элемент и отобразить всевозможную информацию о нем. но я не вижу удобного способа определить для него XPath.
Так есть ли способ сделать это с IE?
Обновил мой ответ, чтобы дать код. Обратите внимание, что вам нужно выбрать элемент, чтобы получить его XPath, это может раздражать некоторые активные компоненты, но я думаю, что в любом случае это может быть хорошей отправной точкой.
Да, это действительно только IE. Он даже не загружается в Firefox (приложение явно проверяет тип браузера)





Я бы использовал букмарклеты. У меня есть один связанный с XPath, но я не знаю, работает ли он в IE. Мне нужно идти, но я протестирую его и дам, если он работает в IE.
Два сайта букмарклетов для веб-разработчиков из моих закладок: Букмарклеты Subsimple и Букмарклеты Squarefree. Там много полезного ...
[РЕДАКТИРОВАТЬ] Хорошо, я вернулся. Букмарклет, который у меня был, был предназначен только для 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.
Теперь версии букмарклета (спасибо Конструктор букмарклетов):
IE
(Мне пришлось разбить его на две части, потому что IE не любит очень длинные букмарклеты (максимальный размер зависит от версии IE!). Вы должны активировать первый (function 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();
Выглядит интересно, но я понятия не имею, как добавить букмарклет :( Вы можете указать мне на что-нибудь, что объясняет это?
Надеюсь, вы получите такой ответ ... Добавить букмарклет очень просто: скопируйте строку javascript: (одну за другой в случае моих марклетов IE) и вставьте ее в адресную строку браузера (и нажмите Return). Затем вы можете добавить его в избранное (они тоже называются избранными), чтобы перезвонить им. Затем запускается JS.
Я получаю сообщение «Ошибка: ps имеет значение null. Исходный файл: javascript: function% ...» Этот код больше не работает в FF 3.5.5?
@Photodeus: Ой! Очевидно, вы первый, кто протестировал версию FF ... У меня была опечатка, ps вместо ns (в ns = ps.nextSibling). Исправлено в ответе. Спасибо за сообщение.
Интересный код. Интересно, можно ли адаптировать этот код для проверки заданного XPath элемента в DOM. Например. передать XPath и вернуть ссылку на элемент DOM, если он найден, или null / undefined в противном случае. Что-то вроде document.getElementByXPath (), document.getElementsByXPath (). Есть способ сделать это для других браузеров, но похоже, что код такой же техники не работает в IE. autumnator.wordpress.com/2013/05/02/…
Поскольку использование букмарклетов озадачило Пола, я решил добавить небольшое введение в их использование. Я делаю это в отдельном сообщении, чтобы не смешивать вещи.
Букмарклеты (также называемые избранными) - это небольшие сценарии JavaScript (sic), предназначенные для вставки в адресную строку браузера (как и любой другой URL-адрес) и, таким образом, для запуска на текущей странице. После его запуска (вставьте, нажмите Enter) вы можете добавить его в закладки для повторного использования (добавить в избранное в IE). Обратите внимание, что браузер может вместо этого добавить в закладки исходный URL-адрес, тогда вам придется отредактировать закладку и заменить URL-адрес своим скриптом. Конечно, вы также можете добавить его в адресную строку для быстрого доступа.
Эти скрипты действуют как часть текущей страницы, обращаясь к глобальным переменным и функциям JS, объектам Dom и т. д.
Они могут быть очень простыми, как исходный javascript: alert("Hello world!");, или довольно сложными, как приведенный выше. Если он возвращает значение (или если последнее выражение имеет значение), значение заменяет текущую страницу. Чтобы избежать этого, вы можете завершить сценарий с помощью alert (для отображения результата) или обернуть сценарий в определение функции и вызвать эту функцию, как я сделал выше. (Некоторые также ставят void (0); в конце, но я видел, что это считается плохой практикой.)
Функциональное решение имеет то преимущество, что все переменные сценария становятся локальными для апплета (если, конечно, объявлены с var), избегая вмешательства / побочных эффектов со сценариями на локальной странице. Вот почему функция упаковки должна иметь имя, которое вряд ли будет конфликтовать с локальным скриптом.
Обратите внимание, что некоторые браузеры (читай: «IE») могут ограничивать размер избранных, макс. длина меняется в зависимости от версии (имеет тенденцию к уменьшению). Вот почему все бесполезные пробелы удалены (построитель букмарлетов, указанный выше, хорош для этого), и я удалил явные сравнения с null и undefined, которые я обычно делаю. Мне также пришлось разделить фавлет на две части: первая часть определяла функцию (живущая до тех пор, пока страница не изменялась / не обновлялась), а вторая часть ее использовала.
Полезный инструмент, особенно в браузерах, не поддерживающих пользовательские скрипты (а-ля Greasemonkey) или без этого расширения.
Я переписал код букмарклета на 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;
}
}
}
Как бы вы тогда использовали эту версию C#?
Я попробовал этот код, и он отлично работает, за исключением того, что он не может преобразовать COM-объект в IHTMLElement, когда HTML-элемент имеет значение INPUT <code> mshtml.IHTMLElement ps = psDom as mshtml.IHTMLElement; </code> кто-нибудь может указать причину?
Вы говорите «только интернет-обозреватель». Означает ли это, что вы даже не можете открыть приложение в Firefox? Или просто он должен безупречно работать в IE, независимо от того, работает ли он в других браузерах?