зеркало из https://github.com/mozilla/gecko-dev.git
Bug 741598 - Enable finding elements of child nodes, r=jgriffin
This commit is contained in:
Родитель
3d76ad5939
Коммит
bb96b17e38
|
@ -112,7 +112,6 @@ function MarionetteDriverActor(aConnection)
|
|||
this.curBrowser = null; // points to current browser
|
||||
this.context = "content";
|
||||
this.scriptTimeout = null;
|
||||
this.elementManager = new ElementManager([SELECTOR, NAME, LINK_TEXT, PARTIAL_LINK_TEXT]);
|
||||
this.timer = null;
|
||||
this.marionetteLog = new MarionetteLogObj();
|
||||
this.command_id = null;
|
||||
|
@ -141,7 +140,7 @@ MarionetteDriverActor.prototype = {
|
|||
* Object to send to the listener
|
||||
*/
|
||||
sendAsync: function MDA_sendAsync(name, values) {
|
||||
this.messageManager.sendAsyncMessage("Marionette:" + name + this.browsers[this.curBrowser].curFrameId, values);
|
||||
this.messageManager.sendAsyncMessage("Marionette:" + name + this.curBrowser.curFrameId, values);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -249,9 +248,11 @@ MarionetteDriverActor.prototype = {
|
|||
let winId = win.QueryInterface(Ci.nsIInterfaceRequestor).
|
||||
getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
|
||||
winId = winId + ((appName == "B2G") ? '-b2g' : '');
|
||||
if (this.elementManager.seenItems[winId] == undefined) {
|
||||
this.browsers[winId] = browser;
|
||||
this.curBrowser = this.browsers[winId];
|
||||
if (this.curBrowser.elementManager.seenItems[winId] == undefined) {
|
||||
//add this to seenItems so we can guarantee the user will get winId as this window's id
|
||||
this.elementManager.seenItems[winId] = win;
|
||||
this.curBrowser.elementManager.seenItems[winId] = win;
|
||||
}
|
||||
this.browsers[winId] = browser;
|
||||
return winId;
|
||||
|
@ -270,11 +271,10 @@ MarionetteDriverActor.prototype = {
|
|||
* True if this is the first time we're talking to this browser
|
||||
*/
|
||||
startBrowser: function MDA_startBrowser(win, newSession) {
|
||||
let winId = this.addBrowser(win);
|
||||
this.curBrowser = winId;
|
||||
this.browsers[this.curBrowser].newSession = newSession;
|
||||
this.browsers[this.curBrowser].startSession(newSession);
|
||||
this.browsers[this.curBrowser].loadFrameScript("chrome://marionette/content/marionette-listener.js", win);
|
||||
this.addBrowser(win);
|
||||
this.curBrowser.newSession = newSession;
|
||||
this.curBrowser.startSession(newSession);
|
||||
this.curBrowser.loadFrameScript("chrome://marionette/content/marionette-listener.js", win);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -292,11 +292,10 @@ MarionetteDriverActor.prototype = {
|
|||
if (!prefs.getBoolPref("marionette.contentListener")) {
|
||||
this.startBrowser(this.getCurrentWindow(), true);
|
||||
}
|
||||
else if ((appName == "B2G")&& (this.curBrowser == null)) {
|
||||
else if ((appName == "B2G") && (this.curBrowser == null)) {
|
||||
//if there is a content listener, then we just wake it up
|
||||
let winId = this.addBrowser(this.getCurrentWindow());
|
||||
this.curBrowser = winId;
|
||||
this.browsers[this.curBrowser].startSession(false);
|
||||
this.addBrowser(this.getCurrentWindow());
|
||||
this.curBrowser.startSession(false);
|
||||
this.messageManager.sendAsyncMessage("Marionette:restart", {});
|
||||
}
|
||||
else {
|
||||
|
@ -354,7 +353,7 @@ MarionetteDriverActor.prototype = {
|
|||
*/
|
||||
createExecuteSandbox: function MDA_createExecuteSandbox(aWindow, marionette, args) {
|
||||
try {
|
||||
args = this.elementManager.convertWrappedArguments(args, aWindow);
|
||||
args = this.curBrowser.elementManager.convertWrappedArguments(args, aWindow);
|
||||
}
|
||||
catch(e) {
|
||||
this.sendError(e.message, e.num, e.stack);
|
||||
|
@ -363,7 +362,7 @@ MarionetteDriverActor.prototype = {
|
|||
|
||||
let _chromeSandbox = new Cu.Sandbox(aWindow,
|
||||
{ sandboxPrototype: aWindow, wantXrays: false, sandboxName: ''});
|
||||
_chromeSandbox.__namedArgs = this.elementManager.applyNamedArgs(args);
|
||||
_chromeSandbox.__namedArgs = this.curBrowser.elementManager.applyNamedArgs(args);
|
||||
_chromeSandbox.__marionetteParams = args;
|
||||
|
||||
marionette.exports.forEach(function(fn) {
|
||||
|
@ -405,7 +404,7 @@ MarionetteDriverActor.prototype = {
|
|||
}
|
||||
|
||||
if (!async) {
|
||||
this.sendResponse(this.elementManager.wrapValue(res));
|
||||
this.sendResponse(this.curBrowser.elementManager.wrapValue(res));
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
|
@ -542,7 +541,7 @@ MarionetteDriverActor.prototype = {
|
|||
curWindow.onerror = original_onerror;
|
||||
|
||||
if (status == 0 || status == undefined) {
|
||||
that.sendToClient({from: that.actorID, value: that.elementManager.wrapValue(value), status: status},
|
||||
that.sendToClient({from: that.actorID, value: that.curBrowser.elementManager.wrapValue(value), status: status},
|
||||
marionette.command_id);
|
||||
}
|
||||
else {
|
||||
|
@ -642,7 +641,11 @@ MarionetteDriverActor.prototype = {
|
|||
* Get the current window's server-assigned ID
|
||||
*/
|
||||
getWindow: function MDA_getWindow() {
|
||||
this.sendResponse(this.curBrowser);
|
||||
for (let i in this.browsers) {
|
||||
if (this.curBrowser == this.browsers[i]) {
|
||||
this.sendResponse(i);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -679,14 +682,14 @@ MarionetteDriverActor.prototype = {
|
|||
this.startBrowser(foundWin, false);
|
||||
}
|
||||
foundWin.focus();
|
||||
this.curBrowser = winId;
|
||||
this.curBrowser = this.browsers[winId];
|
||||
this.sendOk();
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.sendError("Unable to locate window " + aRequest.value, 23, null);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Switch to a given frame within the current window
|
||||
*
|
||||
|
@ -706,7 +709,7 @@ MarionetteDriverActor.prototype = {
|
|||
setSearchTimeout: function MDA_setSearchTimeout(aRequest) {
|
||||
if (this.context == "chrome") {
|
||||
try {
|
||||
this.elementManager.setSearchTimeout(aRequest.value);
|
||||
this.curBrowser.elementManager.setSearchTimeout(aRequest.value);
|
||||
this.sendOk();
|
||||
}
|
||||
catch (e) {
|
||||
|
@ -730,7 +733,7 @@ MarionetteDriverActor.prototype = {
|
|||
let id;
|
||||
try {
|
||||
let notify = this.sendResponse.bind(this);
|
||||
id = this.elementManager.find(aRequest, this.getCurrentWindow().document, notify, false);
|
||||
id = this.curBrowser.elementManager.find(this.getCurrentWindow(),aRequest, notify, false);
|
||||
}
|
||||
catch (e) {
|
||||
this.sendError(e.message, e.num, e.stack);
|
||||
|
@ -754,7 +757,7 @@ MarionetteDriverActor.prototype = {
|
|||
let id;
|
||||
try {
|
||||
let notify = this.sendResponse.bind(this);
|
||||
id = this.elementManager.find(aRequest, this.getCurrentWindow().document, notify, true);
|
||||
id = this.curBrowser.elementManager.find(this.getCurrentWindow(), aRequest, notify, true);
|
||||
}
|
||||
catch (e) {
|
||||
this.sendError(e.message, e.num, e.stack);
|
||||
|
@ -787,16 +790,16 @@ MarionetteDriverActor.prototype = {
|
|||
* and can safely be reused.
|
||||
*/
|
||||
deleteSession: function MDA_deleteSession() {
|
||||
if (this.browsers[this.curBrowser] != null) {
|
||||
if (this.curBrowser != null) {
|
||||
if (appName == "B2G") {
|
||||
this.messageManager.sendAsyncMessage("Marionette:sleepSession" + this.browsers[this.curBrowser].mainContentId, {});
|
||||
this.browsers[this.curBrowser].knownFrames.splice(this.browsers[this.curBrowser].knownFrames.indexOf(this.browsers[this.curBrowser].mainContentId), 1);
|
||||
this.messageManager.sendAsyncMessage("Marionette:sleepSession" + this.curBrowser.mainContentId, {});
|
||||
this.curBrowser.knownFrames.splice(this.curBrowser.knownFrames.indexOf(this.curBrowser.mainContentId), 1);
|
||||
}
|
||||
else {
|
||||
//don't set this pref for B2G since the framescript can be safely reused
|
||||
prefs.setBoolPref("marionette.contentListener", false);
|
||||
}
|
||||
this.browsers[this.curBrowser].closeTab();
|
||||
this.curBrowser.closeTab();
|
||||
//delete session in each frame in each browser
|
||||
for (let win in this.browsers) {
|
||||
for (let i in this.browsers[win].knownFrames) {
|
||||
|
@ -817,7 +820,6 @@ MarionetteDriverActor.prototype = {
|
|||
this.messageManager.removeMessageListener("Marionette:register", this);
|
||||
this.messageManager.removeMessageListener("Marionette:goUrl", this);
|
||||
this.curBrowser = null;
|
||||
this.elementManager.reset();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -849,15 +851,15 @@ MarionetteDriverActor.prototype = {
|
|||
case "Marionette:register":
|
||||
// This code processes the content listener's registration information
|
||||
// and either accepts the listener, or ignores it
|
||||
let nullPrevious= (this.browsers[this.curBrowser].curFrameId == null);
|
||||
let nullPrevious = (this.curBrowser.curFrameId == null);
|
||||
let curWin = this.getCurrentWindow();
|
||||
let frameObject = curWin.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindowUtils).getOuterWindowWithId(message.json.value);
|
||||
let reg = this.browsers[this.curBrowser].register(message.json.value, message.json.href);
|
||||
let reg = this.curBrowser.register(message.json.value, message.json.href);
|
||||
if (reg) {
|
||||
this.elementManager.seenItems[reg] = frameObject; //add to seenItems
|
||||
if (nullPrevious && (this.browsers[this.curBrowser].curFrameId != null)) {
|
||||
this.curBrowser.elementManager.seenItems[reg] = frameObject; //add to seenItems
|
||||
if (nullPrevious && (this.curBrowser.curFrameId != null)) {
|
||||
this.sendAsync("newSession", {B2G: (appName == "B2G")});
|
||||
if (this.browsers[this.curBrowser].newSession) {
|
||||
if (this.curBrowser.newSession) {
|
||||
this.sendResponse(reg);
|
||||
}
|
||||
}
|
||||
|
@ -866,7 +868,7 @@ MarionetteDriverActor.prototype = {
|
|||
case "Marionette:goUrl":
|
||||
// if content determines that the goUrl call is directed at a top level window (not an iframe)
|
||||
// it calls back into chrome to load the uri.
|
||||
this.browsers[this.curBrowser].loadURI(message.json.value, this);
|
||||
this.curBrowser.loadURI(message.json.value, this);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
@ -876,7 +878,7 @@ MarionetteDriverActor.prototype = {
|
|||
handleEvent: function MDA_handleEvent(evt) {
|
||||
if (evt.type == "DOMContentLoaded") {
|
||||
this.sendOk();
|
||||
this.browsers[this.curBrowser].browser.removeEventListener("DOMContentLoaded", this, false);
|
||||
this.curBrowser.browser.removeEventListener("DOMContentLoaded", this, false);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@ -927,6 +929,7 @@ function BrowserObj(win) {
|
|||
this.messageManager = Cc["@mozilla.org/globalmessagemanager;1"].
|
||||
getService(Ci.nsIChromeFrameMessageManager);
|
||||
this.newSession = true; //used to set curFrameId upon new session
|
||||
this.elementManager = new ElementManager([SELECTOR, NAME, LINK_TEXT, PARTIAL_LINK_TEXT]);
|
||||
this.setBrowser(win);
|
||||
}
|
||||
|
||||
|
|
|
@ -125,7 +125,6 @@ ElementManager.prototype = {
|
|||
else if (val == null) {
|
||||
result = null;
|
||||
}
|
||||
// nodeType 1 == 'element'
|
||||
else if (val.nodeType == 1) {
|
||||
for(let i in this.seenItems) {
|
||||
if (this.seenItems[i] == val) {
|
||||
|
@ -222,18 +221,20 @@ ElementManager.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Find an element or elements starting at the document root
|
||||
* using the given search strategy. Search
|
||||
* Find an element or elements starting at the document root or
|
||||
* given node, using the given search strategy. Search
|
||||
* will continue until the search timelimit has been reached.
|
||||
*
|
||||
* @param nsIDOMWindow win
|
||||
* The window to search in
|
||||
* @param object values
|
||||
* The 'using' member of values will tell us which search
|
||||
* method to use. The 'value' member tells us the value we
|
||||
* are looking for.
|
||||
* If this object has an 'element' member, this will be used
|
||||
* as the start node instead of the document root
|
||||
* If this object has a 'time' member, this number will be
|
||||
* used to see if we have hit the search timelimit.
|
||||
* @param nsIDOMElement rootNode
|
||||
* The document root
|
||||
* @param function notify
|
||||
* The notification callback used when we are returning
|
||||
* @param boolean all
|
||||
|
@ -243,12 +244,13 @@ ElementManager.prototype = {
|
|||
* @return nsIDOMElement or list of nsIDOMElements
|
||||
* Returns the element(s) by calling the notify function.
|
||||
*/
|
||||
find: function EM_find(values, rootNode, notify, all) {
|
||||
find: function EM_find(win, values, notify, all) {
|
||||
let startTime = values.time ? values.time : new Date().getTime();
|
||||
let startNode = (values.element != undefined) ? this.getKnownElement(values.element, win) : win.document;
|
||||
if (this.elementStrategies.indexOf(values.using) < 0) {
|
||||
throw new ElementException("No such strategy.", 17, null);
|
||||
}
|
||||
let found = all ? this.findElements(values.using, values.value, rootNode) : this.findElement(values.using, values.value, rootNode);
|
||||
let found = all ? this.findElements(values.using, values.value, win.document, startNode) : this.findElement(values.using, values.value, win.document, startNode);
|
||||
if (found) {
|
||||
let type = Object.prototype.toString.call(found);
|
||||
if ((type == '[object Array]') || (type == '[object HTMLCollection]')) {
|
||||
|
@ -268,10 +270,53 @@ ElementManager.prototype = {
|
|||
throw new ElementException("Unable to locate element: " + values.value, 7, null);
|
||||
} else {
|
||||
values.time = startTime;
|
||||
this.timer.initWithCallback(this.find.bind(this, values, rootNode, notify, all), 100, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
|
||||
this.timer.initWithCallback(this.find.bind(this, win, values, notify, all), 100, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Find a value by XPATH
|
||||
*
|
||||
* @param nsIDOMElement root
|
||||
* Document root
|
||||
* @param string value
|
||||
* XPATH search string
|
||||
* @param nsIDOMElement node
|
||||
* start node
|
||||
*
|
||||
* @return nsIDOMElement
|
||||
* returns the found element
|
||||
*/
|
||||
findByXPath: function EM_findByXPath(root, value, node) {
|
||||
return root.evaluate(value, node, null,
|
||||
Components.interfaces.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
|
||||
},
|
||||
|
||||
/**
|
||||
* Find values by XPATH
|
||||
*
|
||||
* @param nsIDOMElement root
|
||||
* Document root
|
||||
* @param string value
|
||||
* XPATH search string
|
||||
* @param nsIDOMElement node
|
||||
* start node
|
||||
*
|
||||
* @return object
|
||||
* returns a list of found nsIDOMElements
|
||||
*/
|
||||
findByXPathAll: function EM_findByXPathAll(root, value, node) {
|
||||
let values = root.evaluate(value, node, null,
|
||||
Components.interfaces.nsIDOMXPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
|
||||
let elements = [];
|
||||
let element = values.iterateNext();
|
||||
while (element) {
|
||||
elements.push(element);
|
||||
element = values.iterateNext();
|
||||
}
|
||||
return elements;
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper method to find. Finds one element using find's criteria
|
||||
|
@ -282,33 +327,37 @@ ElementManager.prototype = {
|
|||
* Value to look for
|
||||
* @param nsIDOMElement rootNode
|
||||
* Document root
|
||||
* @param nsIDOMElement startNode
|
||||
* Node from which we start searching
|
||||
*
|
||||
* @return nsIDOMElement
|
||||
* Returns found element or throws Exception if not found
|
||||
*/
|
||||
findElement: function EM_findElement(using, value, rootNode) {
|
||||
findElement: function EM_findElement(using, value, rootNode, startNode) {
|
||||
let element;
|
||||
switch (using) {
|
||||
case ID:
|
||||
element = rootNode.getElementById(value);
|
||||
element = startNode.getElementById ?
|
||||
startNode.getElementById(value) :
|
||||
this.findByXPath(rootNode, './/*[@id="' + value + '"]', startNode);
|
||||
break;
|
||||
case NAME:
|
||||
element = rootNode.getElementsByName(value)[0];
|
||||
element = startNode.getElementsByName ?
|
||||
startNode.getElementsByName(value)[0] :
|
||||
this.findByXPath(rootNode, './/*[@name="' + value + '"]', startNode);
|
||||
break;
|
||||
case CLASS_NAME:
|
||||
element = rootNode.getElementsByClassName(value)[0];
|
||||
element = startNode.getElementsByClassName(value)[0]; //works for >=FF3
|
||||
break;
|
||||
case TAG:
|
||||
element = rootNode.getElementsByTagName(value)[0];
|
||||
element = startNode.getElementsByTagName(value)[0]; //works for all elements
|
||||
break;
|
||||
case XPATH:
|
||||
element = rootNode.evaluate(value, rootNode, null,
|
||||
Components.interfaces.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE, null).
|
||||
singleNodeValue;
|
||||
element = this.findByXPath(rootNode, value, startNode);
|
||||
break;
|
||||
case LINK_TEXT:
|
||||
case PARTIAL_LINK_TEXT:
|
||||
let allLinks = rootNode.getElementsByTagName('A');
|
||||
let allLinks = startNode.getElementsByTagName('A');
|
||||
for (let i = 0; i < allLinks.length && !element; i++) {
|
||||
let text = allLinks[i].text;
|
||||
if (PARTIAL_LINK_TEXT == using) {
|
||||
|
@ -321,7 +370,7 @@ ElementManager.prototype = {
|
|||
}
|
||||
break;
|
||||
case SELECTOR:
|
||||
element = rootNode.querySelector(value);
|
||||
element = startNode.querySelector(value);
|
||||
break;
|
||||
default:
|
||||
throw new ElementException("No such strategy", 500, null);
|
||||
|
@ -338,32 +387,30 @@ ElementManager.prototype = {
|
|||
* Value to look for
|
||||
* @param nsIDOMElement rootNode
|
||||
* Document root
|
||||
* @param nsIDOMElement startNode
|
||||
* Node from which we start searching
|
||||
*
|
||||
* @return nsIDOMElement
|
||||
* Returns found elements or throws Exception if not found
|
||||
*/
|
||||
findElements: function EM_findElements(using, value, rootNode) {
|
||||
findElements: function EM_findElements(using, value, rootNode, startNode) {
|
||||
let elements = [];
|
||||
switch (using) {
|
||||
case ID:
|
||||
value = './/*[@id="' + value + '"]';
|
||||
case XPATH:
|
||||
values = rootNode.evaluate(value, rootNode, null,
|
||||
Components.interfaces.nsIDOMXPathResult.ORDERED_NODE_ITERATOR_TYPE, null)
|
||||
let element = values.iterateNext();
|
||||
while (element) {
|
||||
elements.push(element);
|
||||
element = values.iterateNext();
|
||||
}
|
||||
elements = this.findByXPathAll(rootNode, value, startNode);
|
||||
break;
|
||||
case NAME:
|
||||
elements = rootNode.getElementsByName(value);
|
||||
element = startNode.getElementsByName ?
|
||||
startNode.getElementsByName(value)[0] :
|
||||
this.findByXPathAll(rootNode, './/*[@name="' + value + '"]', startNode);
|
||||
break;
|
||||
case CLASS_NAME:
|
||||
elements = rootNode.getElementsByClassName(value);
|
||||
elements = startNode.getElementsByClassName(value);
|
||||
break;
|
||||
case TAG:
|
||||
elements = rootNode.getElementsByTagName(value);
|
||||
elements = startNode.getElementsByTagName(value);
|
||||
break;
|
||||
case LINK_TEXT:
|
||||
case PARTIAL_LINK_TEXT:
|
||||
|
|
|
@ -425,7 +425,8 @@ function findElementContent(msg) {
|
|||
let id;
|
||||
try {
|
||||
let notify = function(id) { sendResponse({value:id});};
|
||||
id = elementManager.find(msg.json, win.document, notify, false);
|
||||
let curWin = activeFrame ? win.frames[activeFrame] : win;
|
||||
id = elementManager.find(curWin, msg.json, notify, false);
|
||||
}
|
||||
catch (e) {
|
||||
sendError(e.message, e.num, e.stack);
|
||||
|
@ -441,7 +442,8 @@ function findElementsContent(msg) {
|
|||
let id;
|
||||
try {
|
||||
let notify = function(id) { sendResponse({value:id});};
|
||||
id = elementManager.find(msg.json, win.document, notify, true);
|
||||
let curWin = activeFrame ? win.frames[activeFrame] : win;
|
||||
id = elementManager.find(curWin, msg.json, notify, true);
|
||||
}
|
||||
catch (e) {
|
||||
sendError(e.message, e.num, e.stack);
|
||||
|
|
Загрузка…
Ссылка в новой задаче