--- a/testing/mochitest/browser-test.js
+++ b/testing/mochitest/browser-test.js
@@ -107,20 +107,17 @@ Tester.prototype = {
},
waitForWindowsState: function Tester_waitForWindowsState(aCallback) {
let timedOut = this.currentTest && this.currentTest.timedOut;
let baseMsg = timedOut ? "Found a {elt} after previous test timed out"
: this.currentTest ? "Found an unexpected {elt} at the end of test run"
: "Found an unexpected {elt}";
- if (gConfig.testRoot == "browser" &&
- this.currentTest &&
- window.gBrowser &&
- gBrowser.tabs.length > 1) {
+ if (this.currentTest && window.gBrowser && gBrowser.tabs.length > 1) {
while (gBrowser.tabs.length > 1) {
let lastTab = gBrowser.tabContainer.lastChild;
let msg = baseMsg.replace("{elt}", "tab") +
": " + lastTab.linkedBrowser.currentURI.spec;
this.currentTest.addResult(new testResult(false, msg, "", false));
gBrowser.removeTab(lastTab);
}
}
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -631,17 +631,17 @@ class Mochitest(object):
self.urlOpts.append("testname=%s" % ("/").join([self.TEST_PATH, options.testPath]))
if options.testManifest:
self.urlOpts.append("testManifest=%s" % options.testManifest)
if hasattr(options, 'runOnly') and options.runOnly:
self.urlOpts.append("runOnly=true")
else:
self.urlOpts.append("runOnly=false")
if options.failureFile:
- self.urlOpts.append("failureFile=%s" % options.failureFile)
+ self.urlOpts.append("failureFile=%s" % self.getFullPath(options.failureFile))
def cleanup(self, manifest, options):
""" remove temporary files and profile """
os.remove(manifest)
shutil.rmtree(options.profilePath)
def startVMwareRecording(self, options):
""" starts recording inside VMware VM using the recording helper dll """
--- a/testing/mochitest/tests/SimpleTest/setup.js
+++ b/testing/mochitest/tests/SimpleTest/setup.js
@@ -82,22 +82,22 @@ if (params.repeat) {
}
// closeWhenDone tells us to close the browser when complete
if (params.closeWhenDone) {
TestRunner.onComplete = SpecialPowers.quit;
}
if (params.failureFile) {
- TestRunner.setFailureFile(params.failureFile);
+ TestRunner.setFailureFile(params.failureFile[0]);
}
// logFile to write our results
if (params.logFile) {
- var spl = new SpecialPowersLogger(params.logFile);
+ var spl = new SpecialPowersLogger(params.logFile[0]);
TestRunner.logger.addListener("mozLogger", fileLevel + "", spl.getLogCallback());
}
// if we get a quiet param, don't log to the console
if (!params.quiet) {
function dumpListener(msg) {
dump(msg.num + " " + msg.level + " " + msg.info.join(' ') + "\n");
}
--- a/webapprt/CommandLineHandler.js
+++ b/webapprt/CommandLineHandler.js
@@ -3,127 +3,69 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://webapprt/modules/WebappRT.jsm");
function CommandLineHandler() {}
CommandLineHandler.prototype = {
classID: Components.ID("{6d69c782-40a3-469b-8bfd-3ee366105a4a}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
handle: function handle(cmdLine) {
let args = Cc["@mozilla.org/hash-property-bag;1"].
createInstance(Ci.nsIWritablePropertyBag);
let inTestMode = this._handleTestMode(cmdLine, args);
- Services.obs.notifyObservers(args, "webapprt-command-line", null);
- // Initialize DOMApplicationRegistry by importing Webapps.jsm, but only
- // after broadcasting webapprt-command-line. Webapps.jsm calls
- // DOMApplicationRegistry.init() when it's first imported. init() accesses
- // the WebappRegD directory, which in test mode is special-cased by
- // DirectoryProvider.js after it observes webapprt-command-line.
- Cu.import("resource://gre/modules/Webapps.jsm");
-
- if (!inTestMode) {
- startUp(inTestMode);
+ if (inTestMode) {
+ // Open the mochitest shim window, which configures the runtime for tests.
+ Services.ww.openWindow(null,
+ "chrome://webapprt/content/mochitest.xul",
+ "_blank",
+ "chrome,dialog=no",
+ args);
} else {
- DOMApplicationRegistry.allAppsLaunchable = true;
-
- // startUp() accesses WebappRT.config, which in test mode is not valid
- // until WebappRT.jsm observes an app installation.
- Services.obs.addObserver(function onInstall(subj, topic, data) {
- Services.obs.removeObserver(onInstall, "webapprt-test-did-install");
- startUp(inTestMode);
- }, "webapprt-test-did-install", false);
+ args.setProperty("url", WebappRT.launchURI.spec);
+ Services.ww.openWindow(null,
+ "chrome://webapprt/content/webapp.xul",
+ "_blank",
+ "chrome,dialog=no,resizable,scrollbars,centerscreen",
+ args);
}
-
- // Open the window with arguments to identify it as the main window
- Services.ww.openWindow(null,
- "chrome://webapprt/content/webapp.xul",
- "_blank",
- "chrome,dialog=no,resizable,scrollbars,centerscreen",
- args);
},
_handleTestMode: function _handleTestMode(cmdLine, args) {
// -test-mode [url]
let idx = cmdLine.findFlag("test-mode", true);
if (idx < 0)
return false;
- let url = null;
+ let url;
let urlIdx = idx + 1;
if (urlIdx < cmdLine.length) {
let potentialURL = cmdLine.getArgument(urlIdx);
if (potentialURL && potentialURL[0] != "-") {
- url = potentialURL;
try {
- Services.io.newURI(url, null, null);
+ url = Services.io.newURI(potentialURL, null, null);
} catch (err) {
throw Components.Exception(
- "-test-mode argument is not a valid URL: " + url,
+ "-test-mode argument is not a valid URL: " + potentialURL,
Components.results.NS_ERROR_INVALID_ARG);
}
cmdLine.removeArguments(urlIdx, urlIdx);
+ args.setProperty("url", url.spec);
}
}
cmdLine.removeArguments(idx, idx);
- args.setProperty("test-mode", url);
return true;
},
helpInfo : "",
};
let components = [CommandLineHandler];
let NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
-
-/* There's some work we need to do on startup, before we load the webapp,
- * and this seems as good a place as any to do it, although it's possible
- * that in the future we will find a lazier place to do it.
- *
- * NOTE: it's very important that the stuff we do here doesn't prevent
- * the command-line handler from being registered/accessible, since otherwise
- * the app won't start, which is catastrophic failure. That's why it's all
- * wrapped in a try/catch block. */
-function startUp(inTestMode) {
- try {
- if (!inTestMode) {
- // Initialize window-independent handling of webapps- notifications. Skip
- // this in test mode, since it interferes with test app installations.
- // We'll have to revisit this when we actually want to test installations
- // and other functionality provided by WebappsHandler.
- Cu.import("resource://webapprt/modules/WebappsHandler.jsm");
- WebappsHandler.init();
- }
-
- // On firstrun, set permissions to their default values.
- if (!Services.prefs.getBoolPref("webapprt.firstrun")) {
- Cu.import("resource://webapprt/modules/WebappRT.jsm");
- let uri = Services.io.newURI(WebappRT.config.app.origin, null, null);
-
- // Set AppCache-related permissions.
- Services.perms.add(uri, "pin-app",
- Ci.nsIPermissionManager.ALLOW_ACTION);
- Services.perms.add(uri, "offline-app",
- Ci.nsIPermissionManager.ALLOW_ACTION);
-
- Services.perms.add(uri, "indexedDB",
- Ci.nsIPermissionManager.ALLOW_ACTION);
- Services.perms.add(uri, "indexedDB-unlimited",
- Ci.nsIPermissionManager.ALLOW_ACTION);
-
- // Now that we've set the appropriate permissions, twiddle the firstrun
- // flag so we don't try to do so again.
- Services.prefs.setBoolPref("webapprt.firstrun", true);
- }
- } catch(ex) {
-#ifdef MOZ_DEBUG
- dump(ex + "\n");
-#endif
- }
-}
--- a/webapprt/DirectoryProvider.js
+++ b/webapprt/DirectoryProvider.js
@@ -9,40 +9,26 @@ const Cu = Components.utils;
const WEBAPP_REGISTRY_DIR = "WebappRegD";
const NS_APP_CHROME_DIR_LIST = "AChromDL";
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://webapprt/modules/WebappRT.jsm");
Cu.import("resource://gre/modules/Services.jsm");
-let gInTestMode = false;
-Services.obs.addObserver(function observe(subj, topic, data) {
- Services.obs.removeObserver(observe, "webapprt-command-line");
- let args = subj.QueryInterface(Ci.nsIPropertyBag2);
- gInTestMode = args.hasKey("test-mode");
-}, "webapprt-command-line", false);
-
function DirectoryProvider() {}
DirectoryProvider.prototype = {
classID: Components.ID("{e1799fda-4b2f-4457-b671-e0641d95698d}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider,
Ci.nsIDirectoryServiceProvider2]),
getFile: function(prop, persistent) {
if (prop == WEBAPP_REGISTRY_DIR) {
- if (gInTestMode) {
- // In test mode, apps are registered in the runtime's profile. Note
- // that in test mode WebappRT.config may not be valid at this point.
- // It's only valid after WebappRT.jsm observes an app installation, and
- // we can get here before any app is installed.
- return FileUtils.getDir("ProfD", []);
- }
let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
dir.initWithPath(WebappRT.config.registryDir);
return dir;
}
// We return null to show failure instead of throwing an error,
// which works with the way the interface is called (per bug 529077).
return null;
--- a/webapprt/Makefile.in
+++ b/webapprt/Makefile.in
@@ -34,16 +34,17 @@ EXTRA_PP_COMPONENTS = \
components.manifest \
CommandLineHandler.js \
ContentPermission.js \
ContentPolicy.js \
DirectoryProvider.js \
$(NULL)
EXTRA_JS_MODULES = \
+ Startup.jsm \
WebappRT.jsm \
WebappsHandler.jsm \
$(NULL)
PREF_JS_EXPORTS = $(srcdir)/prefs.js \
$(NULL)
TEST_DIRS += \
new file mode 100644
--- /dev/null
+++ b/webapprt/Startup.jsm
@@ -0,0 +1,44 @@
+/* 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/. */
+
+/* This is imported by each new webapp window but is only evaluated the first
+ * time it is imported. Put stuff here that you want to happen once on startup
+ * before the webapp is loaded. But note that the "stuff" happens immediately
+ * the first time this module is imported. So only put stuff here that must
+ * happen before the webapp is loaded. */
+
+const EXPORTED_SYMBOLS = [];
+
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+// Initialize DOMApplicationRegistry by importing Webapps.jsm.
+Cu.import("resource://gre/modules/Webapps.jsm");
+
+// Initialize window-independent handling of webapps- notifications.
+Cu.import("resource://webapprt/modules/WebappsHandler.jsm");
+WebappsHandler.init();
+
+// On firstrun, set permissions to their default values.
+if (!Services.prefs.getBoolPref("webapprt.firstrun")) {
+ Cu.import("resource://webapprt/modules/WebappRT.jsm");
+ let uri = Services.io.newURI(WebappRT.config.app.origin, null, null);
+
+ // Set AppCache-related permissions.
+ Services.perms.add(uri, "pin-app",
+ Ci.nsIPermissionManager.ALLOW_ACTION);
+ Services.perms.add(uri, "offline-app",
+ Ci.nsIPermissionManager.ALLOW_ACTION);
+
+ Services.perms.add(uri, "indexedDB",
+ Ci.nsIPermissionManager.ALLOW_ACTION);
+ Services.perms.add(uri, "indexedDB-unlimited",
+ Ci.nsIPermissionManager.ALLOW_ACTION);
+
+ // Now that we've set the appropriate permissions, twiddle the firstrun
+ // flag so we don't try to do so again.
+ Services.prefs.setBoolPref("webapprt.firstrun", true);
+}
--- a/webapprt/WebappRT.jsm
+++ b/webapprt/WebappRT.jsm
@@ -16,64 +16,45 @@ XPCOMUtils.defineLazyGetter(this, "FileU
return FileUtils;
});
XPCOMUtils.defineLazyGetter(this, "DOMApplicationRegistry", function() {
Cu.import("resource://gre/modules/Webapps.jsm");
return DOMApplicationRegistry;
});
-// In test mode, observe webapps-ask-install so tests can install apps.
-Services.obs.addObserver(function observeCmdLine(subj, topic, data) {
- Services.obs.removeObserver(observeCmdLine, "webapprt-command-line");
- let args = subj.QueryInterface(Ci.nsIPropertyBag2);
- if (!args.hasKey("test-mode"))
- return;
- Services.obs.addObserver(function observeInstall(subj, topic, data) {
- // observeInstall is present for the lifetime of the runtime.
- let config = JSON.parse(data);
- config.registryDir = Services.dirsvc.get("ProfD", Ci.nsIFile).path;
- DOMApplicationRegistry.confirmInstall(config);
- delete WebappRT.config;
- WebappRT.config = deepFreeze(config);
- Services.obs.notifyObservers(null, "webapprt-test-did-install",
- JSON.stringify(config));
- }, "webapps-ask-install", false);
-}, "webapprt-command-line", false);
+let WebappRT = {
+ _config: null,
-let WebappRT = {
get config() {
+ if (this._config)
+ return this._config;
+
+ let config;
let webappFile = FileUtils.getFile("AppRegD", ["webapp.json"]);
+
let inputStream = Cc["@mozilla.org/network/file-input-stream;1"].
createInstance(Ci.nsIFileInputStream);
inputStream.init(webappFile, -1, 0, 0);
let json = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
- let config = json.decodeFromStream(inputStream, webappFile.fileSize);
+ config = json.decodeFromStream(inputStream, webappFile.fileSize);
+
+ return this._config = config;
+ },
- // Memoize the getter, freezing the `config` object in the meantime so
- // consumers don't inadvertently (or intentionally) change it, as the object
- // is meant to be a read-only representation of the webapp's configuration.
- config = deepFreeze(config);
- delete this.config;
- Object.defineProperty(this, "config", { get: function getConfig() config });
- return this.config;
+ // This exists to support test mode, which installs webapps after startup.
+ // Ideally we wouldn't have to have a setter, as tests can just delete
+ // the getter and then set the property. But the object to which they set it
+ // will have a reference to its global object, so our reference to it
+ // will leak that object (per bug 780674). The setter enables us to clone
+ // the new value so we don't actually retain a reference to it.
+ set config(newVal) {
+ this._config = JSON.parse(JSON.stringify(newVal));
+ },
+
+ get launchURI() {
+ let url = Services.io.newURI(this.config.app.origin, null, null);
+ if (this.config.app.manifest.launch_path) {
+ url = Services.io.newURI(this.config.app.manifest.launch_path, null, url);
+ }
+ return url;
}
};
-
-function deepFreeze(o) {
- // First, freeze the object.
- Object.freeze(o);
-
- // Then recursively call deepFreeze() to freeze its properties.
- for (let p in o) {
- // If the object is on the prototype, not an object, or is already frozen,
- // skip it. Note that this might leave an unfrozen reference somewhere in
- // the object if there is an already frozen object containing an unfrozen
- // object.
- if (!o.hasOwnProperty(p) || !(typeof o[p] == "object") ||
- Object.isFrozen(o[p]))
- continue;
-
- deepFreeze(o[p]);
- }
-
- return o;
-}
new file mode 100644
--- /dev/null
+++ b/webapprt/content/mochitest.js
@@ -0,0 +1,74 @@
+/* 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/. */
+
+/* Note: this script is loaded by both mochitest.xul and head.js, so make sure
+ * the code you put here can be evaluated by both! */
+
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://webapprt/modules/WebappRT.jsm");
+
+const MANIFEST_URL_BASE = Services.io.newURI(
+ "http://mochi.test:8888/webapprtChrome/webapprt/test/chrome/", null, null);
+
+// When WebappsHandler opens an install confirmation dialog for apps we install,
+// close it, which will be seen as the equivalent of cancelling the install.
+// This doesn't prevent us from installing those apps, as we listen for the same
+// notification as WebappsHandler and do the install ourselves. It just
+// prevents the modal installation confirmation dialogs from hanging tests.
+Services.ww.registerNotification({
+ observe: function(win, topic) {
+ if (topic == "domwindowopened") {
+ // Wait for load because the window is not yet sufficiently initialized.
+ win.addEventListener("load", function onLoadWindow() {
+ win.removeEventListener("load", onLoadWindow, false);
+ if (win.location == "chrome://global/content/commonDialog.xul" &&
+ win.opener == window) {
+ win.close();
+ }
+ }, false);
+ }
+ }
+});
+
+/**
+ * Transmogrify the runtime session into one for the given webapp.
+ *
+ * @param {String} manifestURL
+ * The URL of the webapp's manifest, relative to the base URL.
+ * Note that the base URL points to the *chrome* WebappRT mochitests,
+ * so you must supply an absolute URL to manifests elsewhere.
+ * @param {Object} parameters
+ * The value to pass as the "parameters" argument to
+ * mozIDOMApplicationRegistry.install, e.g., { receipts: ... }.
+ * Use undefined to pass nothing.
+ * @param {Function} onBecome
+ * The callback to call once the transmogrification is complete.
+ */
+function becomeWebapp(manifestURL, parameters, onBecome) {
+ function observeInstall(subj, topic, data) {
+ Services.obs.removeObserver(observeInstall, "webapps-ask-install");
+
+ // Step 2: Configure the runtime session to represent the app.
+ // We load DOMApplicationRegistry into a local scope to avoid appearing
+ // to leak it.
+
+ let scope = {};
+ Cu.import("resource://gre/modules/Webapps.jsm", scope);
+ scope.DOMApplicationRegistry.confirmInstall(JSON.parse(data));
+
+ let installRecord = JSON.parse(data);
+ installRecord.registryDir = Services.dirsvc.get("ProfD", Ci.nsIFile).path;
+ WebappRT.config = installRecord;
+
+ onBecome();
+ }
+ Services.obs.addObserver(observeInstall, "webapps-ask-install", false);
+
+ // Step 1: Install the app at the URL specified by the manifest.
+ let url = Services.io.newURI(manifestURL, null, MANIFEST_URL_BASE);
+ navigator.mozApps.install(url.spec, parameters);
+}
new file mode 100644
--- /dev/null
+++ b/webapprt/content/mochitest.xul
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+
+<!-- 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/. -->
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<window windowtype="webapprt:mochitest"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<script type="application/javascript" src="chrome://webapprt/content/mochitest.js"/>
+
+<script type="application/javascript">
+ Cu.import("resource://webapprt/modules/WebappRT.jsm");
+
+ // In test mode, the runtime isn't configured until we tell it to become
+ // an app, which requires us to use DOMApplicationRegistry to install one.
+ // But DOMApplicationRegistry needs to know the location of its registry dir,
+ // so we need to configure the runtime with at least that information.
+ WebappRT.config = {
+ registryDir: Services.dirsvc.get("ProfD", Ci.nsIFile).path,
+ };
+
+ Cu.import("resource://gre/modules/Webapps.jsm");
+
+ DOMApplicationRegistry.allAppsLaunchable = true;
+
+ becomeWebapp("http://mochi.test:8888/tests/webapprt/test/content/test.webapp",
+ undefined, function onBecome() {
+ Services.ww.openWindow(
+ null,
+ "chrome://webapprt/content/webapp.xul",
+ "_blank",
+ "chrome,dialog=no,resizable,scrollbars,centerscreen",
+ window.arguments[0]
+ );
+ window.close();
+ });
+</script>
+
+<description value="WebappRT Test Shim"/>
+
+</window>
--- a/webapprt/content/webapp.js
+++ b/webapprt/content/webapp.js
@@ -1,16 +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/. */
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
+Cu.import("resource://webapprt/modules/Startup.jsm");
Cu.import("resource://webapprt/modules/WebappRT.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyGetter(this, "gAppBrowser",
function() document.getElementById("content"));
#ifdef MOZ_CRASHREPORTER
@@ -43,79 +44,45 @@ let progressListener = {
updateCrashReportURL(aRequest.URI);
}
}
};
function onLoad() {
window.removeEventListener("load", onLoad, false);
- let cmdLineArgs = window.arguments && window.arguments[0] ?
- window.arguments[0].QueryInterface(Ci.nsIPropertyBag2) :
- null;
-
- // In test mode, listen for test app installations and load the -test-mode URL
- // if present.
- if (cmdLineArgs && cmdLineArgs.hasKey("test-mode")) {
- // This observer is only present until the first app gets installed.
- // It adds the progress listener, which can't happen until then because
- // the progress listener needs to access the app manifest, which isn't
- // available beforehand.
- Services.obs.addObserver(function observeOnce(subj, topic, data) {
- Services.obs.removeObserver(observeOnce, "webapprt-test-did-install");
- gAppBrowser.addProgressListener(progressListener,
- Ci.nsIWebProgress.NOTIFY_LOCATION);
- }, "webapprt-test-did-install", false);
-
- // This observer is present for the lifetime of the runtime.
- Services.obs.addObserver(function observe(subj, topic, data) {
- initWindow(false);
- }, "webapprt-test-did-install", false);
+ let args = window.arguments && window.arguments[0] ?
+ window.arguments[0].QueryInterface(Ci.nsIPropertyBag2) :
+ null;
- let testURL = cmdLineArgs.get("test-mode");
- if (testURL) {
- gAppBrowser.loadURI(testURL);
- }
-
- return;
- }
-
- gAppBrowser.webProgress.
- addProgressListener(progressListener, Ci.nsIWebProgress.NOTIFY_LOCATION |
- Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
-
- initWindow(!!cmdLineArgs);
-}
-window.addEventListener("load", onLoad, false);
-
-function onUnload() {
- gAppBrowser.removeProgressListener(progressListener);
-}
-window.addEventListener("unload", onUnload, false);
-
-function initWindow(isMainWindow) {
- let manifest = WebappRT.config.app.manifest;
+ gAppBrowser.addProgressListener(progressListener,
+ Ci.nsIWebProgress.NOTIFY_LOCATION |
+ Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
updateMenuItems();
// Listen for clicks to redirect <a target="_blank"> to the browser.
// This doesn't capture clicks so content can capture them itself and do
// something different if it doesn't want the default behavior.
gAppBrowser.addEventListener("click", onContentClick, false, true);
- // Only load the webapp on the initially launched main window
- if (isMainWindow) {
- // Load the webapp's launch URL
- let installRecord = WebappRT.config.app;
- let url = Services.io.newURI(installRecord.origin, null, null);
- if (manifest.launch_path)
- url = Services.io.newURI(manifest.launch_path, null, url);
- gAppBrowser.setAttribute("src", url.spec);
+ // This is not the only way that a URL gets loaded in the app browser.
+ // When content calls openWindow(), there are no window.arguments,
+ // but something in the platform loads the URL specified by the content.
+ if (args && args.hasKey("url")) {
+ gAppBrowser.setAttribute("src", args.get("url"));
}
+
}
+window.addEventListener("load", onLoad, false);
+
+function onUnload() {
+ gAppBrowser.removeProgressListener(progressListener);
+}
+window.addEventListener("unload", onUnload, false);
/**
* Direct a click on <a target="_blank"> to the user's default browser.
*
* In the long run, it might be cleaner to move this to an extension of
* nsIWebBrowserChrome3::onBeforeLinkTraversal.
*
* @param {DOMEvent} event the DOM event
@@ -194,17 +161,19 @@ function updateEditUIVisibility() {
}
function updateCrashReportURL(aURI) {
#ifdef MOZ_CRASHREPORTER
if (!gCrashReporter.enabled)
return;
let uri = aURI.clone();
- if (uri.userPass != "") {
- try {
+ // uri.userPass throws on protocols without the concept of authentication,
+ // like about:, which tests can load, so we catch and ignore an exception.
+ try {
+ if (uri.userPass != "") {
uri.userPass = "";
- } catch (e) {}
- }
+ }
+ } catch (e) {}
gCrashReporter.annotateCrashReport("URL", uri.spec);
#endif
}
--- a/webapprt/jar.mn
+++ b/webapprt/jar.mn
@@ -1,8 +1,10 @@
# 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/.
webapprt.jar:
% content webapprt %content/
* content/webapp.js (content/webapp.js)
* content/webapp.xul (content/webapp.xul)
+ content/mochitest.js (content/mochitest.js)
+ content/mochitest.xul (content/mochitest.xul)
--- a/webapprt/test/chrome/Makefile.in
+++ b/webapprt/test/chrome/Makefile.in
@@ -7,17 +7,16 @@ topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = @relativesrcdir@
include $(DEPTH)/config/autoconf.mk
MOCHITEST_WEBAPPRT_CHROME_FILES = \
head.js \
- install.html \
browser_sample.js \
sample.webapp \
sample.html \
browser_window-title.js \
window-title.webapp \
window-title.html \
$(NULL)
--- a/webapprt/test/chrome/browser_sample.js
+++ b/webapprt/test/chrome/browser_sample.js
@@ -1,19 +1,20 @@
// This is a sample WebappRT chrome test. It's just a browser-chrome mochitest.
+Cu.import("resource://webapprt/modules/WebappRT.jsm");
+
function test() {
waitForExplicitFinish();
ok(true, "true is true!");
- installWebapp("sample.webapp", undefined, function onInstall(appConfig) {
+ loadWebapp("sample.webapp", undefined, function onLoad() {
is(document.documentElement.getAttribute("title"),
- appConfig.app.manifest.name,
+ WebappRT.config.app.manifest.name,
"Window title should be webapp name");
- let content = document.getElementById("content");
- let msg = content.contentDocument.getElementById("msg");
+ let msg = gAppBrowser.contentDocument.getElementById("msg");
var observer = new MutationObserver(function (mutations) {
ok(/^Webapp getSelf OK:/.test(msg.textContent),
"The webapp should have successfully installed and updated its msg");
finish();
});
observer.observe(msg, { childList: true });
});
}
--- a/webapprt/test/chrome/browser_window-title.js
+++ b/webapprt/test/chrome/browser_window-title.js
@@ -1,28 +1,26 @@
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://webapprt/modules/WebappRT.jsm");
function test() {
waitForExplicitFinish();
- installWebapp("window-title.webapp", undefined,
- function onInstall(appConfig) {
+ loadWebapp("window-title.webapp", undefined, function onLoad() {
is(document.documentElement.getAttribute("title"),
- appConfig.app.manifest.name,
+ WebappRT.config.app.manifest.name,
"initial window title should be webapp name");
- let appBrowser = document.getElementById("content");
-
// Tests are triples of [URL to load, expected window title, test message].
let tests = [
["http://example.com/webapprtChrome/webapprt/test/chrome/window-title.html",
- "http://example.com" + " - " + appConfig.app.manifest.name,
+ "http://example.com" + " - " + WebappRT.config.app.manifest.name,
"window title should show origin of page at different origin"],
["http://mochi.test:8888/webapprtChrome/webapprt/test/chrome/window-title.html",
- appConfig.app.manifest.name,
+ WebappRT.config.app.manifest.name,
"after returning to app origin, window title should no longer show origin"],
];
let title, message;
let progressListener = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
Ci.nsISupportsWeakReference]),
@@ -31,25 +29,25 @@ function test() {
// Do test in timeout to give runtime time to change title.
window.setTimeout(function() {
is(document.documentElement.getAttribute("title"), title, message);
testNext();
}, 0);
}
};
- appBrowser.addProgressListener(progressListener,
- Ci.nsIWebProgress.NOTIFY_LOCATION);
+ gAppBrowser.addProgressListener(progressListener,
+ Ci.nsIWebProgress.NOTIFY_LOCATION);
function testNext() {
if (!tests.length) {
- appBrowser.removeProgressListener(progressListener);
- appBrowser.stop();
+ gAppBrowser.removeProgressListener(progressListener);
+ gAppBrowser.stop();
finish();
return;
}
- [appBrowser.contentDocument.location, title, message] = tests.shift();
+ [gAppBrowser.contentDocument.location, title, message] = tests.shift();
}
testNext();
});
}
--- a/webapprt/test/chrome/head.js
+++ b/webapprt/test/chrome/head.js
@@ -1,63 +1,31 @@
/* 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 INSTALL_URL =
- "http://mochi.test:8888/webapprtChrome/webapprt/test/chrome/install.html";
+ * 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/. */
Cu.import("resource://gre/modules/Services.jsm");
-/**
- * Installs the given webapp and navigates to it.
- *
- * @param manifestPath
- * The path of the webapp's manifest relative to
- * http://mochi.test:8888/webapprtChrome/webapprt/test/chrome/.
- * @param parameters
- * The value to pass as the "parameters" argument to
- * mozIDOMApplicationRegistry.install, e.g., { receipts: ... }. Use
- * undefined to pass nothing.
- * @param callback
- * Called when the newly installed webapp is navigated to. It's passed
- * the webapp's config object.
- */
-function installWebapp(manifestPath, parameters, onInstall) {
- // Three steps: (1) Load install.html, (2) listen for webapprt-test-did-
- // install to get the app config object, and then (3) listen for load of the
- // webapp page to call the callback. webapprt-test-did-install will be
- // broadcasted before install.html navigates to the webapp page. (This is due
- // to some implementation details: WebappRT.jsm confirms the installation by
- // calling DOMApplicationRegistry.confirmInstall, and then it immediately
- // broadcasts webapprt-test-did-install. confirmInstall asynchronously
- // notifies the mozApps consumer via onsuccess, which is when install.html
- // navigates to the webapp page.)
-
- let content = document.getElementById("content");
+// Some of the code we want to provide to chrome mochitests is in another file
+// so we can share it with the mochitest shim window, thus we need to load it.
+Services.scriptloader.loadSubScript("chrome://webapprt/content/mochitest.js",
+ this);
- Services.obs.addObserver(function observe(subj, topic, data) {
- // step 2
- Services.obs.removeObserver(observe, "webapprt-test-did-install");
- let appConfig = JSON.parse(data);
-
- content.addEventListener("load", function onLoad(event) {
- // step 3
- content.removeEventListener("load", onLoad, true);
- let webappURL = appConfig.app.origin + appConfig.app.manifest.launch_path;
- is(event.target.URL, webappURL,
- "No other page should have loaded between installation and " +
- "the webapp's page load: " + event.target.URL);
- onInstall(appConfig);
- }, true);
- }, "webapprt-test-did-install", false);
-
- // step 1
- let args = [["manifestPath", manifestPath]];
- if (parameters !== undefined) {
- args.push(["parameters", parameters]);
- }
- let queryStr = args.map(function ([key, val])
- key + "=" + encodeURIComponent(JSON.stringify(val))).
- join("&");
- let installURL = INSTALL_URL + "?" + queryStr;
- content.loadURI(installURL);
+/**
+ * Load the webapp in the app browser.
+ *
+ * @param {String} manifestURL
+ * @see becomeWebapp
+ * @param {Object} parameters
+ * @see becomeWebapp
+ * @param {Function} onLoad
+ * The callback to call once the webapp is loaded.
+ */
+function loadWebapp(manifest, parameters, onLoad) {
+ becomeWebapp(manifest, parameters, function onBecome() {
+ function onLoadApp() {
+ gAppBrowser.removeEventListener("load", onLoadApp, true);
+ onLoad();
+ }
+ gAppBrowser.addEventListener("load", onLoadApp, true);
+ gAppBrowser.setAttribute("src", WebappRT.launchURI.spec);
+ });
}
deleted file mode 100644
--- a/webapprt/test/chrome/install.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE HTML>
-
-<!--
- Chrome tests load this file to install their webapps. Pass manifestPath=path
- in the query string to install the app with the manifest at
- http://mochi.test:8888/webapprtChrome/webapprt/test/chrome/<path>.
--->
-
-<html>
- <head>
- <meta charset="utf-8">
- <script>
-
-function parseQueryStr() {
- return window.location.search.substr(1).split("&").
- map(function (pairStr) pairStr.split("=")).
- reduce(function (memo, [key, val]) {
- memo[key] = JSON.parse(decodeURIComponent(val));
- return memo;
- }, {});
-}
-
-function msg(str) {
- document.getElementById("msg").textContent = str;
-}
-
-function onLoad() {
- var args = parseQueryStr();
- if (!args.manifestPath) {
- msg("No manifest path given, so standing by.");
- return;
- }
- var manifestURL =
- "http://mochi.test:8888/webapprtChrome/webapprt/test/chrome/" +
- args.manifestPath;
- var installArgs = [manifestURL, args.parameters];
- msg("Installing webapp with arguments " + installArgs.toSource() + "...");
- var install = navigator.mozApps.install.apply(navigator.mozApps, installArgs);
- install.onsuccess = function (event) {
- msg("Webapp installed, now navigating to it.");
- var testAppURL = install.result.origin +
- install.result.manifest.launch_path;
- window.location = testAppURL;
- };
- install.onerror = function () {
- msg("Webapp installation failed with " + install.error.name +
- " for manifest " + manifestURL);
- };
-}
-
- </script>
- </head>
- <body onload="onLoad();" onunload="">
- <p id="msg">Installation page waiting for page load...</p>
- </body>
-</html>
--- a/webapprt/test/content/Makefile.in
+++ b/webapprt/test/content/Makefile.in
@@ -6,15 +6,13 @@ DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = @relativesrcdir@
include $(DEPTH)/config/autoconf.mk
MOCHITEST_FILES = \
- helpers.js \
+ test.webapp \
webapprt_sample.html \
- sample.webapp \
- sample.html \
$(NULL)
include $(topsrcdir)/config/rules.mk
deleted file mode 100644
--- a/webapprt/test/content/helpers.js
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * Shows a message on the page.
- *
- * @param str
- * The message to show.
- */
-function msg(str) {
- document.getElementById("msg").textContent = str;
-}
-
-/**
- * Installs the specified webapp and navigates to it in the iframe.
- *
- * @param manifestPath
- * The path of the manifest relative to
- * http://mochi.test:8888/tests/webapprt/test/content/.
- * @param parameters
- * The value to pass as the "parameters" argument to
- * mozIDOMApplicationRegistry.install, e.g., { receipts: ... }. Use
- * undefined to pass nothing.
- */
-function installWebapp(manifestPath, parameters) {
- var manifestURL = "http://mochi.test:8888/tests/webapprt/test/content/" +
- manifestPath;
- var installArgs = [manifestURL, parameters];
- msg("Installing webapp with arguments " + installArgs.toSource() + "...");
- var install = navigator.mozApps.install.apply(navigator.mozApps, installArgs);
- install.onsuccess = function (event) {
- msg("Webapp installed.");
- var testAppURL = install.result.origin +
- install.result.manifest.launch_path +
- window.location.search;
- document.getElementById("webapp-iframe").src = testAppURL;
- };
- install.onerror = function () {
- msg("Webapp installation failed with " + install.error.name +
- " for manifest " + manifestURL);
- };
-}
-
-/**
- * If webapprt_foo.html is loaded in the window, this function installs the
- * webapp whose manifest is named foo.webapp.
- *
- * @param parameters
- * The value to pass as the "parameters" argument to
- * mozIDOMApplicationRegistry.install, e.g., { receipts: ... }. Use
- * undefined to pass nothing.
- */
-function installOwnWebapp(parameters) {
- var match = /webapprt_(.+)\.html$/.exec(window.location.pathname);
- if (!match) {
- throw new Error("Test URL is unconventional, so could not derive a " +
- "manifest URL from it: " + window.location);
- }
- installWebapp(match[1] + ".webapp", parameters);
-}
deleted file mode 100644
--- a/webapprt/test/content/sample.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE HTML>
-
-<!--
- This file is the actual test. It's a webapp installed by webapprt_sample.html
- and loaded into its iframe. It's just a plain mochitest.
--->
-
-<html>
- <head>
- <meta charset="utf-8">
- <script src="/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
- </head>
- <body>
- <p id="display">
- This is the test webapp.
- </p>
- <div id="content" style="display: none"></div>
- <pre id="test">
- <script>
-
-SimpleTest.waitForExplicitFinish();
-
-ok(true, "true is true!");
-
-var self = navigator.mozApps.getSelf();
-self.onsuccess = function () {
- ok(true, "onsuccess should be called");
- ok(self.result, "result should be nonnull");
- ok(self.result.manifest, "manifest should be nonnull");
- is(self.result.manifest.name, "Sample Test Webapp", "manifest.name");
- SimpleTest.finish();
-};
-self.onerror = function () {
- ok(false, "onerror should not be called");
- SimpleTest.finish();
-};
-
- </script>
- </pre>
- </body>
-</html>
deleted file mode 100644
--- a/webapprt/test/content/sample.webapp
+++ /dev/null
@@ -1,1 +0,0 @@
-{"name": "Sample Test Webapp", "description": "A webapp that demonstrates how to make a WebappRT test.", "launch_path": "/tests/webapprt/test/content/sample.html" }
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/webapprt/test/content/test.webapp
@@ -0,0 +1,4 @@
+{
+ "name": "WebappRT Mochitest Webapp",
+ "description": "a webapp for running WebappRT mochitests"
+}
--- a/webapprt/test/content/webapprt_sample.html
+++ b/webapprt/test/content/webapprt_sample.html
@@ -1,25 +1,44 @@
<!DOCTYPE HTML>
<!--
- Since its name is prefixed with webapprt_, this file is picked up by the
- mochitest harness. Once loaded, it installs the webapp, and when the
- installation completes, it loads the webapp into an iframe. The webapp is
- the actual test; see sample.html.
+ This is a sample WebappRT content mochitest. Since its name is prefixed with
+ webapprt_, this file is picked up by the Mochitest harness. It's just a plain
+ mochitest that runs in the app browser within an app window.
-->
<html>
<head>
<meta charset="utf-8">
- <script src="helpers.js"></script>
- <script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ </head>
+ <body>
+ <p id="display">
+ This is the sample WebappRT content mochitest.
+ </p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ <script>
-// If your installation page needs to do anything other than call
-// installOwnWebapp, you can do it here.
+SimpleTest.waitForExplicitFinish();
+
+ok(true, "true is true!");
- </script>
- </head>
- <body onload="installOwnWebapp();">
- <p id="msg">Installation page waiting for page load...</p>
- <iframe id="webapp-iframe" width="100%" height="93%"></iframe>
+var self = navigator.mozApps.getSelf();
+self.onsuccess = function () {
+ ok(true, "onsuccess should be called");
+ ok(self.result, "result should be nonnull");
+ ok(self.result.manifest, "manifest should be nonnull");
+ is(self.result.manifest.name, "WebappRT Mochitest Webapp",
+ "manifest.name");
+ SimpleTest.finish();
+};
+self.onerror = function () {
+ ok(false, "onerror should not be called");
+ SimpleTest.finish();
+};
+
+ </script>
+ </pre>
</body>
</html>