Bug 733631 - Create a unit test infrastructure for the webapp runtime. r=myk,felipc,ctalbert

This commit is contained in:
Drew Willcoxon 2012-06-29 15:52:43 -07:00
Родитель 67e4a38f15
Коммит 7d8f11c66d
23 изменённых файлов: 593 добавлений и 54 удалений

Просмотреть файл

@ -188,7 +188,13 @@
function runTests() {
var windowMediator = Cc['@mozilla.org/appshell/window-mediator;1'].
getService(Ci.nsIWindowMediator);
var testWin = windowMediator.getMostRecentWindow("navigator:browser");
var winType = gConfig.testRoot == "browser" ? "navigator:browser" :
gConfig.testRoot == "webapprtChrome" ? "webapprt:webapp" :
null;
if (!winType) {
throw new Error("Unrecognized gConfig.testRoot: " + gConfig.testRoot);
}
var testWin = windowMediator.getMostRecentWindow(winType);
setStatus("Running...");
testWin.focus();

Просмотреть файл

@ -13,7 +13,7 @@ function testOnLoad() {
window.removeEventListener("load", testOnLoad, false);
gConfig = readConfig();
if (gConfig.testRoot == "browser") {
if (gConfig.testRoot == "browser" || gConfig.testRoot == "webapprtChrome") {
// Make sure to launch the test harness for the first opened window only
var prefs = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
@ -110,7 +110,10 @@ Tester.prototype = {
: this.currentTest ? "Found an unexpected {elt} at the end of test run"
: "Found an unexpected {elt}";
if (this.currentTest && window.gBrowser && gBrowser.tabs.length > 1) {
if (gConfig.testRoot == "browser" &&
this.currentTest &&
window.gBrowser &&
gBrowser.tabs.length > 1) {
while (gBrowser.tabs.length > 1) {
let lastTab = gBrowser.tabContainer.lastChild;
let msg = baseMsg.replace("{elt}", "tab") +

Просмотреть файл

@ -139,6 +139,16 @@ class MochitestOptions(optparse.OptionParser):
help = "run browser chrome Mochitests")
defaults["browserChrome"] = False
self.add_option("--webapprt-content",
action = "store_true", dest = "webapprtContent",
help = "run WebappRT content tests")
defaults["webapprtContent"] = False
self.add_option("--webapprt-chrome",
action = "store_true", dest = "webapprtChrome",
help = "run WebappRT chrome tests")
defaults["webapprtChrome"] = False
self.add_option("--a11y",
action = "store_true", dest = "a11y",
help = "run accessibility Mochitests");
@ -304,6 +314,9 @@ See <http://mochikit.com/doc/html/MochiKit/Logging.html> for details on the logg
options.testManifest = options.excludeTests
options.runOnly = False
if options.webapprtContent and options.webapprtChrome:
self.error("Only one of --webapprt-content and --webapprt-chrome may be given.")
return options
@ -323,6 +336,7 @@ class MochitestServer:
self.webServer = options.webServer
self.httpPort = options.httpPort
self.shutdownURL = "http://%(server)s:%(port)s/server/shutdown" % { "server" : self.webServer, "port" : self.httpPort }
self.testPrefix = "'webapprt_'" if options.webapprtContent else "undefined"
def start(self):
"Run the Mochitest server, returning the process ID of the server."
@ -335,8 +349,8 @@ class MochitestServer:
args = ["-g", self._xrePath,
"-v", "170",
"-f", "./" + "httpd.js",
"-e", "const _PROFILE_PATH = '%(profile)s';const _SERVER_PORT = '%(port)s'; const _SERVER_ADDR ='%(server)s';" %
{"profile" : self._profileDir.replace('\\', '\\\\'), "port" : self.httpPort, "server" : self.webServer },
"-e", "const _PROFILE_PATH = '%(profile)s';const _SERVER_PORT = '%(port)s'; const _SERVER_ADDR = '%(server)s'; const _TEST_PREFIX = %(testPrefix)s;" %
{"profile" : self._profileDir.replace('\\', '\\\\'), "port" : self.httpPort, "server" : self.webServer, "testPrefix" : self.testPrefix },
"-f", "./" + "server.js"]
xpcshell = os.path.join(self._utilityPath,
@ -547,7 +561,7 @@ class Mochitest(object):
# allow relative paths for logFile
if options.logFile:
options.logFile = self.getLogFilePath(options.logFile)
if options.browserChrome or options.chrome or options.a11y:
if options.browserChrome or options.chrome or options.a11y or options.webapprtChrome:
self.makeTestConfig(options)
else:
if options.autorun:
@ -641,6 +655,10 @@ class Mochitest(object):
if len(self.urlOpts) > 0:
testURL += "?" + "&".join(self.urlOpts)
if options.webapprtContent:
options.browserArgs.extend(('-test-mode', testURL))
testURL = None
# Remove the leak detection file so it can't "leak" to the tests run.
# The file is not there if leak logging was not enabled in the application build.
if os.path.exists(self.leak_report_file):
@ -655,7 +673,9 @@ class Mochitest(object):
timeout = 330.0 # default JS harness timeout is 300 seconds
# it's a debug build, we can parse leaked DOMWindows and docShells
if Automation.IS_DEBUG_BUILD:
# but skip for WebappRT chrome tests, where DOMWindow "leaks" aren't
# meaningful. See https://bugzilla.mozilla.org/show_bug.cgi?id=733631#c46
if Automation.IS_DEBUG_BUILD and not options.webapprtChrome:
logger = ShutdownLeakLogger(self.automation.log)
else:
logger = None
@ -733,7 +753,9 @@ class Mochitest(object):
testRoot = 'browser'
elif (options.a11y):
testRoot = 'a11y'
elif (options.webapprtChrome):
testRoot = 'webapprtChrome'
if "MOZ_HIDE_RESULTS_TABLE" in os.environ and os.environ["MOZ_HIDE_RESULTS_TABLE"] == "1":
options.hideResultsTable = True
@ -795,13 +817,15 @@ toolbar#nav-bar {
self.automation.log.warning("TEST-UNEXPECTED-FAIL | invalid setup: missing mochikit extension")
return None
# Support Firefox (browser), B2G (shell) and SeaMonkey (navigator).
# Support Firefox (browser), B2G (shell), SeaMonkey (navigator), and Webapp
# Runtime (webapp).
chrome = ""
if options.browserChrome or options.chrome or options.a11y:
if options.browserChrome or options.chrome or options.a11y or options.webapprtChrome:
chrome += """
overlay chrome://browser/content/browser.xul chrome://mochikit/content/browser-test-overlay.xul
overlay chrome://browser/content/shell.xul chrome://mochikit/content/browser-test-overlay.xul
overlay chrome://navigator/content/navigator.xul chrome://mochikit/content/browser-test-overlay.xul
overlay chrome://webapprt/content/webapp.xul chrome://mochikit/content/browser-test-overlay.xul
"""
self.installChromeJar(jarDir, chrome, options)

Просмотреть файл

@ -431,8 +431,10 @@ function isTest(filename, pattern)
return pattern.test(filename);
// File name is a URL style path to a test file, make sure that we check for
// tests that start with test_.
testPattern = /^test_/;
// tests that start with the appropriate prefix.
var testPrefix = typeof(_TEST_PREFIX) == "string" ? _TEST_PREFIX : "test_";
var testPattern = new RegExp("^" + testPrefix);
pathPieces = filename.split('/');
return testPattern.test(pathPieces[pathPieces.length - 1]) &&

Просмотреть файл

@ -129,6 +129,16 @@ else
endif
$(CHECK_TEST_ERROR)
ifeq ($(OS_ARCH),Darwin)
webapprt_stub_path = $(TARGET_DIST)/$(MOZ_MACBUNDLE_NAME)/Contents/MacOS/webapprt-stub$(BIN_SUFFIX)
webapprt-test-content:
$(RUN_MOCHITEST) --webapprt-content --appname $(webapprt_stub_path)
$(CHECK_TEST_ERROR)
webapprt-test-chrome:
$(RUN_MOCHITEST) --webapprt-chrome --appname $(webapprt_stub_path) --browser-arg -test-mode
$(CHECK_TEST_ERROR)
endif
# Usage: |make [EXTRA_TEST_ARGS=...] *test|.
RUN_REFTEST = rm -f ./$@.log && $(PYTHON) _tests/reftest/runreftest.py \
$(SYMBOLS_PATH) $(EXTRA_TEST_ARGS) $(1) | tee ./$@.log

Просмотреть файл

@ -17,16 +17,61 @@ CommandLineHandler.prototype = {
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();
} else {
// 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();
}, "webapprt-test-did-install", false);
}
// 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);
},
// Initialize window-independent handling of webapps- notifications
Cu.import("resource://webapprt/modules/WebappsHandler.jsm");
WebappsHandler.init();
_handleTestMode: function _handleTestMode(cmdLine, args) {
// -test-mode [url]
let idx = cmdLine.findFlag("test-mode", true);
if (idx < 0)
return false;
let url = null;
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);
} catch (err) {
throw Components.Exception(
"-test-mode argument is not a valid URL: " + url,
Components.results.NS_ERROR_INVALID_ARG);
}
cmdLine.removeArguments(urlIdx, urlIdx);
}
}
cmdLine.removeArguments(idx, idx);
args.setProperty("test-mode", url);
return true;
},
helpInfo : "",
@ -43,31 +88,40 @@ let NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
* 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();
}
try {
// Initialize DOMApplicationRegistry so it can receive/respond to messages.
Cu.import("resource://gre/modules/Webapps.jsm");
// 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);
// 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);
// 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);
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) {
// 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");
dump(ex + "\n");
#endif
}
}

