зеркало из https://github.com/mozilla/gecko-dev.git
Bug 779011 - Attach id's to all requests to prevent Marionette from getting out-of-sync, r=mdas, a=NPOTB
This commit is contained in:
Родитель
1eae4fe353
Коммит
943c2ac121
|
@ -19,7 +19,7 @@ function MarionetteComponent() {
|
||||||
this._loaded = false;
|
this._loaded = false;
|
||||||
// set up the logger
|
// set up the logger
|
||||||
this.logger = Log4Moz.repository.getLogger("Marionette");
|
this.logger = Log4Moz.repository.getLogger("Marionette");
|
||||||
this.logger.level = Log4Moz.Level["All"];
|
this.logger.level = Log4Moz.Level["INFO"];
|
||||||
let logf = FileUtils.getFile('ProfD', ['marionette.log']);
|
let logf = FileUtils.getFile('ProfD', ['marionette.log']);
|
||||||
|
|
||||||
let formatter = new Log4Moz.BasicFormatter();
|
let formatter = new Log4Moz.BasicFormatter();
|
||||||
|
|
|
@ -123,6 +123,7 @@ function MarionetteRemoteFrame(windowId, frameId) {
|
||||||
this.frameId = frameId;
|
this.frameId = frameId;
|
||||||
this.targetFrameId = null;
|
this.targetFrameId = null;
|
||||||
this.messageManager = null;
|
this.messageManager = null;
|
||||||
|
this.command_id = null;
|
||||||
}
|
}
|
||||||
// persistent list of remote frames that Marionette has loaded a frame script in
|
// persistent list of remote frames that Marionette has loaded a frame script in
|
||||||
let remoteFrames = [];
|
let remoteFrames = [];
|
||||||
|
@ -239,6 +240,10 @@ MarionetteDriverActor.prototype = {
|
||||||
messageManager.removeMessageListener("Marionette:switchToFrame", this);
|
messageManager.removeMessageListener("Marionette:switchToFrame", this);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
logRequest: function MDA_logRequest(type, data) {
|
||||||
|
logger.debug("Got request: " + type + ", data: " + JSON.stringify(data) + ", id: " + this.command_id);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic method to pass a response to the client
|
* Generic method to pass a response to the client
|
||||||
*
|
*
|
||||||
|
@ -250,9 +255,12 @@ MarionetteDriverActor.prototype = {
|
||||||
*/
|
*/
|
||||||
sendToClient: function MDA_sendToClient(msg, command_id) {
|
sendToClient: function MDA_sendToClient(msg, command_id) {
|
||||||
logger.info("sendToClient: " + JSON.stringify(msg) + ", " + command_id + ", " + this.command_id);
|
logger.info("sendToClient: " + JSON.stringify(msg) + ", " + command_id + ", " + this.command_id);
|
||||||
if (this.command_id != null &&
|
if (!command_id) {
|
||||||
command_id != null &&
|
logger.warn("got a response with no command_id");
|
||||||
|
}
|
||||||
|
else if (this.command_id &&
|
||||||
this.command_id != command_id) {
|
this.command_id != command_id) {
|
||||||
|
logger.warn("ignoring out-of-sync response");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.conn.send(msg);
|
this.conn.send(msg);
|
||||||
|
@ -432,8 +440,20 @@ MarionetteDriverActor.prototype = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getCommandId: function MDA_getCommandId() {
|
||||||
|
return this.uuidGen.generateUUID().toString();
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marionette API:
|
* Marionette API:
|
||||||
|
*
|
||||||
|
* All methods implementing a command from the client should create a
|
||||||
|
* command_id, and then use this command_id in all messages exchanged with
|
||||||
|
* the frame scripts and with responses sent to the client. This prevents
|
||||||
|
* commands and responses from getting out-of-sync, which can happen in
|
||||||
|
* the case of execute_async calls that timeout and then later send a
|
||||||
|
* response, and other situations. See bug 779011. See setScriptTimeout()
|
||||||
|
* for a basic example.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -444,6 +464,8 @@ MarionetteDriverActor.prototype = {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
newSession: function MDA_newSession() {
|
newSession: function MDA_newSession() {
|
||||||
|
this.command_id = this.getCommandId();
|
||||||
|
|
||||||
this.scriptTimeout = 10000;
|
this.scriptTimeout = 10000;
|
||||||
|
|
||||||
function waitForWindow() {
|
function waitForWindow() {
|
||||||
|
@ -471,11 +493,13 @@ MarionetteDriverActor.prototype = {
|
||||||
this.messageManager.broadcastAsyncMessage("Marionette:restart", {});
|
this.messageManager.broadcastAsyncMessage("Marionette:restart", {});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.sendError("Session already running", 500, null);
|
this.sendError("Session already running", 500, null, this.command_id);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getSessionCapabilities: function MDA_getSessionCapabilities(){
|
getSessionCapabilities: function MDA_getSessionCapabilities(){
|
||||||
|
this.command_id = this.getCommandId();
|
||||||
|
|
||||||
let rotatable = appName == "B2G" ? true : false;
|
let rotatable = appName == "B2G" ? true : false;
|
||||||
|
|
||||||
let value = {
|
let value = {
|
||||||
|
@ -492,10 +516,12 @@ MarionetteDriverActor.prototype = {
|
||||||
'version': Services.appinfo.version
|
'version': Services.appinfo.version
|
||||||
};
|
};
|
||||||
|
|
||||||
this.sendResponse(value);
|
this.sendResponse(value, this.command_id);
|
||||||
},
|
},
|
||||||
|
|
||||||
getStatus: function MDA_getStatus(){
|
getStatus: function MDA_getStatus(){
|
||||||
|
this.command_id = this.getCommandId();
|
||||||
|
|
||||||
let arch;
|
let arch;
|
||||||
try {
|
try {
|
||||||
arch = (Services.appinfo.XPCOMABI || 'unknown').split('-')[0]
|
arch = (Services.appinfo.XPCOMABI || 'unknown').split('-')[0]
|
||||||
|
@ -517,7 +543,7 @@ MarionetteDriverActor.prototype = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.sendResponse(value);
|
this.sendResponse(value, this.command_id);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -528,30 +554,34 @@ MarionetteDriverActor.prototype = {
|
||||||
* 'level' member hold log level
|
* 'level' member hold log level
|
||||||
*/
|
*/
|
||||||
log: function MDA_log(aRequest) {
|
log: function MDA_log(aRequest) {
|
||||||
|
this.command_id = this.getCommandId();
|
||||||
this.marionetteLog.log(aRequest.value, aRequest.level);
|
this.marionetteLog.log(aRequest.value, aRequest.level);
|
||||||
this.sendOk();
|
this.sendOk(this.command_id);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return all logged messages.
|
* Return all logged messages.
|
||||||
*/
|
*/
|
||||||
getLogs: function MDA_getLogs() {
|
getLogs: function MDA_getLogs() {
|
||||||
this.sendResponse(this.marionetteLog.getLogs());
|
this.command_id = this.getCommandId();
|
||||||
|
this.sendResponse(this.marionetteLog.getLogs(), this.command_id);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log some performance data
|
* Log some performance data
|
||||||
*/
|
*/
|
||||||
addPerfData: function MDA_addPerfData(aRequest) {
|
addPerfData: function MDA_addPerfData(aRequest) {
|
||||||
|
this.command_id = this.getCommandId();
|
||||||
this.marionettePerf.addPerfData(aRequest.suite, aRequest.name, aRequest.value);
|
this.marionettePerf.addPerfData(aRequest.suite, aRequest.name, aRequest.value);
|
||||||
this.sendOk();
|
this.sendOk(this.command_id);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the performance data
|
* Retrieve the performance data
|
||||||
*/
|
*/
|
||||||
getPerfData: function MDA_getPerfData() {
|
getPerfData: function MDA_getPerfData() {
|
||||||
this.sendResponse(this.marionettePerf.getPerfData());
|
this.command_id = this.getCommandId();
|
||||||
|
this.sendResponse(this.marionettePerf.getPerfData(), this.command_id);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -561,13 +591,15 @@ MarionetteDriverActor.prototype = {
|
||||||
* 'value' member holds the name of the context to be switched to
|
* 'value' member holds the name of the context to be switched to
|
||||||
*/
|
*/
|
||||||
setContext: function MDA_setContext(aRequest) {
|
setContext: function MDA_setContext(aRequest) {
|
||||||
|
this.command_id = this.getCommandId();
|
||||||
|
this.logRequest("setContext", aRequest);
|
||||||
let context = aRequest.value;
|
let context = aRequest.value;
|
||||||
if (context != "content" && context != "chrome") {
|
if (context != "content" && context != "chrome") {
|
||||||
this.sendError("invalid context", 500, null);
|
this.sendError("invalid context", 500, null, this.command_id);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.sendOk();
|
this.sendOk(this.command_id);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -637,11 +669,11 @@ MarionetteDriverActor.prototype = {
|
||||||
* True if the script is asynchronous
|
* True if the script is asynchronous
|
||||||
*/
|
*/
|
||||||
executeScriptInSandbox: function MDA_executeScriptInSandbox(sandbox, script,
|
executeScriptInSandbox: function MDA_executeScriptInSandbox(sandbox, script,
|
||||||
directInject, async) {
|
directInject, async, command_id) {
|
||||||
|
|
||||||
if (directInject && async &&
|
if (directInject && async &&
|
||||||
(this.scriptTimeout == null || this.scriptTimeout == 0)) {
|
(this.scriptTimeout == null || this.scriptTimeout == 0)) {
|
||||||
this.sendError("Please set a timeout", 21, null);
|
this.sendError("Please set a timeout", 21, null, command_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -657,12 +689,13 @@ MarionetteDriverActor.prototype = {
|
||||||
|
|
||||||
if (directInject && !async &&
|
if (directInject && !async &&
|
||||||
(res == undefined || res.passed == undefined)) {
|
(res == undefined || res.passed == undefined)) {
|
||||||
this.sendError("finish() not called", 500, null);
|
this.sendError("finish() not called", 500, null, command_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!async) {
|
if (!async) {
|
||||||
this.sendResponse(this.curBrowser.elementManager.wrapValue(res));
|
this.sendResponse(this.curBrowser.elementManager.wrapValue(res),
|
||||||
|
command_id);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -678,6 +711,8 @@ MarionetteDriverActor.prototype = {
|
||||||
* function body
|
* function body
|
||||||
*/
|
*/
|
||||||
execute: function MDA_execute(aRequest, directInject) {
|
execute: function MDA_execute(aRequest, directInject) {
|
||||||
|
let command_id = this.command_id = this.getCommandId();
|
||||||
|
this.logRequest("execute", aRequest);
|
||||||
if (aRequest.newSandbox == undefined) {
|
if (aRequest.newSandbox == undefined) {
|
||||||
//if client does not send a value in newSandbox,
|
//if client does not send a value in newSandbox,
|
||||||
//then they expect the same behaviour as webdriver
|
//then they expect the same behaviour as webdriver
|
||||||
|
@ -687,7 +722,8 @@ MarionetteDriverActor.prototype = {
|
||||||
this.sendAsync("executeScript", {value: aRequest.value,
|
this.sendAsync("executeScript", {value: aRequest.value,
|
||||||
args: aRequest.args,
|
args: aRequest.args,
|
||||||
newSandbox: aRequest.newSandbox,
|
newSandbox: aRequest.newSandbox,
|
||||||
timeout: this.scriptTimeout});
|
timeout: this.scriptTimeout,
|
||||||
|
command_id: command_id});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -695,7 +731,10 @@ MarionetteDriverActor.prototype = {
|
||||||
let marionette = new Marionette(this, curWindow, "chrome",
|
let marionette = new Marionette(this, curWindow, "chrome",
|
||||||
this.marionetteLog, this.marionettePerf,
|
this.marionetteLog, this.marionettePerf,
|
||||||
this.scriptTimeout, this.testName);
|
this.scriptTimeout, this.testName);
|
||||||
let _chromeSandbox = this.createExecuteSandbox(curWindow, marionette, aRequest.args, aRequest.specialPowers);
|
let _chromeSandbox = this.createExecuteSandbox(curWindow,
|
||||||
|
marionette,
|
||||||
|
aRequest.args,
|
||||||
|
aRequest.specialPowers);
|
||||||
if (!_chromeSandbox)
|
if (!_chromeSandbox)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -714,10 +753,11 @@ MarionetteDriverActor.prototype = {
|
||||||
"};" +
|
"};" +
|
||||||
"func.apply(null, __marionetteParams);";
|
"func.apply(null, __marionetteParams);";
|
||||||
}
|
}
|
||||||
this.executeScriptInSandbox(_chromeSandbox, script, directInject, false);
|
this.executeScriptInSandbox(_chromeSandbox, script, directInject,
|
||||||
|
false, command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
this.sendError(e.name + ': ' + e.message, 17, e.stack);
|
this.sendError(e.name + ': ' + e.message, 17, e.stack, command_id);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -728,13 +768,14 @@ MarionetteDriverActor.prototype = {
|
||||||
* 'value' member is time in milliseconds to set timeout
|
* 'value' member is time in milliseconds to set timeout
|
||||||
*/
|
*/
|
||||||
setScriptTimeout: function MDA_setScriptTimeout(aRequest) {
|
setScriptTimeout: function MDA_setScriptTimeout(aRequest) {
|
||||||
|
this.command_id = this.getCommandId();
|
||||||
let timeout = parseInt(aRequest.value);
|
let timeout = parseInt(aRequest.value);
|
||||||
if(isNaN(timeout)){
|
if(isNaN(timeout)){
|
||||||
this.sendError("Not a Number", 500, null);
|
this.sendError("Not a Number", 500, null, this.command_id);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.scriptTimeout = timeout;
|
this.scriptTimeout = timeout;
|
||||||
this.sendOk();
|
this.sendOk(this.command_id);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -747,6 +788,7 @@ MarionetteDriverActor.prototype = {
|
||||||
* 'timeout' member will be used as the script timeout if it is given
|
* 'timeout' member will be used as the script timeout if it is given
|
||||||
*/
|
*/
|
||||||
executeJSScript: function MDA_executeJSScript(aRequest) {
|
executeJSScript: function MDA_executeJSScript(aRequest) {
|
||||||
|
let command_id = this.command_id = this.getCommandId();
|
||||||
//all pure JS scripts will need to call Marionette.finish() to complete the test.
|
//all pure JS scripts will need to call Marionette.finish() to complete the test.
|
||||||
if (aRequest.newSandbox == undefined) {
|
if (aRequest.newSandbox == undefined) {
|
||||||
//if client does not send a value in newSandbox,
|
//if client does not send a value in newSandbox,
|
||||||
|
@ -766,7 +808,8 @@ MarionetteDriverActor.prototype = {
|
||||||
args: aRequest.args,
|
args: aRequest.args,
|
||||||
newSandbox: aRequest.newSandbox,
|
newSandbox: aRequest.newSandbox,
|
||||||
async: aRequest.async,
|
async: aRequest.async,
|
||||||
timeout: this.scriptTimeout });
|
timeout: this.scriptTimeout,
|
||||||
|
command_id: command_id });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -786,19 +829,20 @@ MarionetteDriverActor.prototype = {
|
||||||
* function body
|
* function body
|
||||||
*/
|
*/
|
||||||
executeWithCallback: function MDA_executeWithCallback(aRequest, directInject) {
|
executeWithCallback: function MDA_executeWithCallback(aRequest, directInject) {
|
||||||
|
let command_id = this.command_id = this.getCommandId();
|
||||||
if (aRequest.newSandbox == undefined) {
|
if (aRequest.newSandbox == undefined) {
|
||||||
//if client does not send a value in newSandbox,
|
//if client does not send a value in newSandbox,
|
||||||
//then they expect the same behaviour as webdriver
|
//then they expect the same behaviour as webdriver
|
||||||
aRequest.newSandbox = true;
|
aRequest.newSandbox = true;
|
||||||
}
|
}
|
||||||
this.command_id = this.uuidGen.generateUUID().toString();
|
|
||||||
|
|
||||||
if (this.context == "content") {
|
if (this.context == "content") {
|
||||||
this.sendAsync("executeAsyncScript", {value: aRequest.value,
|
this.sendAsync("executeAsyncScript", {value: aRequest.value,
|
||||||
args: aRequest.args,
|
args: aRequest.args,
|
||||||
id: this.command_id,
|
id: this.command_id,
|
||||||
newSandbox: aRequest.newSandbox,
|
newSandbox: aRequest.newSandbox,
|
||||||
timeout: this.scriptTimeout});
|
timeout: this.scriptTimeout,
|
||||||
|
command_id: command_id});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -875,7 +919,8 @@ MarionetteDriverActor.prototype = {
|
||||||
+ '__marionetteFunc.apply(null, __marionetteParams);';
|
+ '__marionetteFunc.apply(null, __marionetteParams);';
|
||||||
}
|
}
|
||||||
|
|
||||||
this.executeScriptInSandbox(_chromeSandbox, script, directInject, true);
|
this.executeScriptInSandbox(_chromeSandbox, script, directInject,
|
||||||
|
true, command_id);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
chromeAsyncReturnFunc(e.name + ": " + e.message, 17);
|
chromeAsyncReturnFunc(e.name + ": " + e.message, 17);
|
||||||
}
|
}
|
||||||
|
@ -888,7 +933,9 @@ MarionetteDriverActor.prototype = {
|
||||||
* 'value' member holds the url to navigate to
|
* 'value' member holds the url to navigate to
|
||||||
*/
|
*/
|
||||||
goUrl: function MDA_goUrl(aRequest) {
|
goUrl: function MDA_goUrl(aRequest) {
|
||||||
|
let command_id = this.command_id = this.getCommandId();
|
||||||
if (this.context != "chrome") {
|
if (this.context != "chrome") {
|
||||||
|
aRequest.command_id = command_id;
|
||||||
this.sendAsync("goUrl", aRequest);
|
this.sendAsync("goUrl", aRequest);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -897,7 +944,7 @@ MarionetteDriverActor.prototype = {
|
||||||
let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||||
function checkLoad() {
|
function checkLoad() {
|
||||||
if (curWindow.document.readyState == "complete") {
|
if (curWindow.document.readyState == "complete") {
|
||||||
sendOk();
|
sendOk(command_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
|
checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||||
|
@ -909,11 +956,12 @@ MarionetteDriverActor.prototype = {
|
||||||
* Gets current url
|
* Gets current url
|
||||||
*/
|
*/
|
||||||
getUrl: function MDA_getUrl() {
|
getUrl: function MDA_getUrl() {
|
||||||
|
this.command_id = this.getCommandId();
|
||||||
if (this.context == "chrome") {
|
if (this.context == "chrome") {
|
||||||
this.sendResponse(this.getCurrentWindow().location.href);
|
this.sendResponse(this.getCurrentWindow().location.href, this.command_id);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.sendAsync("getUrl", {});
|
this.sendAsync("getUrl", {command_id: this.command_id});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -921,21 +969,23 @@ MarionetteDriverActor.prototype = {
|
||||||
* Gets the current title of the window
|
* Gets the current title of the window
|
||||||
*/
|
*/
|
||||||
getTitle: function MDA_getTitle() {
|
getTitle: function MDA_getTitle() {
|
||||||
this.sendAsync("getTitle", {});
|
this.command_id = this.getCommandId();
|
||||||
|
this.sendAsync("getTitle", {command_id: this.command_id});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the page source of the content document
|
* Gets the page source of the content document
|
||||||
*/
|
*/
|
||||||
getPageSource: function MDA_getPageSource(){
|
getPageSource: function MDA_getPageSource(){
|
||||||
|
this.command_id = this.getCommandId();
|
||||||
if (this.context == "chrome"){
|
if (this.context == "chrome"){
|
||||||
var curWindow = this.getCurrentWindow();
|
var curWindow = this.getCurrentWindow();
|
||||||
var XMLSerializer = curWindow.XMLSerializer;
|
var XMLSerializer = curWindow.XMLSerializer;
|
||||||
var pageSource = new XMLSerializer().serializeToString(curWindow.document);
|
var pageSource = new XMLSerializer().serializeToString(curWindow.document);
|
||||||
this.sendResponse(pageSource);
|
this.sendResponse(pageSource, this.command_id);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.sendAsync("getPageSource", {});
|
this.sendAsync("getPageSource", {command_id: this.command_id});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -943,30 +993,34 @@ MarionetteDriverActor.prototype = {
|
||||||
* Go back in history
|
* Go back in history
|
||||||
*/
|
*/
|
||||||
goBack: function MDA_goBack() {
|
goBack: function MDA_goBack() {
|
||||||
this.sendAsync("goBack", {});
|
this.command_id = this.getCommandId();
|
||||||
|
this.sendAsync("goBack", {command_id: this.command_id});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Go forward in history
|
* Go forward in history
|
||||||
*/
|
*/
|
||||||
goForward: function MDA_goForward() {
|
goForward: function MDA_goForward() {
|
||||||
this.sendAsync("goForward", {});
|
this.command_id = this.getCommandId();
|
||||||
|
this.sendAsync("goForward", {command_id: this.command_id});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh the page
|
* Refresh the page
|
||||||
*/
|
*/
|
||||||
refresh: function MDA_refresh() {
|
refresh: function MDA_refresh() {
|
||||||
this.sendAsync("refresh", {});
|
this.command_id = this.getCommandId();
|
||||||
|
this.sendAsync("refresh", {command_id: this.command_id});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current window's server-assigned ID
|
* Get the current window's server-assigned ID
|
||||||
*/
|
*/
|
||||||
getWindow: function MDA_getWindow() {
|
getWindow: function MDA_getWindow() {
|
||||||
|
this.command_id = this.getCommandId();
|
||||||
for (let i in this.browsers) {
|
for (let i in this.browsers) {
|
||||||
if (this.curBrowser == this.browsers[i]) {
|
if (this.curBrowser == this.browsers[i]) {
|
||||||
this.sendResponse(i);
|
this.sendResponse(i, this.command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -975,6 +1029,7 @@ MarionetteDriverActor.prototype = {
|
||||||
* Get the server-assigned IDs of all available windows
|
* Get the server-assigned IDs of all available windows
|
||||||
*/
|
*/
|
||||||
getWindows: function MDA_getWindows() {
|
getWindows: function MDA_getWindows() {
|
||||||
|
this.command_id = this.getCommandId();
|
||||||
let res = [];
|
let res = [];
|
||||||
let winEn = this.getWinEnumerator();
|
let winEn = this.getWinEnumerator();
|
||||||
while(winEn.hasMoreElements()) {
|
while(winEn.hasMoreElements()) {
|
||||||
|
@ -983,7 +1038,7 @@ MarionetteDriverActor.prototype = {
|
||||||
winId = winId + ((appName == "B2G") ? '-b2g' : '');
|
winId = winId + ((appName == "B2G") ? '-b2g' : '');
|
||||||
res.push(winId)
|
res.push(winId)
|
||||||
}
|
}
|
||||||
this.sendResponse(res);
|
this.sendResponse(res, this.command_id);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -994,6 +1049,7 @@ MarionetteDriverActor.prototype = {
|
||||||
* 'value' member holds the name or id of the window to switch to
|
* 'value' member holds the name or id of the window to switch to
|
||||||
*/
|
*/
|
||||||
switchToWindow: function MDA_switchToWindow(aRequest) {
|
switchToWindow: function MDA_switchToWindow(aRequest) {
|
||||||
|
let command_id = this.command_id = this.getCommandId();
|
||||||
let winEn = this.getWinEnumerator();
|
let winEn = this.getWinEnumerator();
|
||||||
while(winEn.hasMoreElements()) {
|
while(winEn.hasMoreElements()) {
|
||||||
let foundWin = winEn.getNext();
|
let foundWin = winEn.getNext();
|
||||||
|
@ -1010,11 +1066,12 @@ MarionetteDriverActor.prototype = {
|
||||||
utils.window = foundWin;
|
utils.window = foundWin;
|
||||||
this.curBrowser = this.browsers[winId];
|
this.curBrowser = this.browsers[winId];
|
||||||
}
|
}
|
||||||
this.sendOk();
|
this.sendOk(command_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.sendError("Unable to locate window " + aRequest.value, 23, null);
|
this.sendError("Unable to locate window " + aRequest.value, 23, null,
|
||||||
|
command_id);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1027,15 +1084,17 @@ MarionetteDriverActor.prototype = {
|
||||||
* of the frame to switch to
|
* of the frame to switch to
|
||||||
*/
|
*/
|
||||||
switchToFrame: function MDA_switchToFrame(aRequest) {
|
switchToFrame: function MDA_switchToFrame(aRequest) {
|
||||||
|
let command_id = this.command_id = this.getCommandId();
|
||||||
|
this.logRequest("switchToFrame", aRequest);
|
||||||
let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||||
let checkLoad = function() {
|
let checkLoad = function() {
|
||||||
let errorRegex = /about:.+(error)|(blocked)\?/;
|
let errorRegex = /about:.+(error)|(blocked)\?/;
|
||||||
if (curWindow.document.readyState == "complete") {
|
if (curWindow.document.readyState == "complete") {
|
||||||
this.sendOk();
|
this.sendOk(command_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (curWindow.document.readyState == "interactive" && errorRegex.exec(curWindow.document.baseURI)) {
|
else if (curWindow.document.readyState == "interactive" && errorRegex.exec(curWindow.document.baseURI)) {
|
||||||
this.sendError("Error loading page", 13, null);
|
this.sendError("Error loading page", 13, null, command_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1096,7 +1155,8 @@ MarionetteDriverActor.prototype = {
|
||||||
this.curFrame.focus();
|
this.curFrame.focus();
|
||||||
checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
|
checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||||
} else {
|
} else {
|
||||||
this.sendError("Unable to locate frame: " + aRequest.value, 8, null);
|
this.sendError("Unable to locate frame: " + aRequest.value, 8, null,
|
||||||
|
command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1108,6 +1168,7 @@ MarionetteDriverActor.prototype = {
|
||||||
// we send the message to the right listener.
|
// we send the message to the right listener.
|
||||||
this.switchToGlobalMessageManager();
|
this.switchToGlobalMessageManager();
|
||||||
}
|
}
|
||||||
|
aRequest.command_id = command_id;
|
||||||
this.sendAsync("switchToFrame", aRequest);
|
this.sendAsync("switchToFrame", aRequest);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1119,17 +1180,19 @@ MarionetteDriverActor.prototype = {
|
||||||
* 'value' holds the search timeout in milliseconds
|
* 'value' holds the search timeout in milliseconds
|
||||||
*/
|
*/
|
||||||
setSearchTimeout: function MDA_setSearchTimeout(aRequest) {
|
setSearchTimeout: function MDA_setSearchTimeout(aRequest) {
|
||||||
|
this.command_id = this.getCommandId();
|
||||||
if (this.context == "chrome") {
|
if (this.context == "chrome") {
|
||||||
try {
|
try {
|
||||||
this.curBrowser.elementManager.setSearchTimeout(aRequest.value);
|
this.curBrowser.elementManager.setSearchTimeout(aRequest.value);
|
||||||
this.sendOk();
|
this.sendOk(this.command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
this.sendError(e.message, e.code, e.stack);
|
this.sendError(e.message, e.code, e.stack, this.command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.sendAsync("setSearchTimeout", {value: aRequest.value});
|
this.sendAsync("setSearchTimeout", {value: aRequest.value,
|
||||||
|
command_id: this.command_id});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1141,20 +1204,30 @@ MarionetteDriverActor.prototype = {
|
||||||
* 'value' member is the value the client is looking for
|
* 'value' member is the value the client is looking for
|
||||||
*/
|
*/
|
||||||
findElement: function MDA_findElement(aRequest) {
|
findElement: function MDA_findElement(aRequest) {
|
||||||
|
let command_id = this.command_id = this.getCommandId();
|
||||||
if (this.context == "chrome") {
|
if (this.context == "chrome") {
|
||||||
let id;
|
let id;
|
||||||
try {
|
try {
|
||||||
let on_success = this.sendResponse.bind(this);
|
let on_success = this.sendResponse.bind(this);
|
||||||
let on_error = this.sendError.bind(this);
|
let on_error = this.sendError.bind(this);
|
||||||
id = this.curBrowser.elementManager.find(this.getCurrentWindow(),aRequest, on_success, on_error, false);
|
id = this.curBrowser.elementManager.find(
|
||||||
|
this.getCurrentWindow(),
|
||||||
|
aRequest,
|
||||||
|
on_success,
|
||||||
|
on_error,
|
||||||
|
false,
|
||||||
|
command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
this.sendError(e.message, e.code, e.stack);
|
this.sendError(e.message, e.code, e.stack, command_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.sendAsync("findElementContent", {value: aRequest.value, using: aRequest.using, element: aRequest.element});
|
this.sendAsync("findElementContent", {value: aRequest.value,
|
||||||
|
using: aRequest.using,
|
||||||
|
element: aRequest.element,
|
||||||
|
command_id: command_id});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1166,20 +1239,29 @@ MarionetteDriverActor.prototype = {
|
||||||
* 'value' member is the value the client is looking for
|
* 'value' member is the value the client is looking for
|
||||||
*/
|
*/
|
||||||
findElements: function MDA_findElements(aRequest) {
|
findElements: function MDA_findElements(aRequest) {
|
||||||
|
let command_id = this.command_id = this.getCommandId();
|
||||||
if (this.context == "chrome") {
|
if (this.context == "chrome") {
|
||||||
let id;
|
let id;
|
||||||
try {
|
try {
|
||||||
let on_success = this.sendResponse.bind(this);
|
let on_success = this.sendResponse.bind(this);
|
||||||
let on_error = this.sendError.bind(this);
|
let on_error = this.sendError.bind(this);
|
||||||
id = this.curBrowser.elementManager.find(this.getCurrentWindow(), aRequest, on_success, on_error, true);
|
id = this.curBrowser.elementManager.find(this.getCurrentWindow(),
|
||||||
|
aRequest,
|
||||||
|
on_success,
|
||||||
|
on_error,
|
||||||
|
true,
|
||||||
|
command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
this.sendError(e.message, e.code, e.stack);
|
this.sendError(e.message, e.code, e.stack, command_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.sendAsync("findElementsContent", {value: aRequest.value, using: aRequest.using, element: aRequest.element});
|
this.sendAsync("findElementsContent", {value: aRequest.value,
|
||||||
|
using: aRequest.using,
|
||||||
|
element: aRequest.element,
|
||||||
|
command_id: command_id});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1191,19 +1273,22 @@ MarionetteDriverActor.prototype = {
|
||||||
* the element that will be clicked
|
* the element that will be clicked
|
||||||
*/
|
*/
|
||||||
clickElement: function MDA_clickElement(aRequest) {
|
clickElement: function MDA_clickElement(aRequest) {
|
||||||
|
let command_id = this.command_id = this.getCommandId();
|
||||||
if (this.context == "chrome") {
|
if (this.context == "chrome") {
|
||||||
try {
|
try {
|
||||||
//NOTE: click atom fails, fall back to click() action
|
//NOTE: click atom fails, fall back to click() action
|
||||||
let el = this.curBrowser.elementManager.getKnownElement(aRequest.element, this.getCurrentWindow());
|
let el = this.curBrowser.elementManager.getKnownElement(
|
||||||
|
aRequest.element, this.getCurrentWindow());
|
||||||
el.click();
|
el.click();
|
||||||
this.sendOk();
|
this.sendOk(command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
this.sendError(e.message, e.code, e.stack);
|
this.sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.sendAsync("clickElement", {element: aRequest.element});
|
this.sendAsync("clickElement", {element: aRequest.element,
|
||||||
|
command_id: command_id});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1216,17 +1301,22 @@ MarionetteDriverActor.prototype = {
|
||||||
* 'name' member holds the name of the attribute to retrieve
|
* 'name' member holds the name of the attribute to retrieve
|
||||||
*/
|
*/
|
||||||
getElementAttribute: function MDA_getElementAttribute(aRequest) {
|
getElementAttribute: function MDA_getElementAttribute(aRequest) {
|
||||||
|
let command_id = this.command_id = this.getCommandId();
|
||||||
if (this.context == "chrome") {
|
if (this.context == "chrome") {
|
||||||
try {
|
try {
|
||||||
let el = this.curBrowser.elementManager.getKnownElement(aRequest.element, this.getCurrentWindow());
|
let el = this.curBrowser.elementManager.getKnownElement(
|
||||||
this.sendResponse(utils.getElementAttribute(el, aRequest.name));
|
aRequest.element, this.getCurrentWindow());
|
||||||
|
this.sendResponse(utils.getElementAttribute(el, aRequest.name),
|
||||||
|
command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
this.sendError(e.message, e.code, e.stack);
|
this.sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.sendAsync("getElementAttribute", {element: aRequest.element, name: aRequest.name});
|
this.sendAsync("getElementAttribute", {element: aRequest.element,
|
||||||
|
name: aRequest.name,
|
||||||
|
command_id: command_id});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1238,21 +1328,24 @@ MarionetteDriverActor.prototype = {
|
||||||
* the element that will be inspected
|
* the element that will be inspected
|
||||||
*/
|
*/
|
||||||
getElementText: function MDA_getElementText(aRequest) {
|
getElementText: function MDA_getElementText(aRequest) {
|
||||||
|
let command_id = this.command_id = this.getCommandId();
|
||||||
if (this.context == "chrome") {
|
if (this.context == "chrome") {
|
||||||
//Note: for chrome, we look at text nodes, and any node with a "label" field
|
//Note: for chrome, we look at text nodes, and any node with a "label" field
|
||||||
try {
|
try {
|
||||||
let el = this.curBrowser.elementManager.getKnownElement(aRequest.element, this.getCurrentWindow());
|
let el = this.curBrowser.elementManager.getKnownElement(
|
||||||
|
aRequest.element, this.getCurrentWindow());
|
||||||
let lines = [];
|
let lines = [];
|
||||||
this.getVisibleText(el, lines);
|
this.getVisibleText(el, lines);
|
||||||
lines = lines.join("\n");
|
lines = lines.join("\n");
|
||||||
this.sendResponse(lines);
|
this.sendResponse(lines, command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
this.sendError(e.message, e.code, e.stack);
|
this.sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.sendAsync("getElementText", {element: aRequest.element});
|
this.sendAsync("getElementText", {element: aRequest.element,
|
||||||
|
command_id: command_id});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1264,17 +1357,20 @@ MarionetteDriverActor.prototype = {
|
||||||
* the element that will be inspected
|
* the element that will be inspected
|
||||||
*/
|
*/
|
||||||
getElementTagName: function MDA_getElementTagName(aRequest) {
|
getElementTagName: function MDA_getElementTagName(aRequest) {
|
||||||
|
let command_id = this.command_id = this.getCommandId();
|
||||||
if (this.context == "chrome") {
|
if (this.context == "chrome") {
|
||||||
try {
|
try {
|
||||||
let el = this.curBrowser.elementManager.getKnownElement(aRequest.element, this.getCurrentWindow());
|
let el = this.curBrowser.elementManager.getKnownElement(
|
||||||
this.sendResponse(el.tagName.toLowerCase());
|
aRequest.element, this.getCurrentWindow());
|
||||||
|
this.sendResponse(el.tagName.toLowerCase(), command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
this.sendError(e.message, e.code, e.stack);
|
this.sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.sendAsync("getElementTagName", {element: aRequest.element});
|
this.sendAsync("getElementTagName", {element: aRequest.element,
|
||||||
|
command_id: command_id});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1286,17 +1382,20 @@ MarionetteDriverActor.prototype = {
|
||||||
* the element that will be checked
|
* the element that will be checked
|
||||||
*/
|
*/
|
||||||
isElementDisplayed: function MDA_isElementDisplayed(aRequest) {
|
isElementDisplayed: function MDA_isElementDisplayed(aRequest) {
|
||||||
|
let command_id = this.command_id = this.getCommandId();
|
||||||
if (this.context == "chrome") {
|
if (this.context == "chrome") {
|
||||||
try {
|
try {
|
||||||
let el = this.curBrowser.elementManager.getKnownElement(aRequest.element, this.getCurrentWindow());
|
let el = this.curBrowser.elementManager.getKnownElement(
|
||||||
this.sendResponse(utils.isElementDisplayed(el));
|
aRequest.element, this.getCurrentWindow());
|
||||||
|
this.sendResponse(utils.isElementDisplayed(el), command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
this.sendError(e.message, e.code, e.stack);
|
this.sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.sendAsync("isElementDisplayed", {element:aRequest.element});
|
this.sendAsync("isElementDisplayed", {element:aRequest.element,
|
||||||
|
command_id: command_id});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1308,23 +1407,26 @@ MarionetteDriverActor.prototype = {
|
||||||
* the element that will be checked
|
* the element that will be checked
|
||||||
*/
|
*/
|
||||||
isElementEnabled: function MDA_isElementEnabled(aRequest) {
|
isElementEnabled: function MDA_isElementEnabled(aRequest) {
|
||||||
|
let command_id = this.command_id = this.getCommandId();
|
||||||
if (this.context == "chrome") {
|
if (this.context == "chrome") {
|
||||||
try {
|
try {
|
||||||
//Selenium atom doesn't quite work here
|
//Selenium atom doesn't quite work here
|
||||||
let el = this.curBrowser.elementManager.getKnownElement(aRequest.element, this.getCurrentWindow());
|
let el = this.curBrowser.elementManager.getKnownElement(
|
||||||
|
aRequest.element, this.getCurrentWindow());
|
||||||
if (el.disabled != undefined) {
|
if (el.disabled != undefined) {
|
||||||
this.sendResponse(!!!el.disabled);
|
this.sendResponse(!!!el.disabled, command_id);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.sendResponse(true);
|
this.sendResponse(true, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
this.sendError(e.message, e.code, e.stack);
|
this.sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.sendAsync("isElementEnabled", {element:aRequest.element});
|
this.sendAsync("isElementEnabled", {element:aRequest.element,
|
||||||
|
command_id: command_id});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1336,42 +1438,49 @@ MarionetteDriverActor.prototype = {
|
||||||
* the element that will be checked
|
* the element that will be checked
|
||||||
*/
|
*/
|
||||||
isElementSelected: function MDA_isElementSelected(aRequest) {
|
isElementSelected: function MDA_isElementSelected(aRequest) {
|
||||||
|
let command_id = this.command_id = this.getCommandId();
|
||||||
if (this.context == "chrome") {
|
if (this.context == "chrome") {
|
||||||
try {
|
try {
|
||||||
//Selenium atom doesn't quite work here
|
//Selenium atom doesn't quite work here
|
||||||
let el = this.curBrowser.elementManager.getKnownElement(aRequest.element, this.getCurrentWindow());
|
let el = this.curBrowser.elementManager.getKnownElement(
|
||||||
|
aRequest.element, this.getCurrentWindow());
|
||||||
if (el.checked != undefined) {
|
if (el.checked != undefined) {
|
||||||
this.sendResponse(!!el.checked);
|
this.sendResponse(!!el.checked, command_id);
|
||||||
}
|
}
|
||||||
else if (el.selected != undefined) {
|
else if (el.selected != undefined) {
|
||||||
this.sendResponse(!!el.selected);
|
this.sendResponse(!!el.selected, command_id);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.sendResponse(true);
|
this.sendResponse(true, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
this.sendError(e.message, e.code, e.stack);
|
this.sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.sendAsync("isElementSelected", {element:aRequest.element});
|
this.sendAsync("isElementSelected", {element:aRequest.element,
|
||||||
|
command_id: command_id});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getElementSize: function MDA_getElementSize(aRequest) {
|
getElementSize: function MDA_getElementSize(aRequest) {
|
||||||
|
let command_id = this.command_id = this.getCommandId();
|
||||||
if (this.context == "chrome") {
|
if (this.context == "chrome") {
|
||||||
try {
|
try {
|
||||||
let el = this.curBrowser.elementManager.getKnownElement(aRequest.element, this.getCurrentWindow());
|
let el = this.curBrowser.elementManager.getKnownElement(
|
||||||
|
aRequest.element, this.getCurrentWindow());
|
||||||
let clientRect = el.getBoundingClientRect();
|
let clientRect = el.getBoundingClientRect();
|
||||||
this.sendResponse({width: clientRect.width, height: clientRect.height});
|
this.sendResponse({width: clientRect.width, height: clientRect.height},
|
||||||
|
command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
this.sendError(e.message, e.code, e.stack);
|
this.sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.sendAsync("getElementSize", {element:aRequest.element});
|
this.sendAsync("getElementSize", {element:aRequest.element,
|
||||||
|
command_id: command_id});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1384,19 +1493,23 @@ MarionetteDriverActor.prototype = {
|
||||||
* 'value' member holds the value to send to the element
|
* 'value' member holds the value to send to the element
|
||||||
*/
|
*/
|
||||||
sendKeysToElement: function MDA_sendKeysToElement(aRequest) {
|
sendKeysToElement: function MDA_sendKeysToElement(aRequest) {
|
||||||
|
let command_id = this.command_id = this.getCommandId();
|
||||||
if (this.context == "chrome") {
|
if (this.context == "chrome") {
|
||||||
try {
|
try {
|
||||||
let el = this.curBrowser.elementManager.getKnownElement(aRequest.element, this.getCurrentWindow());
|
let el = this.curBrowser.elementManager.getKnownElement(
|
||||||
|
aRequest.element, this.getCurrentWindow());
|
||||||
el.focus();
|
el.focus();
|
||||||
utils.sendString(aRequest.value.join(""), utils.window);
|
utils.sendString(aRequest.value.join(""), utils.window);
|
||||||
this.sendOk();
|
this.sendOk(command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
this.sendError(e.message, e.code, e.stack);
|
this.sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.sendAsync("sendKeysToElement", {element:aRequest.element, value: aRequest.value});
|
this.sendAsync("sendKeysToElement", {element:aRequest.element,
|
||||||
|
value: aRequest.value,
|
||||||
|
command_id: command_id});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1406,8 +1519,11 @@ MarionetteDriverActor.prototype = {
|
||||||
* The test name is used in logging messages.
|
* The test name is used in logging messages.
|
||||||
*/
|
*/
|
||||||
setTestName: function MDA_setTestName(aRequest) {
|
setTestName: function MDA_setTestName(aRequest) {
|
||||||
|
this.command_id = this.getCommandId();
|
||||||
|
this.logRequest("setTestName", aRequest);
|
||||||
this.testName = aRequest.value;
|
this.testName = aRequest.value;
|
||||||
this.sendAsync("setTestName", {value: aRequest.value});
|
this.sendAsync("setTestName", {value: aRequest.value,
|
||||||
|
command_id: this.command_id});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1418,29 +1534,34 @@ MarionetteDriverActor.prototype = {
|
||||||
* the element that will be cleared
|
* the element that will be cleared
|
||||||
*/
|
*/
|
||||||
clearElement: function MDA_clearElement(aRequest) {
|
clearElement: function MDA_clearElement(aRequest) {
|
||||||
|
let command_id = this.command_id = this.getCommandId();
|
||||||
if (this.context == "chrome") {
|
if (this.context == "chrome") {
|
||||||
//the selenium atom doesn't work here
|
//the selenium atom doesn't work here
|
||||||
try {
|
try {
|
||||||
let el = this.curBrowser.elementManager.getKnownElement(aRequest.element, this.getCurrentWindow());
|
let el = this.curBrowser.elementManager.getKnownElement(
|
||||||
|
aRequest.element, this.getCurrentWindow());
|
||||||
if (el.nodeName == "textbox") {
|
if (el.nodeName == "textbox") {
|
||||||
el.value = "";
|
el.value = "";
|
||||||
}
|
}
|
||||||
else if (el.nodeName == "checkbox") {
|
else if (el.nodeName == "checkbox") {
|
||||||
el.checked = false;
|
el.checked = false;
|
||||||
}
|
}
|
||||||
this.sendOk();
|
this.sendOk(command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
this.sendError(e.message, e.code, e.stack);
|
this.sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.sendAsync("clearElement", {element:aRequest.element});
|
this.sendAsync("clearElement", {element:aRequest.element,
|
||||||
|
command_id: command_id});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getElementPosition: function MDA_getElementPosition(aRequest) {
|
getElementPosition: function MDA_getElementPosition(aRequest) {
|
||||||
this.sendAsync("getElementPosition", {element:aRequest.element});
|
this.command_id = this.getCommandId();
|
||||||
|
this.sendAsync("getElementPosition", {element:aRequest.element,
|
||||||
|
command_id: this.command_id});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1452,9 +1573,10 @@ MarionetteDriverActor.prototype = {
|
||||||
* 1 then it deletes the session otherwise it closes the window
|
* 1 then it deletes the session otherwise it closes the window
|
||||||
*/
|
*/
|
||||||
closeWindow: function MDA_closeWindow() {
|
closeWindow: function MDA_closeWindow() {
|
||||||
|
let command_id = this.command_id = this.getCommandId();
|
||||||
if (appName == "B2G") {
|
if (appName == "B2G") {
|
||||||
// We can't close windows so just return
|
// We can't close windows so just return
|
||||||
this.sendOk();
|
this.sendOk(command_id);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Get the total number of windows
|
// Get the total number of windows
|
||||||
|
@ -1474,10 +1596,11 @@ MarionetteDriverActor.prototype = {
|
||||||
try{
|
try{
|
||||||
this.messageManager.removeDelayedFrameScript(FRAME_SCRIPT);
|
this.messageManager.removeDelayedFrameScript(FRAME_SCRIPT);
|
||||||
this.getCurrentWindow().close();
|
this.getCurrentWindow().close();
|
||||||
this.sendOk();
|
this.sendOk(command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
this.sendError("Could not close window: " + e.message, 13, e.stack);
|
this.sendError("Could not close window: " + e.message, 13, e.stack,
|
||||||
|
command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1492,10 +1615,13 @@ MarionetteDriverActor.prototype = {
|
||||||
* and can safely be reused.
|
* and can safely be reused.
|
||||||
*/
|
*/
|
||||||
deleteSession: function MDA_deleteSession() {
|
deleteSession: function MDA_deleteSession() {
|
||||||
|
let command_id = this.command_id = this.getCommandId();
|
||||||
if (this.curBrowser != null) {
|
if (this.curBrowser != null) {
|
||||||
if (appName == "B2G") {
|
if (appName == "B2G") {
|
||||||
this.globalMessageManager.broadcastAsyncMessage("Marionette:sleepSession" + this.curBrowser.mainContentId, {});
|
this.globalMessageManager.broadcastAsyncMessage(
|
||||||
this.curBrowser.knownFrames.splice(this.curBrowser.knownFrames.indexOf(this.curBrowser.mainContentId), 1);
|
"Marionette:sleepSession" + this.curBrowser.mainContentId, {});
|
||||||
|
this.curBrowser.knownFrames.splice(
|
||||||
|
this.curBrowser.knownFrames.indexOf(this.curBrowser.mainContentId), 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//don't set this pref for B2G since the framescript can be safely reused
|
//don't set this pref for B2G since the framescript can be safely reused
|
||||||
|
@ -1513,7 +1639,7 @@ MarionetteDriverActor.prototype = {
|
||||||
winEnum.getNext().messageManager.removeDelayedFrameScript(FRAME_SCRIPT);
|
winEnum.getNext().messageManager.removeDelayedFrameScript(FRAME_SCRIPT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.sendOk();
|
this.sendOk(command_id);
|
||||||
this.removeMessageManagerListeners(this.globalMessageManager);
|
this.removeMessageManagerListeners(this.globalMessageManager);
|
||||||
this.switchToGlobalMessageManager();
|
this.switchToGlobalMessageManager();
|
||||||
// reset frame to the top-most frame
|
// reset frame to the top-most frame
|
||||||
|
@ -1533,7 +1659,8 @@ MarionetteDriverActor.prototype = {
|
||||||
* Returns the current status of the Application Cache
|
* Returns the current status of the Application Cache
|
||||||
*/
|
*/
|
||||||
getAppCacheStatus: function MDA_getAppCacheStatus(aRequest) {
|
getAppCacheStatus: function MDA_getAppCacheStatus(aRequest) {
|
||||||
this.sendAsync("getAppCacheStatus");
|
this.command_id = this.getCommandId();
|
||||||
|
this.sendAsync("getAppCacheStatus", {command_id: this.command_id});
|
||||||
},
|
},
|
||||||
|
|
||||||
_emu_cb_id: 0,
|
_emu_cb_id: 0,
|
||||||
|
@ -1574,23 +1701,28 @@ MarionetteDriverActor.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
importScript: function MDA_importScript(aRequest) {
|
importScript: function MDA_importScript(aRequest) {
|
||||||
|
let command_id = this.command_id = this.getCommandId();
|
||||||
if (this.context == "chrome") {
|
if (this.context == "chrome") {
|
||||||
let file;
|
let file;
|
||||||
if (this.importedScripts.exists()) {
|
if (this.importedScripts.exists()) {
|
||||||
file = FileUtils.openFileOutputStream(this.importedScripts, FileUtils.MODE_APPEND | FileUtils.MODE_WRONLY);
|
file = FileUtils.openFileOutputStream(this.importedScripts,
|
||||||
|
FileUtils.MODE_APPEND | FileUtils.MODE_WRONLY);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//Note: The permission bits here don't actually get set (bug 804563)
|
//Note: The permission bits here don't actually get set (bug 804563)
|
||||||
this.importedScripts.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, parseInt("0666", 8));
|
this.importedScripts.createUnique(
|
||||||
file = FileUtils.openFileOutputStream(this.importedScripts, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE);
|
Components.interfaces.nsIFile.NORMAL_FILE_TYPE, parseInt("0666", 8));
|
||||||
|
file = FileUtils.openFileOutputStream(this.importedScripts,
|
||||||
|
FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE);
|
||||||
this.importedScripts.permissions = parseInt("0666", 8); //actually set permissions
|
this.importedScripts.permissions = parseInt("0666", 8); //actually set permissions
|
||||||
}
|
}
|
||||||
file.write(aRequest.script, aRequest.script.length);
|
file.write(aRequest.script, aRequest.script.length);
|
||||||
file.close();
|
file.close();
|
||||||
this.sendOk();
|
this.sendOk(command_id);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.sendAsync("importScript", {script: aRequest.script});
|
this.sendAsync("importScript", {script: aRequest.script,
|
||||||
|
command_id: command_id});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1661,6 +1793,7 @@ MarionetteDriverActor.prototype = {
|
||||||
let frame = remoteFrames[i];
|
let frame = remoteFrames[i];
|
||||||
if ((frame.messageManager == mm)) {
|
if ((frame.messageManager == mm)) {
|
||||||
this.currentRemoteFrame = frame;
|
this.currentRemoteFrame = frame;
|
||||||
|
this.currentRemoteFrame.command_id = message.json.command_id;
|
||||||
this.messageManager = frame.messageManager;
|
this.messageManager = frame.messageManager;
|
||||||
this.addMessageManagerListeners(this.messageManager);
|
this.addMessageManagerListeners(this.messageManager);
|
||||||
this.messageManager.sendAsyncMessage("Marionette:restart", {});
|
this.messageManager.sendAsyncMessage("Marionette:restart", {});
|
||||||
|
@ -1675,6 +1808,7 @@ MarionetteDriverActor.prototype = {
|
||||||
this.messageManager = mm;
|
this.messageManager = mm;
|
||||||
let aFrame = new MarionetteRemoteFrame(message.json.win, message.json.frame);
|
let aFrame = new MarionetteRemoteFrame(message.json.win, message.json.frame);
|
||||||
aFrame.messageManager = this.messageManager;
|
aFrame.messageManager = this.messageManager;
|
||||||
|
aFrame.command_id = message.json.command_id;
|
||||||
remoteFrames.push(aFrame);
|
remoteFrames.push(aFrame);
|
||||||
this.currentRemoteFrame = aFrame;
|
this.currentRemoteFrame = aFrame;
|
||||||
break;
|
break;
|
||||||
|
@ -1702,7 +1836,8 @@ MarionetteDriverActor.prototype = {
|
||||||
this.sendAsync(
|
this.sendAsync(
|
||||||
"setState",
|
"setState",
|
||||||
{scriptTimeout: this.scriptTimeout,
|
{scriptTimeout: this.scriptTimeout,
|
||||||
searchTimeout: this.curBrowser.elementManager.searchTimeout});
|
searchTimeout: this.curBrowser.elementManager.searchTimeout,
|
||||||
|
command_id: this.currentRemoteFrame.command_id});
|
||||||
}
|
}
|
||||||
|
|
||||||
let browserType;
|
let browserType;
|
||||||
|
|
|
@ -256,7 +256,7 @@ ElementManager.prototype = {
|
||||||
* @return nsIDOMElement or list of nsIDOMElements
|
* @return nsIDOMElement or list of nsIDOMElements
|
||||||
* Returns the element(s) by calling the on_success function.
|
* Returns the element(s) by calling the on_success function.
|
||||||
*/
|
*/
|
||||||
find: function EM_find(win, values, on_success, on_error, all) {
|
find: function EM_find(win, values, on_success, on_error, all, command_id) {
|
||||||
let startTime = values.time ? values.time : new Date().getTime();
|
let startTime = values.time ? values.time : new Date().getTime();
|
||||||
let startNode = (values.element != undefined) ? this.getKnownElement(values.element, win) : win.document;
|
let startNode = (values.element != undefined) ? this.getKnownElement(values.element, win) : win.document;
|
||||||
if (this.elementStrategies.indexOf(values.using) < 0) {
|
if (this.elementStrategies.indexOf(values.using) < 0) {
|
||||||
|
@ -270,19 +270,23 @@ ElementManager.prototype = {
|
||||||
for (let i = 0 ; i < found.length ; i++) {
|
for (let i = 0 ; i < found.length ; i++) {
|
||||||
ids.push(this.addToKnownElements(found[i]));
|
ids.push(this.addToKnownElements(found[i]));
|
||||||
}
|
}
|
||||||
on_success(ids);
|
on_success(ids, command_id);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let id = this.addToKnownElements(found);
|
let id = this.addToKnownElements(found);
|
||||||
on_success(id);
|
on_success(id, command_id);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
if (this.searchTimeout == 0 || new Date().getTime() - startTime > this.searchTimeout) {
|
if (this.searchTimeout == 0 || new Date().getTime() - startTime > this.searchTimeout) {
|
||||||
on_error("Unable to locate element: " + values.value, 7, null);
|
on_error("Unable to locate element: " + values.value, 7, null, command_id);
|
||||||
} else {
|
} else {
|
||||||
values.time = startTime;
|
values.time = startTime;
|
||||||
this.timer.initWithCallback(this.find.bind(this, win, values, on_success, on_error, all), 100, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
|
this.timer.initWithCallback(this.find.bind(this, win, values,
|
||||||
|
on_success, on_error, all,
|
||||||
|
command_id),
|
||||||
|
100,
|
||||||
|
Components.interfaces.nsITimer.TYPE_ONE_SHOT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -61,8 +61,9 @@ let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||||
function registerSelf() {
|
function registerSelf() {
|
||||||
Services.io.manageOfflineStatus = false;
|
Services.io.manageOfflineStatus = false;
|
||||||
Services.io.offline = false;
|
Services.io.offline = false;
|
||||||
let register = sendSyncMessage("Marionette:register", {value: winUtil.outerWindowID, href: content.location.href});
|
let msg = {value: winUtil.outerWindowID, href: content.location.href};
|
||||||
|
let register = sendSyncMessage("Marionette:register", msg);
|
||||||
|
|
||||||
if (register[0]) {
|
if (register[0]) {
|
||||||
listenerId = register[0];
|
listenerId = register[0];
|
||||||
startListeners();
|
startListeners();
|
||||||
|
@ -151,16 +152,16 @@ function setState(msg) {
|
||||||
elementManager.setSearchTimeout(msg.json.searchTimeout);
|
elementManager.setSearchTimeout(msg.json.searchTimeout);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
sendError(e.message, e.code, e.stack);
|
sendError(e.message, e.code, e.stack, msg.json.command_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sendOk();
|
sendOk(msg.json.command_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restarts all our listeners after this listener was put to sleep
|
* Restarts all our listeners after this listener was put to sleep
|
||||||
*/
|
*/
|
||||||
function restart() {
|
function restart(msg) {
|
||||||
removeMessageListener("Marionette:restart", restart);
|
removeMessageListener("Marionette:restart", restart);
|
||||||
registerSelf();
|
registerSelf();
|
||||||
}
|
}
|
||||||
|
@ -322,7 +323,8 @@ function createExecuteContentSandbox(aWindow, timeout) {
|
||||||
500, null, asyncTestCommandId);
|
500, null, asyncTestCommandId);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sendResponse({value: elementManager.wrapValue(value), status: status}, asyncTestCommandId);
|
sendResponse({value: elementManager.wrapValue(value), status: status},
|
||||||
|
asyncTestCommandId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -352,12 +354,13 @@ function createExecuteContentSandbox(aWindow, timeout) {
|
||||||
* or directly (for 'mochitest' like JS Marionette tests)
|
* or directly (for 'mochitest' like JS Marionette tests)
|
||||||
*/
|
*/
|
||||||
function executeScript(msg, directInject) {
|
function executeScript(msg, directInject) {
|
||||||
|
let asyncTestCommandId = msg.json.command_id;
|
||||||
let script = msg.json.value;
|
let script = msg.json.value;
|
||||||
|
|
||||||
if (msg.json.newSandbox || !sandbox) {
|
if (msg.json.newSandbox || !sandbox) {
|
||||||
sandbox = createExecuteContentSandbox(curWindow, msg.json.timeout);
|
sandbox = createExecuteContentSandbox(curWindow, msg.json.timeout);
|
||||||
if (!sandbox) {
|
if (!sandbox) {
|
||||||
sendError("Could not create sandbox!");
|
sendError("Could not create sandbox!", asyncTestCommandId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -377,10 +380,10 @@ function executeScript(msg, directInject) {
|
||||||
marionetteLogObj.clearLogs();
|
marionetteLogObj.clearLogs();
|
||||||
marionettePerf.clearPerfData();
|
marionettePerf.clearPerfData();
|
||||||
if (res == undefined || res.passed == undefined) {
|
if (res == undefined || res.passed == undefined) {
|
||||||
sendError("Marionette.finish() not called", 17, null);
|
sendError("Marionette.finish() not called", 17, null, asyncTestCommandId);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sendResponse({value: elementManager.wrapValue(res)});
|
sendResponse({value: elementManager.wrapValue(res)}, asyncTestCommandId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -389,7 +392,7 @@ function executeScript(msg, directInject) {
|
||||||
msg.json.args, curWindow);
|
msg.json.args, curWindow);
|
||||||
}
|
}
|
||||||
catch(e) {
|
catch(e) {
|
||||||
sendError(e.message, e.code, e.stack);
|
sendError(e.message, e.code, e.stack, asyncTestCommandId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,12 +410,12 @@ function executeScript(msg, directInject) {
|
||||||
perf: elementManager.wrapValue(marionettePerf.getPerfData())});
|
perf: elementManager.wrapValue(marionettePerf.getPerfData())});
|
||||||
marionetteLogObj.clearLogs();
|
marionetteLogObj.clearLogs();
|
||||||
marionettePerf.clearPerfData();
|
marionettePerf.clearPerfData();
|
||||||
sendResponse({value: elementManager.wrapValue(res)});
|
sendResponse({value: elementManager.wrapValue(res)}, asyncTestCommandId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
// 17 = JavascriptException
|
// 17 = JavascriptException
|
||||||
sendError(e.name + ': ' + e.message, 17, e.stack);
|
sendError(e.name + ': ' + e.message, 17, e.stack, asyncTestCommandId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,7 +424,7 @@ function executeScript(msg, directInject) {
|
||||||
*/
|
*/
|
||||||
function setTestName(msg) {
|
function setTestName(msg) {
|
||||||
marionetteTestName = msg.json.value;
|
marionetteTestName = msg.json.value;
|
||||||
sendOk();
|
sendOk(msg.json.command_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -454,7 +457,7 @@ function executeJSScript(msg) {
|
||||||
function executeWithCallback(msg, useFinish) {
|
function executeWithCallback(msg, useFinish) {
|
||||||
curWindow.addEventListener("unload", errUnload, false);
|
curWindow.addEventListener("unload", errUnload, false);
|
||||||
let script = msg.json.value;
|
let script = msg.json.value;
|
||||||
asyncTestCommandId = msg.json.id;
|
let asyncTestCommandId = msg.json.command_id;
|
||||||
|
|
||||||
if (msg.json.newSandbox || !sandbox) {
|
if (msg.json.newSandbox || !sandbox) {
|
||||||
sandbox = createExecuteContentSandbox(curWindow, msg.json.timeout);
|
sandbox = createExecuteContentSandbox(curWindow, msg.json.timeout);
|
||||||
|
@ -463,6 +466,7 @@ function executeWithCallback(msg, useFinish) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sandbox.tag = script;
|
||||||
|
|
||||||
// Error code 28 is scriptTimeout, but spec says execute_async should return 21 (Timeout),
|
// Error code 28 is scriptTimeout, but spec says execute_async should return 21 (Timeout),
|
||||||
// see http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/execute_async.
|
// see http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/execute_async.
|
||||||
|
@ -482,7 +486,7 @@ function executeWithCallback(msg, useFinish) {
|
||||||
let scriptSrc;
|
let scriptSrc;
|
||||||
if (useFinish) {
|
if (useFinish) {
|
||||||
if (msg.json.timeout == null || msg.json.timeout == 0) {
|
if (msg.json.timeout == null || msg.json.timeout == 0) {
|
||||||
sendError("Please set a timeout", 21, null);
|
sendError("Please set a timeout", 21, null, asyncTestCommandId);
|
||||||
}
|
}
|
||||||
scriptSrc = script;
|
scriptSrc = script;
|
||||||
}
|
}
|
||||||
|
@ -492,7 +496,7 @@ function executeWithCallback(msg, useFinish) {
|
||||||
msg.json.args, curWindow);
|
msg.json.args, curWindow);
|
||||||
}
|
}
|
||||||
catch(e) {
|
catch(e) {
|
||||||
sendError(e.message, e.code, e.stack);
|
sendError(e.message, e.code, e.stack, asyncTestCommandId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,10 +529,10 @@ function setSearchTimeout(msg) {
|
||||||
elementManager.setSearchTimeout(msg.json.value);
|
elementManager.setSearchTimeout(msg.json.value);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
sendError(e.message, e.code, e.stack);
|
sendError(e.message, e.code, e.stack, msg.json.command_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sendOk();
|
sendOk(msg.json.command_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -536,6 +540,7 @@ function setSearchTimeout(msg) {
|
||||||
* All other navigation is handled by the server (in chrome space).
|
* All other navigation is handled by the server (in chrome space).
|
||||||
*/
|
*/
|
||||||
function goUrl(msg) {
|
function goUrl(msg) {
|
||||||
|
let command_id = msg.json.command_id;
|
||||||
addEventListener("DOMContentLoaded", function onDOMContentLoaded(event) {
|
addEventListener("DOMContentLoaded", function onDOMContentLoaded(event) {
|
||||||
// Prevent DOMContentLoaded events from frames from invoking this code,
|
// Prevent DOMContentLoaded events from frames from invoking this code,
|
||||||
// unless the event is coming from the frame associated with the current
|
// unless the event is coming from the frame associated with the current
|
||||||
|
@ -546,11 +551,11 @@ function goUrl(msg) {
|
||||||
|
|
||||||
let errorRegex = /about:.+(error)|(blocked)\?/;
|
let errorRegex = /about:.+(error)|(blocked)\?/;
|
||||||
if (curWindow.document.readyState == "interactive" && errorRegex.exec(curWindow.document.baseURI)) {
|
if (curWindow.document.readyState == "interactive" && errorRegex.exec(curWindow.document.baseURI)) {
|
||||||
sendError("Error loading page", 13, null);
|
sendError("Error loading page", 13, null, command_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendOk();
|
sendOk(command_id);
|
||||||
}
|
}
|
||||||
}, false);
|
}, false);
|
||||||
curWindow.location = msg.json.value;
|
curWindow.location = msg.json.value;
|
||||||
|
@ -560,14 +565,14 @@ function goUrl(msg) {
|
||||||
* Get the current URI
|
* Get the current URI
|
||||||
*/
|
*/
|
||||||
function getUrl(msg) {
|
function getUrl(msg) {
|
||||||
sendResponse({value: curWindow.location.href});
|
sendResponse({value: curWindow.location.href}, msg.json.command_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current Title of the window
|
* Get the current Title of the window
|
||||||
*/
|
*/
|
||||||
function getTitle(msg) {
|
function getTitle(msg) {
|
||||||
sendResponse({value: curWindow.top.document.title});
|
sendResponse({value: curWindow.top.document.title}, msg.json.command_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -576,7 +581,7 @@ function getTitle(msg) {
|
||||||
function getPageSource(msg) {
|
function getPageSource(msg) {
|
||||||
var XMLSerializer = curWindow.XMLSerializer;
|
var XMLSerializer = curWindow.XMLSerializer;
|
||||||
var pageSource = new XMLSerializer().serializeToString(curWindow.document);
|
var pageSource = new XMLSerializer().serializeToString(curWindow.document);
|
||||||
sendResponse({value: pageSource });
|
sendResponse({value: pageSource}, msg.json.command_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -584,7 +589,7 @@ function getPageSource(msg) {
|
||||||
*/
|
*/
|
||||||
function goBack(msg) {
|
function goBack(msg) {
|
||||||
curWindow.history.back();
|
curWindow.history.back();
|
||||||
sendOk();
|
sendOk(msg.json.command_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -592,15 +597,19 @@ function goBack(msg) {
|
||||||
*/
|
*/
|
||||||
function goForward(msg) {
|
function goForward(msg) {
|
||||||
curWindow.history.forward();
|
curWindow.history.forward();
|
||||||
sendOk();
|
sendOk(msg.json.command_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh the page
|
* Refresh the page
|
||||||
*/
|
*/
|
||||||
function refresh(msg) {
|
function refresh(msg) {
|
||||||
|
let command_id = msg.json.command_id;
|
||||||
curWindow.location.reload(true);
|
curWindow.location.reload(true);
|
||||||
let listen = function() { removeEventListener("DOMContentLoaded", arguments.callee, false); sendOk() } ;
|
let listen = function() {
|
||||||
|
removeEventListener("DOMContentLoaded", arguments.callee, false);
|
||||||
|
sendOk(command_id);
|
||||||
|
};
|
||||||
addEventListener("DOMContentLoaded", listen, false);
|
addEventListener("DOMContentLoaded", listen, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -608,13 +617,14 @@ function refresh(msg) {
|
||||||
* Find an element in the document using requested search strategy
|
* Find an element in the document using requested search strategy
|
||||||
*/
|
*/
|
||||||
function findElementContent(msg) {
|
function findElementContent(msg) {
|
||||||
|
let command_id = msg.json.command_id;
|
||||||
try {
|
try {
|
||||||
let on_success = function(id) { sendResponse({value:id}); };
|
let on_success = function(id, cmd_id) { sendResponse({value:id}, cmd_id); };
|
||||||
let on_error = sendError;
|
let on_error = sendError;
|
||||||
elementManager.find(curWindow, msg.json, on_success, on_error, false);
|
elementManager.find(curWindow, msg.json, on_success, on_error, false, command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
sendError(e.message, e.code, e.stack);
|
sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -622,13 +632,14 @@ function findElementContent(msg) {
|
||||||
* Find elements in the document using requested search strategy
|
* Find elements in the document using requested search strategy
|
||||||
*/
|
*/
|
||||||
function findElementsContent(msg) {
|
function findElementsContent(msg) {
|
||||||
|
let command_id = msg.json.command_id;
|
||||||
try {
|
try {
|
||||||
let on_success = function(id) { sendResponse({value:id}); };
|
let on_success = function(id, cmd_id) { sendResponse({value:id}, cmd_id); };
|
||||||
let on_error = sendError;
|
let on_error = sendError;
|
||||||
elementManager.find(curWindow, msg.json, on_success, on_error, true);
|
elementManager.find(curWindow, msg.json, on_success, on_error, true, command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
sendError(e.message, e.code, e.stack);
|
sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -636,14 +647,15 @@ function findElementsContent(msg) {
|
||||||
* Send click event to element
|
* Send click event to element
|
||||||
*/
|
*/
|
||||||
function clickElement(msg) {
|
function clickElement(msg) {
|
||||||
|
let command_id = msg.json.command_id;
|
||||||
let el;
|
let el;
|
||||||
try {
|
try {
|
||||||
el = elementManager.getKnownElement(msg.json.element, curWindow);
|
el = elementManager.getKnownElement(msg.json.element, curWindow);
|
||||||
utils.click(el);
|
utils.click(el);
|
||||||
sendOk();
|
sendOk(command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
sendError(e.message, e.code, e.stack);
|
sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -651,12 +663,14 @@ function clickElement(msg) {
|
||||||
* Get a given attribute of an element
|
* Get a given attribute of an element
|
||||||
*/
|
*/
|
||||||
function getElementAttribute(msg) {
|
function getElementAttribute(msg) {
|
||||||
|
let command_id = msg.json.command_id;
|
||||||
try {
|
try {
|
||||||
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
||||||
sendResponse({value: utils.getElementAttribute(el, msg.json.name)});
|
sendResponse({value: utils.getElementAttribute(el, msg.json.name)},
|
||||||
|
command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
sendError(e.message, e.code, e.stack);
|
sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,12 +678,13 @@ function getElementAttribute(msg) {
|
||||||
* Get the text of this element. This includes text from child elements.
|
* Get the text of this element. This includes text from child elements.
|
||||||
*/
|
*/
|
||||||
function getElementText(msg) {
|
function getElementText(msg) {
|
||||||
|
let command_id = msg.json.command_id;
|
||||||
try {
|
try {
|
||||||
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
||||||
sendResponse({value: utils.getElementText(el)});
|
sendResponse({value: utils.getElementText(el)}, command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
sendError(e.message, e.code, e.stack);
|
sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -677,12 +692,13 @@ function getElementText(msg) {
|
||||||
* Get the tag name of an element.
|
* Get the tag name of an element.
|
||||||
*/
|
*/
|
||||||
function getElementTagName(msg) {
|
function getElementTagName(msg) {
|
||||||
|
let command_id = msg.json.command_id;
|
||||||
try {
|
try {
|
||||||
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
||||||
sendResponse({value: el.tagName.toLowerCase()});
|
sendResponse({value: el.tagName.toLowerCase()}, command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
sendError(e.message, e.code, e.stack);
|
sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -690,12 +706,13 @@ function getElementTagName(msg) {
|
||||||
* Check if element is displayed
|
* Check if element is displayed
|
||||||
*/
|
*/
|
||||||
function isElementDisplayed(msg) {
|
function isElementDisplayed(msg) {
|
||||||
|
let command_id = msg.json.command_id;
|
||||||
try {
|
try {
|
||||||
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
||||||
sendResponse({value: utils.isElementDisplayed(el)});
|
sendResponse({value: utils.isElementDisplayed(el)}, command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
sendError(e.message, e.code, e.stack);
|
sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -703,13 +720,15 @@ function isElementDisplayed(msg) {
|
||||||
* Get the size of the element and return it
|
* Get the size of the element and return it
|
||||||
*/
|
*/
|
||||||
function getElementSize(msg){
|
function getElementSize(msg){
|
||||||
|
let command_id = msg.json.command_id;
|
||||||
try {
|
try {
|
||||||
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
||||||
let clientRect = el.getBoundingClientRect();
|
let clientRect = el.getBoundingClientRect();
|
||||||
sendResponse({value: {width: clientRect.width, height: clientRect.height}});
|
sendResponse({value: {width: clientRect.width, height: clientRect.height}},
|
||||||
|
command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
sendError(e.message, e.code, e.stack);
|
sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -717,12 +736,13 @@ function getElementSize(msg){
|
||||||
* Check if element is enabled
|
* Check if element is enabled
|
||||||
*/
|
*/
|
||||||
function isElementEnabled(msg) {
|
function isElementEnabled(msg) {
|
||||||
|
let command_id = msg.json.command_id;
|
||||||
try {
|
try {
|
||||||
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
||||||
sendResponse({value: utils.isElementEnabled(el)});
|
sendResponse({value: utils.isElementEnabled(el)}, command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
sendError(e.message, e.code, e.stack);
|
sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -730,12 +750,13 @@ function isElementEnabled(msg) {
|
||||||
* Check if element is selected
|
* Check if element is selected
|
||||||
*/
|
*/
|
||||||
function isElementSelected(msg) {
|
function isElementSelected(msg) {
|
||||||
|
let command_id = msg.json.command_id;
|
||||||
try {
|
try {
|
||||||
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
||||||
sendResponse({value: utils.isElementSelected(el)});
|
sendResponse({value: utils.isElementSelected(el)}, command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
sendError(e.message, e.code, e.stack);
|
sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -743,13 +764,14 @@ function isElementSelected(msg) {
|
||||||
* Send keys to element
|
* Send keys to element
|
||||||
*/
|
*/
|
||||||
function sendKeysToElement(msg) {
|
function sendKeysToElement(msg) {
|
||||||
|
let command_id = msg.json.command_id;
|
||||||
try {
|
try {
|
||||||
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
||||||
utils.type(curWindow.document, el, msg.json.value.join(""), true);
|
utils.type(curWindow.document, el, msg.json.value.join(""), true);
|
||||||
sendOk();
|
sendOk(command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
sendError(e.message, e.code, e.stack);
|
sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -757,6 +779,7 @@ function sendKeysToElement(msg) {
|
||||||
* Get the position of an element
|
* Get the position of an element
|
||||||
*/
|
*/
|
||||||
function getElementPosition(msg) {
|
function getElementPosition(msg) {
|
||||||
|
let command_id = msg.json.command_id;
|
||||||
try{
|
try{
|
||||||
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
||||||
var x = el.offsetLeft;
|
var x = el.offsetLeft;
|
||||||
|
@ -785,10 +808,10 @@ function getElementPosition(msg) {
|
||||||
location.x = x;
|
location.x = x;
|
||||||
location.y = y;
|
location.y = y;
|
||||||
|
|
||||||
sendResponse({value: location});
|
sendResponse({value: location}, command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
sendError(e.message, e.code, e.stack);
|
sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -796,13 +819,14 @@ function getElementPosition(msg) {
|
||||||
* Clear the text of an element
|
* Clear the text of an element
|
||||||
*/
|
*/
|
||||||
function clearElement(msg) {
|
function clearElement(msg) {
|
||||||
|
let command_id = msg.json.command_id;
|
||||||
try {
|
try {
|
||||||
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
||||||
utils.clearElement(el);
|
utils.clearElement(el);
|
||||||
sendOk();
|
sendOk(command_id);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
sendError(e.message, e.code, e.stack);
|
sendError(e.message, e.code, e.stack, command_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -811,14 +835,15 @@ function clearElement(msg) {
|
||||||
* its index in window.frames, or the iframe's name or id.
|
* its index in window.frames, or the iframe's name or id.
|
||||||
*/
|
*/
|
||||||
function switchToFrame(msg) {
|
function switchToFrame(msg) {
|
||||||
|
let command_id = msg.json.command_id;
|
||||||
function checkLoad() {
|
function checkLoad() {
|
||||||
let errorRegex = /about:.+(error)|(blocked)\?/;
|
let errorRegex = /about:.+(error)|(blocked)\?/;
|
||||||
if (curWindow.document.readyState == "complete") {
|
if (curWindow.document.readyState == "complete") {
|
||||||
sendOk();
|
sendOk(command_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (curWindow.document.readyState == "interactive" && errorRegex.exec(curWindow.document.baseURI)) {
|
else if (curWindow.document.readyState == "interactive" && errorRegex.exec(curWindow.document.baseURI)) {
|
||||||
sendError("Error loading page", 13, null);
|
sendError("Error loading page", 13, null, command_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
|
checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||||
|
@ -876,7 +901,7 @@ function switchToFrame(msg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (foundFrame == null) {
|
if (foundFrame == null) {
|
||||||
sendError("Unable to locate frame: " + msg.json.value, 8, null);
|
sendError("Unable to locate frame: " + msg.json.value, 8, null, command_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -886,7 +911,9 @@ function switchToFrame(msg) {
|
||||||
// The frame we want to switch to is a remote frame; notify our parent to handle
|
// The frame we want to switch to is a remote frame; notify our parent to handle
|
||||||
// the switch.
|
// the switch.
|
||||||
curWindow = content;
|
curWindow = content;
|
||||||
sendToServer('Marionette:switchToFrame', {frame: foundFrame, win: parWindow});
|
sendToServer('Marionette:switchToFrame', {frame: foundFrame,
|
||||||
|
win: parWindow,
|
||||||
|
command_id: command_id});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
curWindow = curWindow.contentWindow;
|
curWindow = curWindow.contentWindow;
|
||||||
|
@ -895,8 +922,9 @@ function switchToFrame(msg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAppCacheStatus() {
|
function getAppCacheStatus(msg) {
|
||||||
sendResponse({ value: curWindow.applicationCache.status });
|
sendResponse({ value: curWindow.applicationCache.status },
|
||||||
|
msg.json.command_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// emulator callbacks
|
// emulator callbacks
|
||||||
|
@ -931,19 +959,23 @@ function emulatorCmdResult(msg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function importScript(msg) {
|
function importScript(msg) {
|
||||||
|
let command_id = msg.json.command_id;
|
||||||
let file;
|
let file;
|
||||||
if (importedScripts.exists()) {
|
if (importedScripts.exists()) {
|
||||||
file = FileUtils.openFileOutputStream(importedScripts, FileUtils.MODE_APPEND | FileUtils.MODE_WRONLY);
|
file = FileUtils.openFileOutputStream(importedScripts,
|
||||||
|
FileUtils.MODE_APPEND | FileUtils.MODE_WRONLY);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//Note: The permission bits here don't actually get set (bug 804563)
|
//Note: The permission bits here don't actually get set (bug 804563)
|
||||||
importedScripts.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, parseInt("0666", 8));
|
importedScripts.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE,
|
||||||
file = FileUtils.openFileOutputStream(importedScripts, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE);
|
parseInt("0666", 8));
|
||||||
|
file = FileUtils.openFileOutputStream(importedScripts,
|
||||||
|
FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE);
|
||||||
importedScripts.permissions = parseInt("0666", 8); //actually set permissions
|
importedScripts.permissions = parseInt("0666", 8); //actually set permissions
|
||||||
}
|
}
|
||||||
file.write(msg.json.script, msg.json.script.length);
|
file.write(msg.json.script, msg.json.script.length);
|
||||||
file.close();
|
file.close();
|
||||||
sendOk();
|
sendOk(command_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Загрузка…
Ссылка в новой задаче