mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Bug 712643 - land Marionette on m-c. r=mossop,robcee
This commit is contained in:
parent
e6177eb663
commit
710c159137
@ -122,6 +122,14 @@ if [ "$COMPILER_DEPEND" = "" -a "$MOZ_NATIVE_MAKEDEPEND" = "" ]; then
|
||||
"
|
||||
fi
|
||||
|
||||
if [ "$ENABLE_MARIONETTE" ]; then
|
||||
add_makefiles "
|
||||
testing/marionette/Makefile
|
||||
testing/marionette/components/Makefile
|
||||
testing/marionette/tests/Makefile
|
||||
"
|
||||
fi
|
||||
|
||||
if [ "$ENABLE_TESTS" ]; then
|
||||
add_makefiles "
|
||||
build/autoconf/test/Makefile
|
||||
|
@ -455,6 +455,10 @@ pref("ril.data.apn", "");
|
||||
pref("ril.data.user", "");
|
||||
pref("ril.data.passwd", "");
|
||||
|
||||
//Enable/disable marionette server, set listening port
|
||||
pref("marionette.defaultPrefs.enabled", true);
|
||||
pref("marionette.defaultPrefs.port", 2828);
|
||||
|
||||
#ifdef MOZ_UPDATER
|
||||
pref("app.update.enabled", true);
|
||||
pref("app.update.auto", true);
|
||||
|
@ -46,7 +46,7 @@ MOZ_OFFICIAL_BRANDING_DIRECTORY=b2g/branding/official
|
||||
# MOZ_APP_DISPLAYNAME is set by branding/configure.sh
|
||||
|
||||
MOZ_SAFE_BROWSING=
|
||||
MOZ_SERVICES_SYNC=
|
||||
MOZ_SERVICES_SYNC=1
|
||||
|
||||
MOZ_WEBSMS_BACKEND=1
|
||||
MOZ_DISABLE_DOMCRYPTO=1
|
||||
|
@ -617,6 +617,10 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DLL_SUFFIX@
|
||||
@BINPATH@/components/B2GComponents.manifest
|
||||
@BINPATH@/components/B2GComponents.xpt
|
||||
@BINPATH@/components/CameraContent.js
|
||||
@BINPATH@/chrome/marionette@JAREXT@
|
||||
@BINPATH@/chrome/marionette.manifest
|
||||
@BINPATH@/components/MarionetteComponents.manifest
|
||||
@BINPATH@/components/marionettecomponent.js
|
||||
@BINPATH@/components/AlertsService.js
|
||||
@BINPATH@/components/ContentPermissionPrompt.js
|
||||
#ifdef MOZ_UPDATER
|
||||
|
@ -135,6 +135,7 @@ MOZ_LIBSTDCXX_HOST_VERSION=@MOZ_LIBSTDCXX_HOST_VERSION@
|
||||
INCREMENTAL_LINKER = @INCREMENTAL_LINKER@
|
||||
MACOSX_DEPLOYMENT_TARGET = @MACOSX_DEPLOYMENT_TARGET@
|
||||
ENABLE_TESTS = @ENABLE_TESTS@
|
||||
ENABLE_MARIONETTE = @ENABLE_MARIONETTE@
|
||||
IBMBIDI = @IBMBIDI@
|
||||
MOZ_UNIVERSALCHARDET = @MOZ_UNIVERSALCHARDET@
|
||||
ACCESSIBILITY = @ACCESSIBILITY@
|
||||
|
@ -6437,6 +6437,14 @@ MOZ_ARG_DISABLE_BOOL(tests,
|
||||
ENABLE_TESTS=,
|
||||
ENABLE_TESTS=1 )
|
||||
|
||||
dnl ========================================================
|
||||
dnl Marionette
|
||||
dnl ========================================================
|
||||
MOZ_ARG_ENABLE_BOOL(marionette,
|
||||
[ --enable-marionette Enable Marionette for remote testing and control],
|
||||
ENABLE_MARIONETTE=1,
|
||||
ENABLE_MARIONETTE)
|
||||
|
||||
dnl ========================================================
|
||||
dnl parental controls (for Windows Vista)
|
||||
dnl ========================================================
|
||||
@ -8381,6 +8389,7 @@ AC_SUBST(JAR)
|
||||
AC_SUBST(MOZ_PROFILELOCKING)
|
||||
|
||||
AC_SUBST(ENABLE_TESTS)
|
||||
AC_SUBST(ENABLE_MARIONETTE)
|
||||
AC_SUBST(IBMBIDI)
|
||||
AC_SUBST(MOZ_UNIVERSALCHARDET)
|
||||
AC_SUBST(ACCESSIBILITY)
|
||||
|
19
testing/marionette/Makefile.in
Normal file
19
testing/marionette/Makefile.in
Normal file
@ -0,0 +1,19 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
ifdef ENABLE_MARIONETTE
|
||||
DIRS += components
|
||||
ifdef ENABLE_TESTS
|
||||
DIRS += tests
|
||||
endif
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
17
testing/marionette/components/Makefile.in
Normal file
17
testing/marionette/components/Makefile.in
Normal file
@ -0,0 +1,17 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
EXTRA_PP_COMPONENTS = \
|
||||
MarionetteComponents.manifest \
|
||||
marionettecomponent.js \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
@ -0,0 +1,4 @@
|
||||
# Marionette
|
||||
component {786a1369-dca5-4adc-8486-33d23c88010a} marionettecomponent.js
|
||||
contract @mozilla.org/marionette;1 {786a1369-dca5-4adc-8486-33d23c88010a}
|
||||
category profile-after-change MarionetteComponent @mozilla.org/marionette;1
|
89
testing/marionette/components/marionettecomponent.js
Normal file
89
testing/marionette/components/marionettecomponent.js
Normal file
@ -0,0 +1,89 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
const MARIONETTE_CONTRACTID = "@mozilla.org/marionette;1";
|
||||
const MARIONETTE_CID = Components.ID("{786a1369-dca5-4adc-8486-33d23c88010a}");
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function MarionetteComponent() {
|
||||
this._loaded = false;
|
||||
}
|
||||
|
||||
MarionetteComponent.prototype = {
|
||||
classDescription: "Marionette component",
|
||||
classID: MARIONETTE_CID,
|
||||
contractID: MARIONETTE_CONTRACTID,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
|
||||
_xpcom_categories: [{category: "profile-after-change", service: true}],
|
||||
|
||||
observe: function mc_observe(aSubject, aTopic, aData) {
|
||||
let observerService = Services.obs;
|
||||
switch (aTopic) {
|
||||
case "profile-after-change":
|
||||
if (Services.prefs.getBoolPref('marionette.defaultPrefs.enabled')) {
|
||||
// set up the logger
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
Cu.import("resource://gre/modules/services-sync/log4moz.js");
|
||||
|
||||
let logger = Log4Moz.repository.getLogger("Marionette");
|
||||
logger.level = Log4Moz.Level["All"];
|
||||
let logf = FileUtils.getFile('ProfD', ['marionette.log']);
|
||||
|
||||
let formatter = new Log4Moz.BasicFormatter();
|
||||
logger.addAppender(new Log4Moz.FileAppender(logf, formatter));
|
||||
logger.info("MarionetteComponent loaded");
|
||||
|
||||
//add observers
|
||||
observerService.addObserver(this, "final-ui-startup", false);
|
||||
observerService.addObserver(this, "xpcom-shutdown", false);
|
||||
}
|
||||
else {
|
||||
logger.info("marionette not enabled");
|
||||
}
|
||||
break;
|
||||
case "final-ui-startup":
|
||||
observerService.removeObserver(this, "final-ui-startup");
|
||||
this.init();
|
||||
break;
|
||||
case "xpcom-shutdown":
|
||||
observerService.removeObserver(this, "xpcom-shutdown");
|
||||
this.uninit();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
init: function mc_init() {
|
||||
if (!this._loaded) {
|
||||
this._loaded = true;
|
||||
let port;
|
||||
try {
|
||||
port = Services.prefs.getIntPref('marionette.defaultPrefs.port');
|
||||
}
|
||||
catch(e) {
|
||||
port = 2828;
|
||||
}
|
||||
try {
|
||||
Cu.import('resource:///modules/devtools/dbg-server.jsm');
|
||||
DebuggerServer.addActors('chrome://marionette/content/marionette-actors.js');
|
||||
DebuggerServer.initTransport();
|
||||
DebuggerServer.openListener(port, true);
|
||||
}
|
||||
catch(e) {
|
||||
logger.error('exception: ' + e.name + ', ' + e.message);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
uninit: function mc_uninit() {
|
||||
DebuggerServer.closeListener();
|
||||
this._loaded = false;
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
const NSGetFactory = XPCOMUtils.generateNSGetFactory([MarionetteComponent]);
|
7
testing/marionette/jar.mn
Normal file
7
testing/marionette/jar.mn
Normal file
@ -0,0 +1,7 @@
|
||||
marionette.jar:
|
||||
% content marionette %content/
|
||||
content/marionette-actors.js (marionette-actors.js)
|
||||
content/marionette-listener.js (marionette-listener.js)
|
||||
content/marionette-elements.js (marionette-elements.js)
|
||||
content/marionette-log-obj.js (marionette-log-obj.js)
|
||||
content/marionette-simpletest.js (marionette-simpletest.js)
|
1050
testing/marionette/marionette-actors.js
Normal file
1050
testing/marionette/marionette-actors.js
Normal file
File diff suppressed because it is too large
Load Diff
403
testing/marionette/marionette-elements.js
Normal file
403
testing/marionette/marionette-elements.js
Normal file
@ -0,0 +1,403 @@
|
||||
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* The ElementManager manages DOM references and interactions with elements.
|
||||
* According to the WebDriver spec (http://code.google.com/p/selenium/wiki/JsonWireProtocol), the
|
||||
* server sends the client an element reference, and maintains the map of reference to element.
|
||||
* The client uses this reference when querying/interacting with the element, and the
|
||||
* server uses maps this reference to the actual element when it executes the command.
|
||||
*/
|
||||
|
||||
let EXPORTED_SYMBOLS = ["ElementManager", "CLASS_NAME", "SELECTOR", "ID", "NAME", "LINK_TEXT", "PARTIAL_LINK_TEXT", "TAG", "XPATH"];
|
||||
|
||||
let uuidGen = Components.classes["@mozilla.org/uuid-generator;1"]
|
||||
.getService(Components.interfaces.nsIUUIDGenerator);
|
||||
|
||||
let CLASS_NAME = "class name";
|
||||
let SELECTOR = "css selector";
|
||||
let ID = "id";
|
||||
let NAME = "name";
|
||||
let LINK_TEXT = "link text";
|
||||
let PARTIAL_LINK_TEXT = "partial link text";
|
||||
let TAG = "tag name";
|
||||
let XPATH = "xpath";
|
||||
|
||||
function ElementException(msg, num, stack) {
|
||||
this.message = msg;
|
||||
this.num = num;
|
||||
this.stack = stack;
|
||||
}
|
||||
|
||||
/* NOTE: Bug 736592 has been created to replace seenItems with a weakRef map */
|
||||
function ElementManager(notSupported) {
|
||||
this.searchTimeout = 0;
|
||||
this.seenItems = {};
|
||||
this.timer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
|
||||
this.elementStrategies = [CLASS_NAME, SELECTOR, ID, NAME, LINK_TEXT, PARTIAL_LINK_TEXT, TAG, XPATH];
|
||||
for (let i = 0; i < notSupported.length; i++) {
|
||||
this.elementStrategies.splice(this.elementStrategies.indexOf(notSupported[i]), 1);
|
||||
}
|
||||
}
|
||||
|
||||
ElementManager.prototype = {
|
||||
/**
|
||||
* Reset values
|
||||
*/
|
||||
reset: function EM_clear() {
|
||||
this.searchTimeout = 0;
|
||||
this.seenItems = {};
|
||||
},
|
||||
|
||||
/**
|
||||
* Add element to list of seen elements
|
||||
*
|
||||
* @param nsIDOMElement element
|
||||
* The element to add
|
||||
*
|
||||
* @return string
|
||||
* Returns the server-assigned reference ID
|
||||
*/
|
||||
addToKnownElements: function EM_addToKnownElements(element) {
|
||||
for (let i in this.seenItems) {
|
||||
if (this.seenItems[i] == element) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
var id = uuidGen.generateUUID().toString();
|
||||
this.seenItems[id] = element;
|
||||
return id;
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve element from its unique ID
|
||||
*
|
||||
* @param String id
|
||||
* The DOM reference ID
|
||||
* @param nsIDOMWindow win
|
||||
* The window that contains the element
|
||||
*
|
||||
* @returns nsIDOMElement
|
||||
* Returns the element or throws Exception if not found
|
||||
*/
|
||||
getKnownElement: function EM_getKnownElement(id, win) {
|
||||
let el = this.seenItems[id];
|
||||
if (!el) {
|
||||
throw new ElementException("Element has not been seen before", 17, null);
|
||||
}
|
||||
el = el;
|
||||
if (!(el.ownerDocument == win.document)) {
|
||||
throw new ElementException("Stale element reference", 10, null);
|
||||
}
|
||||
return el;
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert values to primitives that can be transported over the Marionette
|
||||
* JSON protocol.
|
||||
*
|
||||
* @param object val
|
||||
* object to be wrapped
|
||||
*
|
||||
* @return object
|
||||
* Returns a JSON primitive or Object
|
||||
*/
|
||||
wrapValue: function EM_wrapValue(val) {
|
||||
let result;
|
||||
switch(typeof(val)) {
|
||||
case "undefined":
|
||||
result = null;
|
||||
break;
|
||||
case "string":
|
||||
case "number":
|
||||
case "boolean":
|
||||
result = val;
|
||||
break;
|
||||
case "object":
|
||||
if (Object.prototype.toString.call(val) == '[object Array]') {
|
||||
result = [];
|
||||
for (let i in val) {
|
||||
result.push(this.wrapValue(val[i]));
|
||||
}
|
||||
}
|
||||
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) {
|
||||
result = {'ELEMENT': i};
|
||||
}
|
||||
}
|
||||
result = {'ELEMENT': this.addToKnownElements(val)};
|
||||
}
|
||||
else {
|
||||
result = {};
|
||||
for (let prop in val) {
|
||||
result[prop] = this.wrapValue(val[prop]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert any ELEMENT references in 'args' to the actual elements
|
||||
*
|
||||
* @param object args
|
||||
* Arguments passed in by client
|
||||
* @param nsIDOMWindow win
|
||||
* The window that contains the elements
|
||||
*
|
||||
* @returns object
|
||||
* Returns the objects passed in by the client, with the
|
||||
* reference IDs replaced by the actual elements.
|
||||
*/
|
||||
convertWrappedArguments: function EM_convertWrappedArguments(args, win) {
|
||||
let converted;
|
||||
switch (typeof(args)) {
|
||||
case 'number':
|
||||
case 'string':
|
||||
case 'boolean':
|
||||
converted = args;
|
||||
break;
|
||||
case 'object':
|
||||
if (args == null) {
|
||||
converted = null;
|
||||
}
|
||||
else if (Object.prototype.toString.call(args) == '[object Array]') {
|
||||
converted = [];
|
||||
for (let i in args) {
|
||||
converted.push(this.convertWrappedArguments(args[i], win));
|
||||
}
|
||||
}
|
||||
else if (typeof(args['ELEMENT'] === 'string') &&
|
||||
args.hasOwnProperty('ELEMENT')) {
|
||||
converted = this.getKnownElement(args['ELEMENT'], win);
|
||||
if (converted == null)
|
||||
throw new ElementException("Unknown element: " + args['ELEMENT'], 500, null);
|
||||
}
|
||||
else {
|
||||
converted = {};
|
||||
for (let prop in args) {
|
||||
converted[prop] = this.convertWrappedArguments(args[prop], win);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return converted;
|
||||
},
|
||||
|
||||
/*
|
||||
* Execute* helpers
|
||||
*/
|
||||
|
||||
/**
|
||||
* Return an object with any namedArgs applied to it. Used
|
||||
* to let clients use given names when refering to arguments
|
||||
* in execute calls, instead of using the arguments list.
|
||||
*
|
||||
* @param object args
|
||||
* list of arguments being passed in
|
||||
*
|
||||
* @return object
|
||||
* If '__marionetteArgs' is in args, then
|
||||
* it will return an object with these arguments
|
||||
* as its members.
|
||||
*/
|
||||
applyNamedArgs: function EM_applyNamedArgs(args) {
|
||||
namedArgs = {};
|
||||
args.forEach(function(arg) {
|
||||
if (typeof(arg['__marionetteArgs']) === 'object') {
|
||||
for (let prop in arg['__marionetteArgs']) {
|
||||
namedArgs[prop] = arg['__marionetteArgs'][prop];
|
||||
}
|
||||
}
|
||||
});
|
||||
return namedArgs;
|
||||
},
|
||||
|
||||
/**
|
||||
* Find an element or elements starting at the document root
|
||||
* using the given search strategy. Search
|
||||
* will continue until the search timelimit has been reached.
|
||||
*
|
||||
* @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 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
|
||||
* If true, all found elements will be returned.
|
||||
* If false, only the first element will be returned.
|
||||
*
|
||||
* @return nsIDOMElement or list of nsIDOMElements
|
||||
* Returns the element(s) by calling the notify function.
|
||||
*/
|
||||
find: function EM_find(values, rootNode, notify, all) {
|
||||
let startTime = values.time ? values.time : new Date().getTime();
|
||||
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);
|
||||
if (found) {
|
||||
let type = Object.prototype.toString.call(found);
|
||||
if ((type == '[object Array]') || (type == '[object HTMLCollection]')) {
|
||||
let ids = []
|
||||
for (let i = 0 ; i < found.length ; i++) {
|
||||
ids.push(this.addToKnownElements(found[i]));
|
||||
}
|
||||
notify(ids);
|
||||
}
|
||||
else {
|
||||
let id = this.addToKnownElements(found);
|
||||
notify(id);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (this.searchTimeout == 0 || new Date().getTime() - startTime > this.searchTimeout) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper method to find. Finds one element using find's criteria
|
||||
*
|
||||
* @param string using
|
||||
* String identifying which search method to use
|
||||
* @param string value
|
||||
* Value to look for
|
||||
* @param nsIDOMElement rootNode
|
||||
* Document root
|
||||
*
|
||||
* @return nsIDOMElement
|
||||
* Returns found element or throws Exception if not found
|
||||
*/
|
||||
findElement: function EM_findElement(using, value, rootNode) {
|
||||
let element;
|
||||
switch (using) {
|
||||
case ID:
|
||||
element = rootNode.getElementById(value);
|
||||
break;
|
||||
case NAME:
|
||||
element = rootNode.getElementsByName(value)[0];
|
||||
break;
|
||||
case CLASS_NAME:
|
||||
element = rootNode.getElementsByClassName(value)[0];
|
||||
break;
|
||||
case TAG:
|
||||
element = rootNode.getElementsByTagName(value)[0];
|
||||
break;
|
||||
case XPATH:
|
||||
element = rootNode.evaluate(value, rootNode, null,
|
||||
Components.interfaces.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE, null).
|
||||
singleNodeValue;
|
||||
break;
|
||||
case LINK_TEXT:
|
||||
case PARTIAL_LINK_TEXT:
|
||||
let allLinks = rootNode.getElementsByTagName('A');
|
||||
for (let i = 0; i < allLinks.length && !element; i++) {
|
||||
let text = allLinks[i].text;
|
||||
if (PARTIAL_LINK_TEXT == using) {
|
||||
if (text.indexOf(value) != -1) {
|
||||
element = allLinks[i];
|
||||
}
|
||||
} else if (text == value) {
|
||||
element = allLinks[i];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SELECTOR:
|
||||
element = rootNode.querySelector(value);
|
||||
break;
|
||||
default:
|
||||
throw new ElementException("No such strategy", 500, null);
|
||||
}
|
||||
return element;
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper method to find. Finds all element using find's criteria
|
||||
*
|
||||
* @param string using
|
||||
* String identifying which search method to use
|
||||
* @param string value
|
||||
* Value to look for
|
||||
* @param nsIDOMElement rootNode
|
||||
* Document root
|
||||
*
|
||||
* @return nsIDOMElement
|
||||
* Returns found elements or throws Exception if not found
|
||||
*/
|
||||
findElements: function EM_findElements(using, value, rootNode) {
|
||||
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();
|
||||
}
|
||||
break;
|
||||
case NAME:
|
||||
elements = rootNode.getElementsByName(value);
|
||||
break;
|
||||
case CLASS_NAME:
|
||||
elements = rootNode.getElementsByClassName(value);
|
||||
break;
|
||||
case TAG:
|
||||
elements = rootNode.getElementsByTagName(value);
|
||||
break;
|
||||
case LINK_TEXT:
|
||||
case PARTIAL_LINK_TEXT:
|
||||
let allLinks = rootNode.getElementsByTagName('A');
|
||||
for (let i = 0; i < allLinks.length; i++) {
|
||||
let text = allLinks[i].text;
|
||||
if (PARTIAL_LINK_TEXT == using) {
|
||||
if (text.indexOf(value) != -1) {
|
||||
elements.push(allLinks[i]);
|
||||
}
|
||||
} else if (text == value) {
|
||||
elements.push(allLinks[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SELECTOR:
|
||||
elements = rootNode.querySelectorAll(value);
|
||||
break;
|
||||
default:
|
||||
throw new ElementException("No such strategy", 500, null);
|
||||
}
|
||||
return elements;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the timeout for searching for elements with find element
|
||||
*
|
||||
* @param number value
|
||||
* Timeout value in milliseconds
|
||||
*/
|
||||
setSearchTimeout: function EM_setSearchTimeout(value) {
|
||||
this.searchTimeout = parseInt(value);
|
||||
if(isNaN(this.searchTimeout)){
|
||||
throw new ElementException("Not a Number", 500, null);
|
||||
}
|
||||
},
|
||||
}
|
534
testing/marionette/marionette-listener.js
Normal file
534
testing/marionette/marionette-listener.js
Normal file
@ -0,0 +1,534 @@
|
||||
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
let Cu = Components.utils;
|
||||
let uuidGen = Components.classes["@mozilla.org/uuid-generator;1"]
|
||||
.getService(Components.interfaces.nsIUUIDGenerator);
|
||||
|
||||
let loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
|
||||
.getService(Components.interfaces.mozIJSSubScriptLoader);
|
||||
loader.loadSubScript("chrome://marionette/content/marionette-simpletest.js");
|
||||
loader.loadSubScript("chrome://marionette/content/marionette-log-obj.js");
|
||||
Components.utils.import("chrome://marionette/content/marionette-elements.js");
|
||||
let marionetteLogObj = new MarionetteLogObj();
|
||||
|
||||
let isB2G = false;
|
||||
|
||||
let marionetteTimeout = null;
|
||||
let winUtil = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
let listenerId = null; //unique ID of this listener
|
||||
let activeFrame = null;
|
||||
let win = content;
|
||||
let elementManager = new ElementManager([]);
|
||||
|
||||
/**
|
||||
* Called when listener is first started up.
|
||||
* The listener sends its unique window ID and its current URI to the actor.
|
||||
* If the actor returns an ID, we start the listeners. Otherwise, nothing happens.
|
||||
*/
|
||||
function registerSelf() {
|
||||
let register = sendSyncMessage("Marionette:register", {value: winUtil.outerWindowID, href: content.location.href});
|
||||
|
||||
if (register[0]) {
|
||||
listenerId = register[0];
|
||||
startListeners();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start all message listeners
|
||||
*/
|
||||
function startListeners() {
|
||||
addMessageListener("Marionette:newSession" + listenerId, newSession);
|
||||
addMessageListener("Marionette:executeScript" + listenerId, executeScript);
|
||||
addMessageListener("Marionette:setScriptTimeout" + listenerId, setScriptTimeout);
|
||||
addMessageListener("Marionette:executeAsyncScript" + listenerId, executeAsyncScript);
|
||||
addMessageListener("Marionette:executeJSScript" + listenerId, executeJSScript);
|
||||
addMessageListener("Marionette:setSearchTimeout" + listenerId, setSearchTimeout);
|
||||
addMessageListener("Marionette:goUrl" + listenerId, goUrl);
|
||||
addMessageListener("Marionette:getUrl" + listenerId, getUrl);
|
||||
addMessageListener("Marionette:goBack" + listenerId, goBack);
|
||||
addMessageListener("Marionette:goForward" + listenerId, goForward);
|
||||
addMessageListener("Marionette:refresh" + listenerId, refresh);
|
||||
addMessageListener("Marionette:findElementContent" + listenerId, findElementContent);
|
||||
addMessageListener("Marionette:findElementsContent" + listenerId, findElementsContent);
|
||||
addMessageListener("Marionette:clickElement" + listenerId, clickElement);
|
||||
addMessageListener("Marionette:switchToFrame" + listenerId, switchToFrame);
|
||||
addMessageListener("Marionette:deleteSession" + listenerId, deleteSession);
|
||||
addMessageListener("Marionette:sleepSession" + listenerId, sleepSession);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when we start a new session. It registers the
|
||||
* current environment, and resets all values
|
||||
*/
|
||||
function newSession(msg) {
|
||||
isB2G = msg.json.B2G;
|
||||
resetValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the current session to sleep, so all listeners are removed except
|
||||
* for the 'restart' listener. This is used to keep the content listener
|
||||
* alive for reuse in B2G instead of reloading it each time.
|
||||
*/
|
||||
function sleepSession(msg) {
|
||||
deleteSession();
|
||||
addMessageListener("Marionette:restart", restart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restarts all our listeners after this listener was put to sleep
|
||||
*/
|
||||
function restart() {
|
||||
removeMessageListener("Marionette:restart", restart);
|
||||
registerSelf();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all listeners
|
||||
*/
|
||||
function deleteSession(msg) {
|
||||
removeMessageListener("Marionette:newSession" + listenerId, newSession);
|
||||
removeMessageListener("Marionette:executeScript" + listenerId, executeScript);
|
||||
removeMessageListener("Marionette:setScriptTimeout" + listenerId, setScriptTimeout);
|
||||
removeMessageListener("Marionette:executeAsyncScript" + listenerId, executeAsyncScript);
|
||||
removeMessageListener("Marionette:executeJSScript" + listenerId, executeJSScript);
|
||||
removeMessageListener("Marionette:setSearchTimeout" + listenerId, setSearchTimeout);
|
||||
removeMessageListener("Marionette:goUrl" + listenerId, goUrl);
|
||||
removeMessageListener("Marionette:getUrl" + listenerId, getUrl);
|
||||
removeMessageListener("Marionette:goBack" + listenerId, goBack);
|
||||
removeMessageListener("Marionette:goForward" + listenerId, goForward);
|
||||
removeMessageListener("Marionette:refresh" + listenerId, refresh);
|
||||
removeMessageListener("Marionette:findElementContent" + listenerId, findElementContent);
|
||||
removeMessageListener("Marionette:findElementsContent" + listenerId, findElementsContent);
|
||||
removeMessageListener("Marionette:clickElement" + listenerId, clickElement);
|
||||
removeMessageListener("Marionette:switchToFrame" + listenerId, switchToFrame);
|
||||
removeMessageListener("Marionette:deleteSession" + listenerId, deleteSession);
|
||||
removeMessageListener("Marionette:sleepSession" + listenerId, sleepSession);
|
||||
this.elementManager.reset();
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generic method to send a message to the server
|
||||
*/
|
||||
function sendToServer(msg, value, command_id) {
|
||||
if (command_id) {
|
||||
value.command_id = command_id;
|
||||
}
|
||||
sendAsyncMessage(msg, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send response back to server
|
||||
*/
|
||||
function sendResponse(value, command_id) {
|
||||
sendToServer("Marionette:done", value, command_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send ack back to server
|
||||
*/
|
||||
function sendOk(command_id) {
|
||||
sendToServer("Marionette:ok", {}, command_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send log message to server
|
||||
*/
|
||||
function sendLog(msg) {
|
||||
sendToServer("Marionette:log", { message: msg });
|
||||
}
|
||||
|
||||
/**
|
||||
* Send error message to server
|
||||
*/
|
||||
function sendError(message, status, trace, command_id) {
|
||||
let error_msg = { message: message, status: status, stacktrace: trace };
|
||||
sendToServer("Marionette:error", error_msg, command_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear test values after completion of test
|
||||
*/
|
||||
function resetValues() {
|
||||
marionetteTimeout = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* send error when we detect an unload event during async scripts
|
||||
*/
|
||||
function errUnload() {
|
||||
sendError("unload was called", 17, null);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Marionette Methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns a content sandbox that can be used by the execute_foo functions.
|
||||
*/
|
||||
function createExecuteContentSandbox(aWindow, marionette, args) {
|
||||
try {
|
||||
args = elementManager.convertWrappedArguments(args, aWindow);
|
||||
}
|
||||
catch(e) {
|
||||
sendError(e.message, e.num, e.stack);
|
||||
return;
|
||||
}
|
||||
|
||||
let sandbox = new Cu.Sandbox(aWindow);
|
||||
sandbox.window = aWindow;
|
||||
sandbox.document = sandbox.window.document;
|
||||
sandbox.navigator = sandbox.window.navigator;
|
||||
sandbox.__namedArgs = elementManager.applyNamedArgs(args);
|
||||
sandbox.__marionetteParams = args;
|
||||
sandbox.__proto__ = sandbox.window;
|
||||
|
||||
marionette.exports.forEach(function(fn) {
|
||||
sandbox[fn] = marionette[fn].bind(marionette);
|
||||
});
|
||||
|
||||
return sandbox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given script either as a function body (executeScript)
|
||||
* or directly (for 'mochitest' like JS Marionette tests)
|
||||
*/
|
||||
function executeScript(msg, directInject) {
|
||||
let script = msg.json.value;
|
||||
let marionette = new Marionette(false, win, "content", marionetteLogObj);
|
||||
|
||||
let sandbox = createExecuteContentSandbox(win, marionette, msg.json.args);
|
||||
if (!sandbox)
|
||||
return;
|
||||
|
||||
sandbox.finish = function sandbox_finish() {
|
||||
return marionette.generate_results();
|
||||
};
|
||||
|
||||
try {
|
||||
if (directInject) {
|
||||
let res = Cu.evalInSandbox(script, sandbox, "1.8");
|
||||
sendSyncMessage("Marionette:testLog", {value: elementManager.wrapValue(marionetteLogObj.getLogs())});
|
||||
marionetteLogObj.clearLogs();
|
||||
if (res == undefined || res.passed == undefined) {
|
||||
sendError("Marionette.finish() not called", 17, null);
|
||||
}
|
||||
else {
|
||||
sendResponse({value: elementManager.wrapValue(res)});
|
||||
}
|
||||
}
|
||||
else {
|
||||
let scriptSrc = "let __marionetteFunc = function(){" + script + "};" +
|
||||
"__marionetteFunc.apply(null, __marionetteParams);";
|
||||
let res = Cu.evalInSandbox(scriptSrc, sandbox, "1.8");
|
||||
sendSyncMessage("Marionette:testLog", {value: elementManager.wrapValue(marionetteLogObj.getLogs())});
|
||||
marionetteLogObj.clearLogs();
|
||||
sendResponse({value: elementManager.wrapValue(res)});
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
// 17 = JavascriptException
|
||||
sendError(e.name + ': ' + e.message, 17, e.stack);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to set the timeout of asynchronous scripts
|
||||
*/
|
||||
function setScriptTimeout(msg) {
|
||||
marionetteTimeout = msg.json.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute async script
|
||||
*/
|
||||
function executeAsyncScript(msg) {
|
||||
executeWithCallback(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute pure JS test. Handles both async and sync cases.
|
||||
*/
|
||||
function executeJSScript(msg) {
|
||||
if (msg.json.timeout) {
|
||||
executeWithCallback(msg, msg.json.timeout);
|
||||
}
|
||||
else {
|
||||
executeScript(msg, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is used by executeAsync and executeJSScript to execute a script
|
||||
* in a sandbox.
|
||||
*
|
||||
* For executeJSScript, it will return a message only when the finish() method is called.
|
||||
* For executeAsync, it will return a response when marionetteScriptFinished/arguments[arguments.length-1]
|
||||
* method is called, or if it times out.
|
||||
*/
|
||||
function executeWithCallback(msg, timeout) {
|
||||
win.addEventListener("unload", errUnload, false);
|
||||
let script = msg.json.value;
|
||||
let command_id = msg.json.id;
|
||||
|
||||
// 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.
|
||||
// However Selenium code returns 28, see
|
||||
// http://code.google.com/p/selenium/source/browse/trunk/javascript/firefox-driver/js/evaluate.js.
|
||||
// We'll stay compatible with the Selenium code.
|
||||
let timeoutId = win.setTimeout(function() {
|
||||
contentAsyncReturnFunc('timed out', 28);
|
||||
}, marionetteTimeout);
|
||||
win.addEventListener('error', function win__onerror(evt) {
|
||||
win.removeEventListener('error', win__onerror, true);
|
||||
contentAsyncReturnFunc(evt, 17);
|
||||
return true;
|
||||
}, true);
|
||||
|
||||
function contentAsyncReturnFunc(value, status) {
|
||||
win.removeEventListener("unload", errUnload, false);
|
||||
|
||||
/* clear all timeouts potentially generated by the script*/
|
||||
for(let i=0; i<=timeoutId; i++) {
|
||||
win.clearTimeout(i);
|
||||
}
|
||||
|
||||
sendSyncMessage("Marionette:testLog", {value: elementManager.wrapValue(marionetteLogObj.getLogs())});
|
||||
marionetteLogObj.clearLogs();
|
||||
if (status == 0){
|
||||
sendResponse({value: elementManager.wrapValue(value), status: status}, command_id);
|
||||
}
|
||||
else {
|
||||
sendError(value, status, null, command_id);
|
||||
}
|
||||
};
|
||||
|
||||
let scriptSrc;
|
||||
if (timeout) {
|
||||
if (marionetteTimeout == null || marionetteTimeout == 0) {
|
||||
sendError("Please set a timeout", 21, null);
|
||||
}
|
||||
scriptSrc = script;
|
||||
}
|
||||
else {
|
||||
scriptSrc = "let marionetteScriptFinished = function(value) { return asyncComplete(value,0);};" +
|
||||
"__marionetteParams.push(marionetteScriptFinished);" +
|
||||
"let __marionetteFunc = function() { " + script + "};" +
|
||||
"__marionetteFunc.apply(null, __marionetteParams); ";
|
||||
}
|
||||
|
||||
let marionette = new Marionette(true, win, "content", marionetteLogObj);
|
||||
|
||||
let sandbox = createExecuteContentSandbox(win, marionette, msg.json.args);
|
||||
if (!sandbox)
|
||||
return;
|
||||
|
||||
sandbox.asyncComplete = contentAsyncReturnFunc;
|
||||
sandbox.finish = function sandbox_finish() {
|
||||
contentAsyncReturnFunc(marionette.generate_results(), 0);
|
||||
};
|
||||
|
||||
try {
|
||||
Cu.evalInSandbox(scriptSrc, sandbox, "1.8");
|
||||
} catch (e) {
|
||||
// 17 = JavascriptException
|
||||
sendError(e.name + ': ' + e.message, 17, e.stack);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to set the timeout period for element searching
|
||||
*/
|
||||
function setSearchTimeout(msg) {
|
||||
try {
|
||||
elementManager.setSearchTimeout(msg.json.value);
|
||||
}
|
||||
catch (e) {
|
||||
sendError(e.message, e.num, e.stack);
|
||||
return;
|
||||
}
|
||||
sendOk();
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to URI. Handles the case where we navigate within an iframe.
|
||||
* All other navigation is handled by the server (in chrome space).
|
||||
*/
|
||||
function goUrl(msg) {
|
||||
if (activeFrame != null) {
|
||||
win.document.location = msg.json.value;
|
||||
//TODO: replace this with event firing when Bug 720714 is resolved
|
||||
let checkTimer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
|
||||
let checkLoad = function () {
|
||||
if (win.document.readyState == "complete") {
|
||||
sendOk();
|
||||
}
|
||||
else {
|
||||
checkTimer.initWithCallback(checkLoad, 100, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
};
|
||||
checkLoad();
|
||||
}
|
||||
else {
|
||||
sendAsyncMessage("Marionette:goUrl", {value: msg.json.value});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current URI
|
||||
*/
|
||||
function getUrl(msg) {
|
||||
sendResponse({value: win.location.href});
|
||||
}
|
||||
|
||||
/**
|
||||
* Go back in history
|
||||
*/
|
||||
function goBack(msg) {
|
||||
win.history.back();
|
||||
sendOk();
|
||||
}
|
||||
|
||||
/**
|
||||
* Go forward in history
|
||||
*/
|
||||
function goForward(msg) {
|
||||
win.history.forward();
|
||||
sendOk();
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the page
|
||||
*/
|
||||
function refresh(msg) {
|
||||
win.location.reload(true);
|
||||
let listen = function() { removeEventListener("DOMContentLoaded", arguments.callee, false); sendOk() } ;
|
||||
addEventListener("DOMContentLoaded", listen, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an element in the document using requested search strategy
|
||||
*/
|
||||
function findElementContent(msg) {
|
||||
//Todo: extend to support findChildElement
|
||||
let id;
|
||||
try {
|
||||
let notify = function(id) { sendResponse({value:id});};
|
||||
id = elementManager.find(msg.json, win.document, notify, false);
|
||||
}
|
||||
catch (e) {
|
||||
sendError(e.message, e.num, e.stack);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find elements in the document using requested search strategy
|
||||
*/
|
||||
function findElementsContent(msg) {
|
||||
//Todo: extend to support findChildElement
|
||||
let id;
|
||||
try {
|
||||
let notify = function(id) { sendResponse({value:id});};
|
||||
id = elementManager.find(msg.json, win.document, notify, true);
|
||||
}
|
||||
catch (e) {
|
||||
sendError(e.message, e.num, e.stack);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send click event to element
|
||||
*/
|
||||
function clickElement(msg) {
|
||||
let el;
|
||||
try {
|
||||
el = elementManager.getKnownElement(msg.json.element, win);
|
||||
}
|
||||
catch (e) {
|
||||
sendError(e.message, e.num, e.stack);
|
||||
return;
|
||||
}
|
||||
el.click();
|
||||
sendOk();
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to frame given either the server-assigned element id,
|
||||
* its index in window.frames, or the iframe's name or id.
|
||||
*/
|
||||
function switchToFrame(msg) {
|
||||
let foundFrame = null;
|
||||
if ((msg.json.value == null) && (msg.json.element == null)) {
|
||||
win = content;
|
||||
activeFrame = null;
|
||||
content.focus();
|
||||
sendOk();
|
||||
return;
|
||||
}
|
||||
if (msg.json.element != undefined) {
|
||||
if (elementManager.seenItems[msg.json.element] != undefined) {
|
||||
let wantedFrame = elementManager.getKnownElement(msg.json.element, win);//HTMLIFrameElement
|
||||
let numFrames = win.frames.length;
|
||||
for (let i = 0; i < numFrames; i++) {
|
||||
if (win.frames[i].frameElement == wantedFrame) {
|
||||
win = win.frames[i];
|
||||
activeFrame = i;
|
||||
win.focus();
|
||||
sendOk();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
switch(typeof(msg.json.value)) {
|
||||
case "string" :
|
||||
let foundById = null;
|
||||
let numFrames = win.frames.length;
|
||||
for (let i = 0; i < numFrames; i++) {
|
||||
//give precedence to name
|
||||
let frame = win.frames[i];
|
||||
let frameElement = frame.frameElement;
|
||||
if (frameElement.name == msg.json.value) {
|
||||
foundFrame = i;
|
||||
break;
|
||||
} else if ((foundById == null) && (frameElement.id == msg.json.value)) {
|
||||
foundById = i;
|
||||
}
|
||||
}
|
||||
if ((foundFrame == null) && (foundById != null)) {
|
||||
foundFrame = foundById;
|
||||
}
|
||||
break;
|
||||
case "number":
|
||||
if (win.frames[msg.json.value] != undefined) {
|
||||
foundFrame = msg.json.value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
//TODO: implement index
|
||||
if (foundFrame != null) {
|
||||
let frameWindow = win.frames[foundFrame];
|
||||
activeFrame = foundFrame;
|
||||
win = frameWindow;
|
||||
win.focus();
|
||||
sendOk();
|
||||
} else {
|
||||
sendError("Unable to locate frame: " + msg.json.value, 8, null);
|
||||
}
|
||||
}
|
||||
|
||||
//call register self when we get loaded
|
||||
registerSelf();
|
45
testing/marionette/marionette-log-obj.js
Normal file
45
testing/marionette/marionette-log-obj.js
Normal file
@ -0,0 +1,45 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function MarionetteLogObj() {
|
||||
this.logs = [];
|
||||
}
|
||||
MarionetteLogObj.prototype = {
|
||||
/**
|
||||
* Log message. Accepts user defined log-level.
|
||||
* @param msg String
|
||||
* The message to be logged
|
||||
* @param level String
|
||||
* The logging level to be used
|
||||
*/
|
||||
log: function ML_log(msg, level) {
|
||||
let lev = level ? level : "INFO";
|
||||
this.logs.push( [lev, msg, (new Date()).toString()]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a list of logs to its list
|
||||
* @param msgs Object
|
||||
* Takes a list of strings
|
||||
*/
|
||||
addLogs: function ML_addLogs(msgs) {
|
||||
for (let i = 0; i < msgs.length; i++) {
|
||||
this.logs.push(msgs[i]);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Return all logged messages.
|
||||
*/
|
||||
getLogs: function ML_getLogs() {
|
||||
return this.logs;
|
||||
},
|
||||
|
||||
/**
|
||||
* Clears the logs
|
||||
*/
|
||||
clearLogs: function ML_clearLogs() {
|
||||
this.logs = [];
|
||||
},
|
||||
}
|
131
testing/marionette/marionette-simpletest.js
Normal file
131
testing/marionette/marionette-simpletest.js
Normal file
@ -0,0 +1,131 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
/*
|
||||
* The Marionette object, passed to the script context.
|
||||
*/
|
||||
|
||||
function Marionette(is_async, window, context, logObj) {
|
||||
this.is_async = is_async;
|
||||
this.window = window;
|
||||
this.tests = [];
|
||||
this.logObj = logObj;
|
||||
this.context = context;
|
||||
this.exports = ['ok', 'is', 'isnot', 'log', 'getLogs', 'generate_results', 'waitFor'];
|
||||
}
|
||||
|
||||
Marionette.prototype = {
|
||||
ok: function Marionette__ok(condition, name, diag) {
|
||||
let test = {'result': !!condition, 'name': name, 'diag': diag};
|
||||
this.logResult(test, "TEST-PASS", "TEST-UNEXPECTED-FAIL");
|
||||
this.tests.push(test);
|
||||
},
|
||||
|
||||
is: function Marionette__is(a, b, name) {
|
||||
let pass = (a == b);
|
||||
let diag = pass ? this.repr(a) + " should equal " + this.repr(b)
|
||||
: "got " + this.repr(a) + ", expected " + this.repr(b);
|
||||
this.ok(pass, name, diag);
|
||||
},
|
||||
|
||||
isnot: function Marionette__isnot (a, b, name) {
|
||||
let pass = (a != b);
|
||||
let diag = pass ? this.repr(a) + " should not equal " + this.repr(b)
|
||||
: "didn't expect " + this.repr(a) + ", but got it";
|
||||
this.ok(pass, name, diag);
|
||||
},
|
||||
|
||||
log: function Marionette__log(msg, level) {
|
||||
if (this.logObj != null) {
|
||||
this.logObj.log(msg, level);
|
||||
}
|
||||
},
|
||||
|
||||
getLogs: function Marionette__getLogs() {
|
||||
if (this.logObj != null) {
|
||||
this.logObj.getLogs();
|
||||
}
|
||||
},
|
||||
|
||||
generate_results: function Marionette__generate_results() {
|
||||
let passed = 0;
|
||||
let failed = 0;
|
||||
let failures = [];
|
||||
for (let i in this.tests) {
|
||||
if(this.tests[i].result) {
|
||||
passed++;
|
||||
}
|
||||
else {
|
||||
failed++;
|
||||
failures.push({'name': this.tests[i].name,
|
||||
'diag': this.tests[i].diag});
|
||||
}
|
||||
}
|
||||
return {"passed": passed, "failed": failed, "failures": failures};
|
||||
},
|
||||
|
||||
logToFile: function Marionette__logToFile(file) {
|
||||
//TODO
|
||||
},
|
||||
|
||||
logResult: function Marionette__logResult(test, passString, failString) {
|
||||
//TODO: dump to file
|
||||
let resultString = test.result ? passString : failString;
|
||||
let diagnostic = test.name + (test.diag ? " - " + test.diag : "");
|
||||
let msg = [resultString, diagnostic].join(" | ");
|
||||
dump("MARIONETTE TEST RESULT:" + msg + "\n");
|
||||
},
|
||||
|
||||
repr: function Marionette__repr(o) {
|
||||
if (typeof(o) == "undefined") {
|
||||
return "undefined";
|
||||
} else if (o === null) {
|
||||
return "null";
|
||||
}
|
||||
try {
|
||||
if (typeof(o.__repr__) == 'function') {
|
||||
return o.__repr__();
|
||||
} else if (typeof(o.repr) == 'function' && o.repr != arguments.callee) {
|
||||
return o.repr();
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
try {
|
||||
if (typeof(o.NAME) == 'string' && (
|
||||
o.toString == Function.prototype.toString ||
|
||||
o.toString == Object.prototype.toString
|
||||
)) {
|
||||
return o.NAME;
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
let ostring;
|
||||
try {
|
||||
ostring = (o + "");
|
||||
} catch (e) {
|
||||
return "[" + typeof(o) + "]";
|
||||
}
|
||||
if (typeof(o) == "function") {
|
||||
o = ostring.replace(/^\s+/, "");
|
||||
let idx = o.indexOf("{");
|
||||
if (idx != -1) {
|
||||
o = o.substr(0, idx) + "{...}";
|
||||
}
|
||||
}
|
||||
return ostring;
|
||||
},
|
||||
|
||||
defaultWaitForTimeout: 10000,
|
||||
waitFor: function test_waitFor(callback, test, timeout) {
|
||||
if (test()) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
timeout = timeout || Date.now();
|
||||
if (Date.now() - timeout > this.defaultWaitForTimeout) {
|
||||
throw 'waitFor timeout';
|
||||
}
|
||||
this.window.setTimeout(this.waitFor.bind(this), 100, callback, test, timeout);
|
||||
},
|
||||
};
|
||||
|
17
testing/marionette/tests/Makefile.in
Normal file
17
testing/marionette/tests/Makefile.in
Normal file
@ -0,0 +1,17 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
relativesrcdir = testing/marionette/tests
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = test_marionette
|
||||
|
||||
XPCSHELL_TESTS = unit
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
11
testing/marionette/tests/unit/head_mar.js
Normal file
11
testing/marionette/tests/unit/head_mar.js
Normal file
@ -0,0 +1,11 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource:///modules/devtools/dbg-server.jsm");
|
||||
Cu.import("resource:///modules/devtools/dbg-client.jsm");
|
53
testing/marionette/tests/unit/test_marionette_err.js
Normal file
53
testing/marionette/tests/unit/test_marionette_err.js
Normal file
@ -0,0 +1,53 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function run_test()
|
||||
{
|
||||
//DebuggerServer.addActors("resource:///modules/marionette-actors.js");
|
||||
//DebuggerServer.init();
|
||||
|
||||
add_test(test_error);
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
function test_error()
|
||||
{
|
||||
//DebuggerServer.openListener(2828, true);
|
||||
do_test_pending();
|
||||
received = false;
|
||||
id = "";
|
||||
|
||||
let transport = debuggerSocketConnect("127.0.0.1", 2828);
|
||||
transport.hooks = {
|
||||
onPacket: function(aPacket) {
|
||||
this.onPacket = function(aPacket) {
|
||||
if (received) {
|
||||
do_check_eq(aPacket.from, id);
|
||||
if(aPacket.error == undefined) {
|
||||
do_throw("Expected error, instead received 'done' packet!");
|
||||
transport.close();
|
||||
}
|
||||
else {
|
||||
transport.close();
|
||||
}
|
||||
}
|
||||
else {
|
||||
received = true;
|
||||
id = aPacket.id;
|
||||
transport.send({to: id,
|
||||
type: "nonExistent",
|
||||
});
|
||||
}
|
||||
}
|
||||
transport.send({to: "root",
|
||||
type: "getMarionetteID",
|
||||
});
|
||||
},
|
||||
onClosed: function(aStatus) {
|
||||
do_check_eq(aStatus, 0);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
},
|
||||
};
|
||||
transport.ready();
|
||||
}
|
75
testing/marionette/tests/unit/test_marionette_exec.js
Normal file
75
testing/marionette/tests/unit/test_marionette_exec.js
Normal file
@ -0,0 +1,75 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function run_test()
|
||||
{
|
||||
//DebuggerServer.addActors("resource:///modules/marionette-actors.js");
|
||||
//DebuggerServer.init();
|
||||
|
||||
add_test(test_execute);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_execute()
|
||||
{
|
||||
//DebuggerServer.openListener(2828, true);
|
||||
do_test_pending();
|
||||
got_session = false;
|
||||
received = false;
|
||||
id = "";
|
||||
|
||||
let transport = debuggerSocketConnect("127.0.0.1", 2828);
|
||||
transport.hooks = {
|
||||
onPacket: function(aPacket) {
|
||||
this.onPacket = function(aPacket) {
|
||||
if(!got_session) {
|
||||
got_session=true;
|
||||
id = aPacket.id;
|
||||
transport.send({to: id,
|
||||
type: "newSession",
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (received) {
|
||||
do_check_eq(aPacket.from, id);
|
||||
if(aPacket.value == "3") {
|
||||
transport.send({to: id,
|
||||
type: "executeScript",
|
||||
value: "return 5+arguments[0];",
|
||||
args: [1],
|
||||
});
|
||||
}
|
||||
if(aPacket.value == "6") {
|
||||
transport.send({to: id,
|
||||
type: "deleteSession"
|
||||
});
|
||||
transport.close();
|
||||
}
|
||||
if(aPacket.error != undefined) {
|
||||
do_throw("Received error: " + aPacket.error);
|
||||
transport.close();
|
||||
}
|
||||
}
|
||||
else {
|
||||
received = true;
|
||||
do_check_eq('session', aPacket.value);
|
||||
transport.send({to: id,
|
||||
type: "executeScript",
|
||||
value: "alert('asdf'); return 2+1;",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
transport.send({to: "root",
|
||||
type: "getMarionetteID",
|
||||
});
|
||||
},
|
||||
onClosed: function(aStatus) {
|
||||
do_check_eq(aStatus, 0);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
delete transport;
|
||||
},
|
||||
};
|
||||
transport.ready();
|
||||
}
|
193
testing/marionette/tests/unit/test_marionette_execAsync.js
Normal file
193
testing/marionette/tests/unit/test_marionette_execAsync.js
Normal file
@ -0,0 +1,193 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function run_test()
|
||||
{
|
||||
add_test(test_executeAsync);
|
||||
add_test(test_executeAsyncTimeout);
|
||||
add_test(test_executeAsyncUnload); //TODO: fix unload listener
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_executeAsync()
|
||||
{
|
||||
do_test_pending();
|
||||
got_session = false;
|
||||
received = false;
|
||||
id = "";
|
||||
|
||||
let transport = debuggerSocketConnect("127.0.0.1", 2828);
|
||||
transport.hooks = {
|
||||
onPacket: function(aPacket) {
|
||||
this.onPacket = function(aPacket) {
|
||||
if(!got_session) {
|
||||
got_session=true;
|
||||
id = aPacket.id;
|
||||
transport.send({to: id,
|
||||
type: "newSession",
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (received) {
|
||||
do_check_eq(aPacket.from, id);
|
||||
if(aPacket.ok == true) {
|
||||
transport.send({to: id,
|
||||
type: "executeAsyncScript",
|
||||
value: "arguments[arguments.length - 1](5+1);",
|
||||
});
|
||||
}
|
||||
else if(aPacket.value == "6") {
|
||||
transport.send({to: id,
|
||||
type: "deleteSession",
|
||||
});
|
||||
transport.close();
|
||||
}
|
||||
else if(aPacket.error != undefined) {
|
||||
do_throw("Received error: " + aPacket.error);
|
||||
transport.close();
|
||||
}
|
||||
}
|
||||
else {
|
||||
received = true;
|
||||
do_check_eq('session', aPacket.value);
|
||||
transport.send({to: id,
|
||||
type: "setScriptTimeout",
|
||||
value: "2000",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
transport.send({to: "root",
|
||||
type: "getMarionetteID",
|
||||
});
|
||||
},
|
||||
onClosed: function(aStatus) {
|
||||
do_check_eq(aStatus, 0);
|
||||
do_test_finished();
|
||||
delete transport;
|
||||
run_next_test();
|
||||
},
|
||||
};
|
||||
transport.ready();
|
||||
}
|
||||
|
||||
function test_executeAsyncTimeout()
|
||||
{
|
||||
do_test_pending();
|
||||
got_session = false;
|
||||
received = false;
|
||||
id = "";
|
||||
|
||||
let transport = debuggerSocketConnect("127.0.0.1", 2828);
|
||||
transport.hooks = {
|
||||
onPacket: function(aPacket) {
|
||||
this.onPacket = function(aPacket) {
|
||||
if(!got_session) {
|
||||
got_session=true;
|
||||
id = aPacket.id;
|
||||
transport.send({to: id,
|
||||
type: "newSession",
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (received) {
|
||||
do_check_eq(aPacket.from, id);
|
||||
if(aPacket.ok == true) {
|
||||
transport.send({to: id,
|
||||
type: "executeAsyncScript",
|
||||
value: "window.setTimeout(arguments[arguments.length - 1], 5000, 6);",
|
||||
});
|
||||
}
|
||||
else if(aPacket.value == "6") {
|
||||
do_throw("Should have timed out!");
|
||||
transport.close();
|
||||
}
|
||||
else if(aPacket.error != undefined) {
|
||||
do_check_eq(aPacket.error.message, "timed out");
|
||||
do_check_eq(aPacket.error.status, 28);
|
||||
transport.close();
|
||||
}
|
||||
}
|
||||
else {
|
||||
received = true;
|
||||
do_check_eq('session', aPacket.value);
|
||||
transport.send({to: id,
|
||||
type: "setScriptTimeout",
|
||||
value: "2000",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
transport.send({to: "root",
|
||||
type: "getMarionetteID",
|
||||
});
|
||||
},
|
||||
onClosed: function(aStatus) {
|
||||
do_check_eq(aStatus, 0);
|
||||
do_test_finished();
|
||||
delete transport;
|
||||
run_next_test();
|
||||
},
|
||||
};
|
||||
transport.ready();
|
||||
}
|
||||
|
||||
function test_executeAsyncUnload()
|
||||
{
|
||||
do_test_pending();
|
||||
got_session = false;
|
||||
received = false;
|
||||
id = "";
|
||||
|
||||
let transport = debuggerSocketConnect("127.0.0.1", 2828);
|
||||
transport.hooks = {
|
||||
onPacket: function(aPacket) {
|
||||
this.onPacket = function(aPacket) {
|
||||
if(!got_session) {
|
||||
got_session=true;
|
||||
id = aPacket.id;
|
||||
transport.send({to: id,
|
||||
type: "newSession",
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (received) {
|
||||
do_check_eq(aPacket.from, id);
|
||||
if(aPacket.ok == true) {
|
||||
transport.send({to: id,
|
||||
type: "executeAsyncScript",
|
||||
value: "window.location.reload();",
|
||||
});
|
||||
}
|
||||
else if(aPacket.value == "6") {
|
||||
do_throw("Should have thrown unload error!");
|
||||
transport.close();
|
||||
}
|
||||
else if(aPacket.error != undefined) {
|
||||
do_check_eq(aPacket.error.status, 17);
|
||||
transport.close();
|
||||
}
|
||||
}
|
||||
else {
|
||||
received = true;
|
||||
do_check_eq('session', aPacket.value);
|
||||
transport.send({to: id,
|
||||
type: "setScriptTimeout",
|
||||
value: "2000",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
transport.send({to: "root",
|
||||
type: "getMarionetteID",
|
||||
});
|
||||
},
|
||||
onClosed: function(aStatus) {
|
||||
do_check_eq(aStatus, 0);
|
||||
do_test_finished();
|
||||
delete transport;
|
||||
run_next_test();
|
||||
},
|
||||
};
|
||||
transport.ready();
|
||||
}
|
365
testing/marionette/tests/unit/test_marionette_execjs.js
Normal file
365
testing/marionette/tests/unit/test_marionette_execjs.js
Normal file
@ -0,0 +1,365 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function run_test()
|
||||
{
|
||||
add_test(test_execute);
|
||||
add_test(test_execute_async);
|
||||
add_test(test_execute_async_timeout);
|
||||
add_test(test_execute_chrome);
|
||||
add_test(test_execute_async_chrome);
|
||||
add_test(test_execute_async_timeout_chrome);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_execute()
|
||||
{
|
||||
do_test_pending();
|
||||
got_session = false;
|
||||
received = false;
|
||||
id = "";
|
||||
|
||||
let transport = debuggerSocketConnect("127.0.0.1", 2828);
|
||||
transport.hooks = {
|
||||
onPacket: function(aPacket) {
|
||||
this.onPacket = function(aPacket) {
|
||||
if(!got_session) {
|
||||
got_session=true;
|
||||
id = aPacket.id;
|
||||
transport.send({to: id,
|
||||
type: "newSession",
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (received) {
|
||||
do_check_eq(aPacket.from, id);
|
||||
do_check_eq(aPacket.value.passed, 1);
|
||||
do_check_eq(aPacket.value.failed, 0);
|
||||
transport.close();
|
||||
}
|
||||
else {
|
||||
received = true;
|
||||
do_check_eq('mobile', aPacket.value);
|
||||
transport.send({to: id,
|
||||
type: "executeJSScript",
|
||||
value: "Marionette.is(1,1, 'should return 1'); Marionette.finish();",
|
||||
timeout: false
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
transport.send({to: "root",
|
||||
type: "getMarionetteID",
|
||||
});
|
||||
},
|
||||
onClosed: function(aStatus) {
|
||||
do_check_eq(aStatus, 0);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
delete transport;
|
||||
},
|
||||
};
|
||||
transport.ready();
|
||||
}
|
||||
|
||||
function test_execute_async()
|
||||
{
|
||||
do_test_pending();
|
||||
got_session = false;
|
||||
received = false;
|
||||
received2 = false;
|
||||
id = "";
|
||||
|
||||
let transport = debuggerSocketConnect("127.0.0.1", 2828);
|
||||
transport.hooks = {
|
||||
onPacket: function(aPacket) {
|
||||
this.onPacket = function(aPacket) {
|
||||
if(!got_session) {
|
||||
got_session=true;
|
||||
id = aPacket.id;
|
||||
transport.send({to: id,
|
||||
type: "newSession",
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (received) {
|
||||
if(received2) {
|
||||
do_check_eq(aPacket.from, id);
|
||||
do_check_eq(aPacket.value.passed, 1);
|
||||
do_check_eq(aPacket.value.failed, 0);
|
||||
transport.close();
|
||||
}
|
||||
else {
|
||||
received2 = true;
|
||||
transport.send({to: id,
|
||||
type: "executeJSScript",
|
||||
value: "Marionette.is(1,1, 'should return 1'); Marionette.finish();",
|
||||
timeout: true
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
received = true;
|
||||
do_check_eq('mobile', aPacket.value);
|
||||
transport.send({to: id,
|
||||
type: "setScriptTimeout",
|
||||
value: "2000",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
transport.send({to: "root",
|
||||
type: "getMarionetteID",
|
||||
});
|
||||
},
|
||||
onClosed: function(aStatus) {
|
||||
do_check_eq(aStatus, 0);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
delete transport;
|
||||
},
|
||||
};
|
||||
transport.ready();
|
||||
}
|
||||
|
||||
function test_execute_async_timeout()
|
||||
{
|
||||
do_test_pending();
|
||||
got_session = false;
|
||||
received = false;
|
||||
received2 = false;
|
||||
id = "";
|
||||
|
||||
let transport = debuggerSocketConnect("127.0.0.1", 2828);
|
||||
transport.hooks = {
|
||||
onPacket: function(aPacket) {
|
||||
this.onPacket = function(aPacket) {
|
||||
if(!got_session) {
|
||||
got_session=true;
|
||||
id = aPacket.id;
|
||||
transport.send({to: id,
|
||||
type: "newSession",
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (received) {
|
||||
if(received2) {
|
||||
do_check_eq(aPacket.from, id);
|
||||
do_check_eq(aPacket.error.status, 28);
|
||||
transport.close();
|
||||
}
|
||||
else {
|
||||
received2 = true;
|
||||
transport.send({to: id,
|
||||
type: "executeJSScript",
|
||||
value: "Marionette.is(1,1, 'should return 1');",
|
||||
timeout: true
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
received = true;
|
||||
do_check_eq('mobile', aPacket.value);
|
||||
transport.send({to: id,
|
||||
type: "setScriptTimeout",
|
||||
value: "2000",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
transport.send({to: "root",
|
||||
type: "getMarionetteID",
|
||||
});
|
||||
},
|
||||
onClosed: function(aStatus) {
|
||||
do_check_eq(aStatus, 0);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
delete transport;
|
||||
},
|
||||
};
|
||||
transport.ready();
|
||||
}
|
||||
|
||||
function test_execute_chrome()
|
||||
{
|
||||
do_test_pending();
|
||||
got_session = false;
|
||||
got_context = false;
|
||||
received = false;
|
||||
id = "";
|
||||
|
||||
let transport = debuggerSocketConnect("127.0.0.1", 2828);
|
||||
transport.hooks = {
|
||||
onPacket: function(aPacket) {
|
||||
this.onPacket = function(aPacket) {
|
||||
if(!got_session) {
|
||||
got_session=true;
|
||||
id = aPacket.id;
|
||||
transport.send({to: id,
|
||||
type: "newSession",
|
||||
});
|
||||
}
|
||||
else if (!got_context) {
|
||||
got_context = true;
|
||||
do_check_eq('mobile', aPacket.value);
|
||||
transport.send({to: id,
|
||||
type: "setContext",
|
||||
value: "chrome",
|
||||
});
|
||||
}
|
||||
else if (!received) {
|
||||
received = true;
|
||||
transport.send({to: id,
|
||||
type: "executeJSScript",
|
||||
value: "Marionette.is(1,1, 'should return 1'); Marionette.finish();",
|
||||
timeout: false
|
||||
});
|
||||
}
|
||||
else {
|
||||
do_check_eq(aPacket.from, id);
|
||||
do_check_eq(aPacket.value.passed, 1);
|
||||
do_check_eq(aPacket.value.failed, 0);
|
||||
transport.close();
|
||||
}
|
||||
}
|
||||
transport.send({to: "root",
|
||||
type: "getMarionetteID",
|
||||
});
|
||||
},
|
||||
onClosed: function(aStatus) {
|
||||
do_check_eq(aStatus, 0);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
delete transport;
|
||||
},
|
||||
};
|
||||
transport.ready();
|
||||
}
|
||||
|
||||
function test_execute_async_chrome()
|
||||
{
|
||||
do_test_pending();
|
||||
got_session = false;
|
||||
got_context = false;
|
||||
received = false;
|
||||
received2 = false;
|
||||
id = "";
|
||||
|
||||
let transport = debuggerSocketConnect("127.0.0.1", 2828);
|
||||
transport.hooks = {
|
||||
onPacket: function(aPacket) {
|
||||
this.onPacket = function(aPacket) {
|
||||
if(!got_session) {
|
||||
got_session=true;
|
||||
id = aPacket.id;
|
||||
transport.send({to: id,
|
||||
type: "newSession",
|
||||
});
|
||||
}
|
||||
else if (!got_context) {
|
||||
got_context = true;
|
||||
do_check_eq('mobile', aPacket.value);
|
||||
transport.send({to: id,
|
||||
type: "setContext",
|
||||
value: "chrome",
|
||||
});
|
||||
}
|
||||
else if (!received) {
|
||||
received = true;
|
||||
transport.send({to: id,
|
||||
type: "setScriptTimeout",
|
||||
value: "2000",
|
||||
});
|
||||
}
|
||||
else if (!received2) {
|
||||
received2 = true;
|
||||
transport.send({to: id,
|
||||
type: "executeJSScript",
|
||||
value: "Marionette.is(1,1, 'should return 1'); Marionette.finish();",
|
||||
timeout: true
|
||||
});
|
||||
}
|
||||
else {
|
||||
do_check_eq(aPacket.from, id);
|
||||
do_check_eq(aPacket.value.passed, 1);
|
||||
do_check_eq(aPacket.value.failed, 0);
|
||||
transport.close();
|
||||
}
|
||||
}
|
||||
transport.send({to: "root",
|
||||
type: "getMarionetteID",
|
||||
});
|
||||
},
|
||||
onClosed: function(aStatus) {
|
||||
do_check_eq(aStatus, 0);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
delete transport;
|
||||
},
|
||||
};
|
||||
transport.ready();
|
||||
}
|
||||
|
||||
function test_execute_async_timeout_chrome()
|
||||
{
|
||||
do_test_pending();
|
||||
got_session = false;
|
||||
got_context = false;
|
||||
received = false;
|
||||
received2 = false;
|
||||
id = "";
|
||||
|
||||
let transport = debuggerSocketConnect("127.0.0.1", 2828);
|
||||
transport.hooks = {
|
||||
onPacket: function(aPacket) {
|
||||
this.onPacket = function(aPacket) {
|
||||
if(!got_session) {
|
||||
got_session=true;
|
||||
id = aPacket.id;
|
||||
transport.send({to: id,
|
||||
type: "newSession",
|
||||
});
|
||||
}
|
||||
else if (!got_context) {
|
||||
got_context = true;
|
||||
do_check_eq('mobile', aPacket.value);
|
||||
transport.send({to: id,
|
||||
type: "setContext",
|
||||
value: "chrome",
|
||||
});
|
||||
}
|
||||
else if (!received) {
|
||||
received = true;
|
||||
transport.send({to: id,
|
||||
type: "setScriptTimeout",
|
||||
value: "2000",
|
||||
});
|
||||
}
|
||||
else if (!received2) {
|
||||
received2 = true;
|
||||
transport.send({to: id,
|
||||
type: "executeJSScript",
|
||||
value: "Marionette.is(1,1, 'should return 1');",
|
||||
timeout: true
|
||||
});
|
||||
}
|
||||
else {
|
||||
do_check_eq(aPacket.from, id);
|
||||
do_check_eq(aPacket.error.status, 28);
|
||||
transport.close();
|
||||
}
|
||||
}
|
||||
transport.send({to: "root",
|
||||
type: "getMarionetteID",
|
||||
});
|
||||
},
|
||||
onClosed: function(aStatus) {
|
||||
do_check_eq(aStatus, 0);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
delete transport;
|
||||
},
|
||||
};
|
||||
transport.ready();
|
||||
}
|
8
testing/marionette/tests/unit/xpcshell.ini
Normal file
8
testing/marionette/tests/unit/xpcshell.ini
Normal file
@ -0,0 +1,8 @@
|
||||
[DEFAULT]
|
||||
head = head_mar.js
|
||||
tail =
|
||||
|
||||
[test_marionette_exec.js]
|
||||
[test_marionette_execjs.js]
|
||||
[test_marionette_execAsync.js]
|
||||
[test_marionette_err.js]
|
@ -46,6 +46,7 @@ skip-if = os == "android"
|
||||
[include:toolkit/mozapps/update/test_svc/unit/xpcshell.ini]
|
||||
[include:toolkit/mozapps/update/test/unit/xpcshell.ini]
|
||||
[include:security/manager/ssl/tests/unit/xpcshell.ini]
|
||||
[include:testing/marionette/tests/unit/xpcshell.ini]
|
||||
[include:testing/xpcshell/example/unit/xpcshell.ini]
|
||||
[include:xpcom/tests/unit/xpcshell.ini]
|
||||
[include:modules/libpref/test/unit/xpcshell.ini]
|
||||
|
@ -273,6 +273,10 @@ ifdef MOZ_MAPINFO
|
||||
tier_platform_dirs += tools/codesighs
|
||||
endif
|
||||
|
||||
ifdef ENABLE_MARIONETTE
|
||||
tier_platform_dirs += testing/marionette
|
||||
endif
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
tier_platform_dirs += testing/mochitest
|
||||
tier_platform_dirs += testing/xpcshell
|
||||
|
Loading…
Reference in New Issue
Block a user