Просмотреть файл

@ -12,6 +12,14 @@ 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() {}
@ -23,6 +31,13 @@ DirectoryProvider.prototype = {
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;

Просмотреть файл

@ -46,6 +46,10 @@ EXTRA_JS_MODULES = \
PREF_JS_EXPORTS = $(srcdir)/prefs.js \
$(NULL)
TEST_DIRS += \
test \
$(NULL)
include $(topsrcdir)/config/rules.mk
ifdef MOZ_DEBUG

Просмотреть файл

@ -9,12 +9,36 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyGetter(this, "FileUtils", function() {
Cu.import("resource://gre/modules/FileUtils.jsm");
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;
delete WebappRT.config;
WebappRT.config = deepFreeze(config);
DOMApplicationRegistry.confirmInstall(config);
Services.obs.notifyObservers(null, "webapprt-test-did-install",
JSON.stringify(config));
}, "webapps-ask-install", false);
}, "webapprt-command-line", false);
let WebappRT = {
get config() {
let webappFile = FileUtils.getFile("AppRegD", ["webapp.json"]);

Просмотреть файл

@ -12,10 +12,36 @@ Cu.import("resource://gre/modules/Services.jsm");
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")) {
Services.obs.addObserver(function observe(subj, topic, data) {
// The observer is present for the lifetime of the runtime.
initWindow(false);
}, "webapprt-test-did-install", false);
let testURL = cmdLineArgs.get("test-mode");
if (testURL) {
document.getElementById("content").loadURI(testURL);
}
return;
}
initWindow(!!cmdLineArgs);
}
window.addEventListener("load", onLoad, false);
function initWindow(isMainWindow) {
// Set the title of the window to the name of the webapp
let manifest = WebappRT.config.app.manifest;
document.documentElement.setAttribute("title", manifest.name);
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.
@ -23,7 +49,7 @@ function onLoad() {
false, true);
// Only load the webapp on the initially launched main window
if ("arguments" in window) {
if (isMainWindow) {
// Load the webapp's launch URL
let installRecord = WebappRT.config.app;
let url = Services.io.newURI(installRecord.origin, null, null);
@ -32,7 +58,6 @@ function onLoad() {
document.getElementById("content").setAttribute("src", url.spec);
}
}
window.addEventListener("load", onLoad, false);
/**
* Direct a click on <a target="_blank"> to the user's default browser.
@ -66,11 +91,10 @@ function onContentClick(event) {
event.preventDefault();
}
#ifdef XP_MACOSX
// On Mac, we dynamically create the label for the Quit menuitem, using
// a string property to inject the name of the webapp into it.
window.addEventListener("load", function onLoadUpdateMenuItems() {
window.removeEventListener("load", onLoadUpdateMenuItems, false);
function updateMenuItems() {
#ifdef XP_MACOSX
let installRecord = WebappRT.config.app;
let manifest = WebappRT.config.app.manifest;
let bundle =
@ -81,8 +105,8 @@ window.addEventListener("load", function onLoadUpdateMenuItems() {
[manifest.name], 1);
document.getElementById("menu_FileQuitItem").setAttribute("label", quitLabel);
document.getElementById("menu_mac_hide_app").setAttribute("label", hideLabel);
}, false);
#endif
}
function updateEditUIVisibility() {
#ifndef XP_MACOSX

Просмотреть файл

@ -90,6 +90,9 @@ main(int argc, char **argv)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSDictionary *args = [[NSUserDefaults standardUserDefaults]
volatileDomainForName:NSArgumentDomain];
NSString *firefoxPath = nil;
NSString *alternateBinaryID = nil;
@ -199,11 +202,6 @@ main(int argc, char **argv)
NS_LogInit();
{ // Scope for any XPCOM stuff we create
nsINIParser parser;
if (NS_FAILED(parser.Init(appEnv))) {
NSLog(@"%s was not found\n", appEnv);
@throw MakeException(@"Error", @"Unable to parse environment files for application startup");
}
// Get the path to the runtime directory.
char rtDir[MAXPATHLEN];
@ -234,13 +232,24 @@ main(int argc, char **argv)
@throw MakeException(@"Error", @"Unable to parse base INI file.");
}
char profile[MAXPATHLEN];
if (NS_FAILED(parser.GetString("Webapp", "Profile", profile, MAXPATHLEN))) {
NSLog(@"Unable to retrieve profile from web app INI file");
@throw MakeException(@"Error", @"Unable to retrieve installation profile.");
NSString *profile = [args objectForKey:@"profile"];
if (profile) {
NSLog(@"Profile specified with -profile: %@", profile);
}
else {
nsINIParser parser;
if (NS_FAILED(parser.Init(appEnv))) {
NSLog(@"%s was not found\n", appEnv);
@throw MakeException(@"Error", @"Unable to parse environment files for application startup");
}
char profile[MAXPATHLEN];
if (NS_FAILED(parser.GetString("Webapp", "Profile", profile, MAXPATHLEN))) {
NSLog(@"Unable to retrieve profile from web app INI file");
@throw MakeException(@"Error", @"Unable to retrieve installation profile.");
}
NSLog(@"setting app profile: %s", profile);
SetAllocatedString(webShellAppData->profile, profile);
}
NSLog(@"setting app profile: %s", profile);
SetAllocatedString(webShellAppData->profile, profile);
nsCOMPtr<nsIFile> directory;
if (NS_FAILED(XRE_GetFileFromPath(rtDir, getter_AddRefs(directory)))) {
@ -309,6 +318,14 @@ NSString
//default is firefox
NSString *binaryPath = nil;
// We're run from the Firefox bundle during WebappRT chrome and content tests.
NSString *myBundlePath = [[NSBundle mainBundle] bundlePath];
NSString *fxPath = [NSString stringWithFormat:@"%@%sfirefox-bin",
myBundlePath, APP_CONTENTS_PATH];
if ([[NSFileManager defaultManager] fileExistsAtPath:fxPath]) {
return myBundlePath;
}
//we look for these flavors of Firefox, in this order
NSArray* launchBinarySearchList = [NSArray arrayWithObjects: @"org.mozilla.nightly",
@"org.mozilla.aurora",

17
webapprt/test/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
DIRS += \
chrome \
content \
$(NULL)
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -0,0 +1,23 @@
# 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 = webapprt/test/chrome
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_BROWSER_TEST_FILES = \
head.js \
install.html \
browser_sample.js \
sample.webapp \
sample.html \
$(NULL)
libs:: $(_BROWSER_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/webapprtChrome/$(relativesrcdir)

Просмотреть файл

@ -0,0 +1,19 @@
// This is a sample WebappRT chrome test. It's just a browser-chrome mochitest.
function test() {
waitForExplicitFinish();
ok(true, "true is true!");
installWebapp("sample.webapp", undefined, function onInstall(appConfig) {
is(document.documentElement.getAttribute("title"),
appConfig.app.manifest.name,
"Window title should be webapp name");
let content = document.getElementById("content");
let msg = content.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 });
});
}

Просмотреть файл

@ -0,0 +1,63 @@
/* 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";
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");
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);
}

Просмотреть файл

@ -0,0 +1,56 @@
<!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>

Просмотреть файл

@ -0,0 +1,30 @@
<!DOCTYPE HTML>
<!--
This is the webapp. It doesn't need to do anything in particular, just
whatever you want to test from your browser_ test file.
-->
<html>
<head>
<meta charset="utf-8">
<script>
function onLoad() {
var msg = document.getElementById("msg");
var self = navigator.mozApps.getSelf();
self.onsuccess = function () {
msg.textContent = "Webapp getSelf OK: " + self.result;
};
self.onerror = function () {
msg.textContent = "Webapp getSelf failed: " + self.error.name;
};
}
</script>
</head>
<body onload="onLoad();" onunload="">
<p>This is the test webapp.</p>
<p id="msg">Webapp waiting for page load...</p>
</body>
</html>

Просмотреть файл

@ -0,0 +1 @@
{"name": "Sample Test Webapp", "description": "A webapp that demonstrates how to make a WebappRT test.", "launch_path": "/webapprtChrome/webapprt/test/chrome/sample.html" }

Просмотреть файл

@ -0,0 +1,22 @@
# 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 = webapprt/test/content
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TEST_FILES = \
helpers.js \
webapprt_sample.html \
sample.webapp \
sample.html \
$(NULL)
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

Просмотреть файл

@ -0,0 +1,57 @@
/**
* 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);
}

Просмотреть файл

@ -0,0 +1,42 @@
<!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>

Просмотреть файл

@ -0,0 +1 @@
{"name": "Sample Test Webapp", "description": "A webapp that demonstrates how to make a WebappRT test.", "launch_path": "/tests/webapprt/test/content/sample.html" }

Просмотреть файл

@ -0,0 +1,25 @@
<!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.
-->
<html>
<head>
<meta charset="utf-8">
<script src="helpers.js"></script>
<script>
// If your installation page needs to do anything other than call
// installOwnWebapp, you can do it here.
</script>
</head>
<body onload="installOwnWebapp();">
<p id="msg">Installation page waiting for page load...</p>
<iframe id="webapp-iframe" width="100%" height="93%"></iframe>
</body>
</html>