diff --git a/addon-sdk/source/app-extension/bootstrap.js b/addon-sdk/source/app-extension/bootstrap.js index 49d0f97373e7..87b3a9c24ec0 100644 --- a/addon-sdk/source/app-extension/bootstrap.js +++ b/addon-sdk/source/app-extension/bootstrap.js @@ -354,7 +354,6 @@ function nukeModules() { // the addon is unload. unloadSandbox(cuddlefishSandbox.loaderSandbox); - unloadSandbox(cuddlefishSandbox.xulappSandbox); // Bug 764840: We need to unload cuddlefish otherwise it will stay alive // and keep a reference to this compartment. diff --git a/addon-sdk/source/bin/jpm-test.js b/addon-sdk/source/bin/jpm-test.js index 3b83639d1377..f9836e10234a 100644 --- a/addon-sdk/source/bin/jpm-test.js +++ b/addon-sdk/source/bin/jpm-test.js @@ -3,8 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; -var readParam = require("./node-scripts/utils").readParam; -var path = require("path"); +var Promise = require("promise"); var Mocha = require("mocha"); var mocha = new Mocha({ ui: "bdd", @@ -12,16 +11,19 @@ var mocha = new Mocha({ timeout: 900000 }); -var type = readParam("type"); +exports.run = function(type) { + return new Promise(function(resolve) { + type = type || ""; + [ + (/^(modules)?$/.test(type)) && require.resolve("../bin/node-scripts/test.modules"), + (/^(addons)?$/.test(type)) && require.resolve("../bin/node-scripts/test.addons"), + (/^(examples)?$/.test(type)) && require.resolve("../bin/node-scripts/test.examples"), + ].sort().forEach(function(filepath) { + filepath && mocha.addFile(filepath); + }) -[ - (!type || type == "modules") && require.resolve("../bin/node-scripts/test.modules"), - (!type || type == "addons") && require.resolve("../bin/node-scripts/test.addons"), - (!type || type == "examples") && require.resolve("../bin/node-scripts/test.examples"), -].sort().forEach(function(filepath) { - filepath && mocha.addFile(filepath); -}) - -mocha.run(function (failures) { - process.exit(failures); -}); + mocha.run(function(failures) { + resolve(failures); + }); + }); +} diff --git a/addon-sdk/source/examples/debug-client/data/client.js b/addon-sdk/source/examples/debug-client/data/client.js index 022f9a1c35c6..baec09105320 100644 --- a/addon-sdk/source/examples/debug-client/data/client.js +++ b/addon-sdk/source/examples/debug-client/data/client.js @@ -202,7 +202,7 @@ var Connection = Class({ }, poolFor: function(id) { for (let pool of this.pools.values()) { - if (pool.has(id)) + if pool.has(id) return pool; } }, @@ -797,7 +797,7 @@ var Tab = Client.from({ "storageActor": "storage", "gcliActor": "gcli", "memoryActor": "memory", - "eventLoopLag": "eventLoopLag", + "eventLoopLag": "eventLoopLag" "trace": "trace", // missing } diff --git a/addon-sdk/source/gulpfile.js b/addon-sdk/source/gulpfile.js new file mode 100644 index 000000000000..fc1b89e79d93 --- /dev/null +++ b/addon-sdk/source/gulpfile.js @@ -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/. */ +"use strict"; + +var gulp = require('gulp'); + +gulp.task('test', function(done) { + require("./bin/jpm-test").run().then(done); +}); + +gulp.task('test:addons', function(done) { + require("./bin/jpm-test").run("addons").then(done); +}); + +gulp.task('test:examples', function(done) { + require("./bin/jpm-test").run("examples").then(done); +}); + +gulp.task('test:modules', function(done) { + require("./bin/jpm-test").run("modules").then(done); +}); + diff --git a/addon-sdk/source/lib/sdk/content/l10n-html.js b/addon-sdk/source/lib/sdk/content/l10n-html.js index ccb1551027ec..cf0aae941dd3 100644 --- a/addon-sdk/source/lib/sdk/content/l10n-html.js +++ b/addon-sdk/source/lib/sdk/content/l10n-html.js @@ -16,6 +16,31 @@ const assetsURI = require('../self').data.url(); const hideSheetUri = "data:text/css,:root {visibility: hidden !important;}"; +function translateElementAttributes(element) { + // Translateable attributes + const attrList = ['title', 'accesskey', 'alt', 'label', 'placeholder']; + const ariaAttrMap = { + 'ariaLabel': 'aria-label', + 'ariaValueText': 'aria-valuetext', + 'ariaMozHint': 'aria-moz-hint' + }; + const attrSeparator = '.'; + + // Try to translate each of the attributes + for (let attribute of attrList) { + const data = core.get(element.dataset.l10nId + attrSeparator + attribute); + if (data) + element.setAttribute(attribute, data); + } + + // Look for the aria attribute translations that match fxOS's aliases + for (let attrAlias in ariaAttrMap) { + const data = core.get(element.dataset.l10nId + attrSeparator + attrAlias); + if (data) + element.setAttribute(ariaAttrMap[attrAlias], data); + } +} + // Taken from Gaia: // https://github.com/andreasgal/gaia/blob/04fde2640a7f40314643016a5a6c98bf3755f5fd/webapi.js#L1470 function translateElement(element) { @@ -32,6 +57,8 @@ function translateElement(element) { var data = core.get(key); if (data) child.textContent = data; + + translateElementAttributes(child); } } exports.translateElement = translateElement; diff --git a/addon-sdk/source/lib/sdk/deprecated/unit-test.js b/addon-sdk/source/lib/sdk/deprecated/unit-test.js index d6d1c048ab01..33bb6d7dd50d 100644 --- a/addon-sdk/source/lib/sdk/deprecated/unit-test.js +++ b/addon-sdk/source/lib/sdk/deprecated/unit-test.js @@ -320,6 +320,8 @@ TestRunner.prototype = { }); PromiseDebugging.flushUncaughtErrors(); + PromiseDebugging.removeUncaughtErrorObserver(this._uncaughtErrorObserver); + return all(winPromises).then(() => { let browserWins = wins.filter(isBrowser); @@ -537,7 +539,8 @@ TestRunner.prototype = { this.test.errors = {}; this.test.last = 'START'; PromiseDebugging.clearUncaughtErrorObservers(); - PromiseDebugging.addUncaughtErrorObserver(this._uncaughtErrorObserver.bind(this)); + this._uncaughtErrorObserver = this._uncaughtErrorObserver.bind(this); + PromiseDebugging.addUncaughtErrorObserver(this._uncaughtErrorObserver); this.isDone = false; this.onDone = function(self) { diff --git a/addon-sdk/source/lib/sdk/event/dom.js b/addon-sdk/source/lib/sdk/event/dom.js index 54963230ff3c..01c162be4c38 100644 --- a/addon-sdk/source/lib/sdk/event/dom.js +++ b/addon-sdk/source/lib/sdk/event/dom.js @@ -21,6 +21,10 @@ let getWindowFrom = x => null; function removeFromListeners() { + this.removeEventListener("DOMWindowClose", removeFromListeners); + for (let cleaner of listeners.get(this)) + cleaner(); + listeners.delete(this); } @@ -45,26 +49,25 @@ function open(target, type, options) { if (!window) throw new Error("Unable to obtain the owner window from the target given."); - let cleaners = listeners.get(window) || []; + let cleaners = listeners.get(window); + if (!cleaners) { + cleaners = []; + listeners.set(window, cleaners); + + // We need to remove from our map the `window` once is closed, to prevent + // memory leak + window.addEventListener("DOMWindowClose", removeFromListeners); + } + cleaners.push(() => target.removeEventListener(type, listener, capture)); - - listeners.set(window, cleaners); - - // We need to remove from our map the `window` once is closed, to prevent - // memory leak - window.addEventListener("DOMWindowClose", removeFromListeners); - target.addEventListener(type, listener, capture); return output; } unload(() => { - for (let [window, cleaners] of listeners) { - cleaners.forEach(callback => callback()) - } - - listeners.clear(); + for (let window of listeners.keys()) + removeFromListeners.call(window); }); exports.open = open; diff --git a/addon-sdk/source/lib/sdk/io/fs.js b/addon-sdk/source/lib/sdk/io/fs.js index 7a8db312b9dd..7d7e28932e52 100644 --- a/addon-sdk/source/lib/sdk/io/fs.js +++ b/addon-sdk/source/lib/sdk/io/fs.js @@ -692,8 +692,6 @@ function writeSync(fd, buffer, offset, length, position) { else if (length + offset !== buffer.length) { buffer = buffer.slice(offset, offset + length); } - let writeStream = new WriteStream(fd, { position: position, - length: length }); let output = BinaryOutputStream(nsIFileOutputStream(fd)); nsIBinaryOutputStream(fd, output); diff --git a/addon-sdk/source/lib/sdk/places/events.js b/addon-sdk/source/lib/sdk/places/events.js index 610ce0f79669..6f3e11bcf1bd 100644 --- a/addon-sdk/source/lib/sdk/places/events.js +++ b/addon-sdk/source/lib/sdk/places/events.js @@ -23,6 +23,7 @@ const historyService = Cc['@mozilla.org/browser/nav-history-service;1'] const { mapBookmarkItemType } = require('./utils'); const { EventTarget } = require('../event/target'); const { emit } = require('../event/core'); +const { when } = require('../system/unload'); const emitter = EventTarget(); @@ -119,4 +120,9 @@ historyService.addObserver(historyObserver, false); let bookmarkObserver = createObserverInstance(BOOKMARK_EVENTS, BOOKMARK_ARGS); bookmarkService.addObserver(bookmarkObserver, false); +when(() => { + historyService.removeObserver(historyObserver); + bookmarkService.removeObserver(bookmarkObserver); +}); + exports.events = emitter; diff --git a/addon-sdk/source/lib/toolkit/loader.js b/addon-sdk/source/lib/toolkit/loader.js index 1c8f122aea30..2aec555d93b1 100644 --- a/addon-sdk/source/lib/toolkit/loader.js +++ b/addon-sdk/source/lib/toolkit/loader.js @@ -169,6 +169,15 @@ function serializeStack(frames) { Loader.serializeStack = serializeStack; function readURI(uri) { + let nsURI = NetUtil.newURI(uri); + if (nsURI.scheme == "resource") { + // Resolve to a real URI, this will catch any obvious bad paths without + // logging assertions in debug builds, see bug 1135219 + let proto = Cc["@mozilla.org/network/protocol;1?name=resource"]. + getService(Ci.nsIResProtocolHandler); + uri = proto.resolveURI(nsURI); + } + let stream = NetUtil.newChannel2(uri, 'UTF-8', null, @@ -420,6 +429,10 @@ const nodeResolve = iced(function nodeResolve(id, requirer, { rootURI }) { // Resolve again id = Loader.resolve(id, requirer); + // If this is already an absolute URI then there is no resolution to do + if (isAbsoluteURI(id)) + return void 0; + // we assume that extensions are correct, i.e., a directory doesnt't have '.js' // and a js file isn't named 'file.json.js' let fullId = join(rootURI, id); @@ -431,9 +444,14 @@ const nodeResolve = iced(function nodeResolve(id, requirer, { rootURI }) { if ((resolvedPath = loadAsDirectory(fullId))) return stripBase(rootURI, resolvedPath); + // If the requirer is an absolute URI then the node module resolution below + // won't work correctly as we prefix everything with rootURI + if (isAbsoluteURI(requirer)) + return void 0; + // If manifest has dependencies, attempt to look up node modules // in the `dependencies` list - let dirs = getNodeModulePaths(dirname(join(rootURI, requirer))).map(dir => join(dir, id)); + let dirs = getNodeModulePaths(dirname(requirer)).map(dir => join(rootURI, dir, id)); for (let i = 0; i < dirs.length; i++) { if ((resolvedPath = loadAsFile(dirs[i]))) return stripBase(rootURI, resolvedPath); @@ -509,6 +527,7 @@ function getNodeModulePaths (start) { let dir = join(parts.slice(0, i + 1).join('/'), moduleDir); dirs.push(dir); } + dirs.push(moduleDir); return dirs; } diff --git a/addon-sdk/source/package.json b/addon-sdk/source/package.json index 0e0c1f0e30dc..f2faebc753c1 100644 --- a/addon-sdk/source/package.json +++ b/addon-sdk/source/package.json @@ -8,10 +8,7 @@ "license": "MPL 2.0", "unpack": true, "scripts": { - "test": "node ./bin/jpm-test.js", - "modules": "node ./bin/jpm-test.js --type modules", - "addons": "node ./bin/jpm-test.js --type addons", - "examples": "node ./bin/jpm-test.js --type examples" + "test": "gulp test" }, "homepage": "https://github.com/mozilla/addon-sdk", "repository": { @@ -25,6 +22,7 @@ "async": "0.9.0", "chai": "2.1.1", "glob": "4.4.2", + "gulp": "3.8.11", "jpm": "0.0.29", "lodash": "3.3.1", "mocha": "2.1.0", diff --git a/addon-sdk/source/python-lib/cuddlefish/prefs.py b/addon-sdk/source/python-lib/cuddlefish/prefs.py index bb0417201572..5e1a5e01f34f 100644 --- a/addon-sdk/source/python-lib/cuddlefish/prefs.py +++ b/addon-sdk/source/python-lib/cuddlefish/prefs.py @@ -56,6 +56,7 @@ DEFAULT_NO_CONNECTIONS_PREFS = { 'browser.aboutHomeSnippets.updateUrl': 'https://localhost/snippet-dummy', 'browser.newtab.url' : 'about:blank', 'browser.search.update': False, + 'browser.search.suggest.enabled' : False, 'browser.safebrowsing.enabled' : False, 'browser.safebrowsing.updateURL': 'http://localhost/safebrowsing-dummy/update', 'browser.safebrowsing.gethashURL': 'http://localhost/safebrowsing-dummy/gethash', diff --git a/addon-sdk/source/test/addons/e10s-l10n/data/test-localization.html b/addon-sdk/source/test/addons/e10s-l10n/data/test-localization.html index 5428863ad8e2..5646946da35d 100644 --- a/addon-sdk/source/test/addons/e10s-l10n/data/test-localization.html +++ b/addon-sdk/source/test/addons/e10s-l10n/data/test-localization.html @@ -20,5 +20,10 @@
A data-l10n-id value can be used in multiple elements
+ + + + + { + let listener = function(frame, ...args) { + if (!frame.isTab) + return; + frames.off("attach", listener); + resolve([frame, ...args]); + } + + frames.on("attach", listener); + }); +} + // Check that we see a process stop and start exports["test process restart"] = function*(assert) { if (!isE10S) { @@ -44,7 +57,7 @@ exports["test process restart"] = function*(assert) { // Switch the remote tab to a local URI which should kill the remote process let frameDetach = promiseEventOnItemAndContainer(assert, remoteFrame, frames, 'detach'); - let frameAttach = promiseEvent(frames, 'attach'); + let frameAttach = promiseTabFrameAttach(frames); let processDetach = promiseEventOnItemAndContainer(assert, remoteProcess, processes, 'detach'); setTabURL(tab, LOCAL_URI); // The load should kill the remote frame @@ -57,7 +70,7 @@ exports["test process restart"] = function*(assert) { frameDetach = promiseEventOnItemAndContainer(assert, newFrame, frames, 'detach'); let processAttach = promiseEvent(processes, 'attach'); - frameAttach = promiseEvent(frames, 'attach'); + frameAttach = promiseTabFrameAttach(frames); setTabURL(tab, REMOTE_URI); // The load should kill the remote frame yield frameDetach; @@ -149,7 +162,7 @@ exports["test frame list"] = function*(assert) { assert.equal(browserFrames(frames), getTabs(window).length, "Should be the right number of browser frames."); assert.equal((yield getChildFrameCount(processes)), frames.length, "Child processes should have the right number of frames"); - let promise = promiseEvent(frames, 'attach'); + let promise = promiseTabFrameAttach(frames); let tab1 = openTab(window, LOCAL_URI); let [frame1] = yield promise; assert.ok(!!frame1, "Should have seen the new frame"); @@ -158,7 +171,7 @@ exports["test frame list"] = function*(assert) { assert.equal(browserFrames(frames), getTabs(window).length, "Should be the right number of browser frames."); assert.equal((yield getChildFrameCount(processes)), frames.length, "Child processes should have the right number of frames"); - promise = promiseEvent(frames, 'attach'); + promise = promiseTabFrameAttach(frames); let tab2 = openTab(window, REMOTE_URI); let [frame2] = yield promise; assert.ok(!!frame2, "Should have seen the new frame"); @@ -256,7 +269,7 @@ exports["test unload"] = function*(assert) { let loader = new Loader(module); let { frames } = yield waitForProcesses(loader); - let promise = promiseEvent(frames, 'attach'); + let promise = promiseTabFrameAttach(frames); let tab = openTab(window, "data:,"); let browser = getBrowserForTab(tab); yield promiseDOMEvent(browser, "load", true); @@ -280,7 +293,7 @@ exports["test frame detach on unload"] = function*(assert) { let loader = new Loader(module); let { frames } = yield waitForProcesses(loader); - let promise = promiseEvent(frames, 'attach'); + let promise = promiseTabFrameAttach(frames); let tab = openTab(window, "data:,"); let browser = getBrowserForTab(tab); yield promiseDOMEvent(browser, "load", true); @@ -304,7 +317,7 @@ exports["test frame event listeners"] = function*(assert) { let loader = new Loader(module); let { frames } = yield waitForProcesses(loader); - let promise = promiseEvent(frames, 'attach'); + let promise = promiseTabFrameAttach(frames); let tab = openTab(window, "data:text/html,"); let browser = getBrowserForTab(tab); yield promiseDOMEvent(browser, "load", true); @@ -339,7 +352,7 @@ exports["test frames event listeners"] = function*(assert) { let loader = new Loader(module); let { frames } = yield waitForProcesses(loader); - let promise = promiseEvent(frames, 'attach'); + let promise = promiseTabFrameAttach(frames); let tab = openTab(window, "data:text/html,"); let browser = getBrowserForTab(tab); yield promiseDOMEvent(browser, "load", true); @@ -377,8 +390,8 @@ exports["test unload removes frame event listeners"] = function*(assert) { let loader2 = new Loader(module); let { frames: frames2 } = yield waitForProcesses(loader2); - let promise = promiseEvent(frames, 'attach'); - let promise2 = promiseEvent(frames2, 'attach'); + let promise = promiseTabFrameAttach(frames); + let promise2 = promiseTabFrameAttach(frames2); let tab = openTab(window, "data:text/html,"); let browser = getBrowserForTab(tab); yield promiseDOMEvent(browser, "load", true); @@ -418,8 +431,8 @@ exports["test unload removes frames event listeners"] = function*(assert) { let loader2 = new Loader(module); let { frames: frames2 } = yield waitForProcesses(loader2); - let promise = promiseEvent(frames, 'attach'); - let promise2 = promiseEvent(frames2, 'attach'); + let promise = promiseTabFrameAttach(frames); + let promise2 = promiseTabFrameAttach(frames2); let tab = openTab(window, "data:text/html,"); let browser = getBrowserForTab(tab); yield promiseDOMEvent(browser, "load", true); diff --git a/addon-sdk/source/test/addons/l10n/data/test-localization.html b/addon-sdk/source/test/addons/l10n/data/test-localization.html index 5428863ad8e2..5646946da35d 100644 --- a/addon-sdk/source/test/addons/l10n/data/test-localization.html +++ b/addon-sdk/source/test/addons/l10n/data/test-localization.html @@ -20,5 +20,10 @@
A data-l10n-id value can be used in multiple elements
+ + + + + { + let listener = function(frame, ...args) { + if (!frame.isTab) + return; + frames.off("attach", listener); + resolve([frame, ...args]); + } + + frames.on("attach", listener); + }); +} + // Check that we see a process stop and start exports["test process restart"] = function*(assert) { if (!isE10S) { @@ -44,7 +57,7 @@ exports["test process restart"] = function*(assert) { // Switch the remote tab to a local URI which should kill the remote process let frameDetach = promiseEventOnItemAndContainer(assert, remoteFrame, frames, 'detach'); - let frameAttach = promiseEvent(frames, 'attach'); + let frameAttach = promiseTabFrameAttach(frames); let processDetach = promiseEventOnItemAndContainer(assert, remoteProcess, processes, 'detach'); setTabURL(tab, LOCAL_URI); // The load should kill the remote frame @@ -57,7 +70,7 @@ exports["test process restart"] = function*(assert) { frameDetach = promiseEventOnItemAndContainer(assert, newFrame, frames, 'detach'); let processAttach = promiseEvent(processes, 'attach'); - frameAttach = promiseEvent(frames, 'attach'); + frameAttach = promiseTabFrameAttach(frames); setTabURL(tab, REMOTE_URI); // The load should kill the remote frame yield frameDetach; @@ -149,7 +162,7 @@ exports["test frame list"] = function*(assert) { assert.equal(browserFrames(frames), getTabs(window).length, "Should be the right number of browser frames."); assert.equal((yield getChildFrameCount(processes)), frames.length, "Child processes should have the right number of frames"); - let promise = promiseEvent(frames, 'attach'); + let promise = promiseTabFrameAttach(frames); let tab1 = openTab(window, LOCAL_URI); let [frame1] = yield promise; assert.ok(!!frame1, "Should have seen the new frame"); @@ -158,7 +171,7 @@ exports["test frame list"] = function*(assert) { assert.equal(browserFrames(frames), getTabs(window).length, "Should be the right number of browser frames."); assert.equal((yield getChildFrameCount(processes)), frames.length, "Child processes should have the right number of frames"); - promise = promiseEvent(frames, 'attach'); + promise = promiseTabFrameAttach(frames); let tab2 = openTab(window, REMOTE_URI); let [frame2] = yield promise; assert.ok(!!frame2, "Should have seen the new frame"); @@ -256,7 +269,7 @@ exports["test unload"] = function*(assert) { let loader = new Loader(module); let { frames } = yield waitForProcesses(loader); - let promise = promiseEvent(frames, 'attach'); + let promise = promiseTabFrameAttach(frames); let tab = openTab(window, "data:,"); let browser = getBrowserForTab(tab); yield promiseDOMEvent(browser, "load", true); @@ -280,7 +293,7 @@ exports["test frame detach on unload"] = function*(assert) { let loader = new Loader(module); let { frames } = yield waitForProcesses(loader); - let promise = promiseEvent(frames, 'attach'); + let promise = promiseTabFrameAttach(frames); let tab = openTab(window, "data:,"); let browser = getBrowserForTab(tab); yield promiseDOMEvent(browser, "load", true); @@ -304,7 +317,7 @@ exports["test frame event listeners"] = function*(assert) { let loader = new Loader(module); let { frames } = yield waitForProcesses(loader); - let promise = promiseEvent(frames, 'attach'); + let promise = promiseTabFrameAttach(frames); let tab = openTab(window, "data:text/html,"); let browser = getBrowserForTab(tab); yield promiseDOMEvent(browser, "load", true); @@ -339,7 +352,7 @@ exports["test frames event listeners"] = function*(assert) { let loader = new Loader(module); let { frames } = yield waitForProcesses(loader); - let promise = promiseEvent(frames, 'attach'); + let promise = promiseTabFrameAttach(frames); let tab = openTab(window, "data:text/html,"); let browser = getBrowserForTab(tab); yield promiseDOMEvent(browser, "load", true); @@ -377,8 +390,8 @@ exports["test unload removes frame event listeners"] = function*(assert) { let loader2 = new Loader(module); let { frames: frames2 } = yield waitForProcesses(loader2); - let promise = promiseEvent(frames, 'attach'); - let promise2 = promiseEvent(frames2, 'attach'); + let promise = promiseTabFrameAttach(frames); + let promise2 = promiseTabFrameAttach(frames2); let tab = openTab(window, "data:text/html,"); let browser = getBrowserForTab(tab); yield promiseDOMEvent(browser, "load", true); @@ -418,8 +431,8 @@ exports["test unload removes frames event listeners"] = function*(assert) { let loader2 = new Loader(module); let { frames: frames2 } = yield waitForProcesses(loader2); - let promise = promiseEvent(frames, 'attach'); - let promise2 = promiseEvent(frames2, 'attach'); + let promise = promiseTabFrameAttach(frames); + let promise2 = promiseTabFrameAttach(frames2); let tab = openTab(window, "data:text/html,"); let browser = getBrowserForTab(tab); yield promiseDOMEvent(browser, "load", true); diff --git a/addon-sdk/source/test/jetpack-package.ini b/addon-sdk/source/test/jetpack-package.ini index ff836c5e76f6..80b5b08a71ab 100644 --- a/addon-sdk/source/test/jetpack-package.ini +++ b/addon-sdk/source/test/jetpack-package.ini @@ -62,6 +62,7 @@ skip-if = true [test-environment.js] [test-errors.js] [test-event-core.js] +[test-event-dom.js] [test-event-target.js] [test-event-utils.js] [test-events.js] diff --git a/addon-sdk/source/test/preferences/no-connections.json b/addon-sdk/source/test/preferences/no-connections.json index 47f98847ab0b..09cf579275d3 100644 --- a/addon-sdk/source/test/preferences/no-connections.json +++ b/addon-sdk/source/test/preferences/no-connections.json @@ -13,6 +13,7 @@ "browser.aboutHomeSnippets.updateUrl": "https://localhost/snippet-dummy", "browser.newtab.url": "about:blank", "browser.search.update": false, + "browser.search.suggest.enabled": false, "browser.safebrowsing.enabled": false, "browser.safebrowsing.updateURL": "http://localhost/safebrowsing-dummy/update", "browser.safebrowsing.gethashURL": "http://localhost/safebrowsing-dummy/gethash", diff --git a/addon-sdk/source/test/private-browsing/windows.js b/addon-sdk/source/test/private-browsing/windows.js index 58215ac5a652..439ef53a486c 100644 --- a/addon-sdk/source/test/private-browsing/windows.js +++ b/addon-sdk/source/test/private-browsing/windows.js @@ -10,6 +10,7 @@ const { getMode } = require('sdk/private-browsing/utils'); const { browserWindows: windows } = require('sdk/windows'); const { defer } = require('sdk/core/promise'); const tabs = require('sdk/tabs'); +const { getMostRecentBrowserWindow } = require('sdk/window/utils'); // test openDialog() from window/utils with private option // test isActive state in pwpb case @@ -80,27 +81,22 @@ exports.testIsPrivateOnWindowOpenFromPrivate = function(assert, done) { }; exports.testOpenTabWithPrivateWindow = function*(assert) { - let { promise, resolve } = defer(); + let window = getMostRecentBrowserWindow().OpenBrowserWindow({ private: true }); - let window = yield openPromise(null, { - features: { - private: true, - toolbar: true - } - }); - yield focus(window); + assert.pass("loading new private window"); + + yield promise(window, 'load').then(focus); assert.equal(isPrivate(window), true, 'the focused window is private'); - tabs.open({ + yield new Promise(resolve => tabs.open({ url: 'about:blank', onOpen: (tab) => { assert.equal(isPrivate(tab), false, 'the opened tab is not private'); tab.close(resolve); } - }); + })); - yield promise; yield close(window); }; diff --git a/addon-sdk/source/test/tabs/utils.js b/addon-sdk/source/test/tabs/utils.js new file mode 100644 index 000000000000..4981a4d087bb --- /dev/null +++ b/addon-sdk/source/test/tabs/utils.js @@ -0,0 +1,24 @@ +/* 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/. */ +"use strict"; + +const { openTab: makeTab, getTabContentWindow } = require("sdk/tabs/utils"); + +function openTab(rawWindow, url) { + return new Promise(resolve => { + let tab = makeTab(rawWindow, url); + let window = getTabContentWindow(tab); + if (window.document.readyState == "complete") { + return resolve(); + } + + window.addEventListener("load", function onLoad() { + window.removeEventListener("load", onLoad, true); + resolve(); + }, true); + + return null; + }) +} +exports.openTab = openTab; diff --git a/addon-sdk/source/test/test-event-dom.js b/addon-sdk/source/test/test-event-dom.js new file mode 100644 index 000000000000..fbbc6825bf88 --- /dev/null +++ b/addon-sdk/source/test/test-event-dom.js @@ -0,0 +1,92 @@ +/* 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/. */ +'use strict'; + +const { openWindow, closeWindow } = require('./util'); +const { Loader } = require('sdk/test/loader'); +const { getMostRecentBrowserWindow } = require('sdk/window/utils'); +const { Cc, Ci } = require('chrome'); +const els = Cc["@mozilla.org/eventlistenerservice;1"]. + getService(Ci.nsIEventListenerService); + +function countListeners(target, type) { + let listeners = els.getListenerInfoFor(target, {}); + return listeners.filter(listener => listener.type == type).length; +} + +exports['test window close clears listeners'] = function(assert) { + let window = yield openWindow(); + let loader = Loader(module); + + // Any element will do here + let gBrowser = window.gBrowser; + + // Other parts of the app may be listening for this + let windowListeners = countListeners(window, "DOMWindowClose"); + + // We can assume we're the only ones using the test events + assert.equal(countListeners(gBrowser, "TestEvent1"), 0, "Should be no listener for test event 1"); + assert.equal(countListeners(gBrowser, "TestEvent2"), 0, "Should be no listener for test event 2"); + + let { open } = loader.require('sdk/event/dom'); + + open(gBrowser, "TestEvent1"); + assert.equal(countListeners(window, "DOMWindowClose"), windowListeners + 1, + "Should have added a DOMWindowClose listener"); + assert.equal(countListeners(gBrowser, "TestEvent1"), 1, "Should be a listener for test event 1"); + assert.equal(countListeners(gBrowser, "TestEvent2"), 0, "Should be no listener for test event 2"); + + open(gBrowser, "TestEvent2"); + assert.equal(countListeners(window, "DOMWindowClose"), windowListeners + 1, + "Should not have added another DOMWindowClose listener"); + assert.equal(countListeners(gBrowser, "TestEvent1"), 1, "Should be a listener for test event 1"); + assert.equal(countListeners(gBrowser, "TestEvent2"), 1, "Should be a listener for test event 2"); + + window = yield closeWindow(window); + + assert.equal(countListeners(window, "DOMWindowClose"), windowListeners, + "Should have removed a DOMWindowClose listener"); + assert.equal(countListeners(gBrowser, "TestEvent1"), 0, "Should be no listener for test event 1"); + assert.equal(countListeners(gBrowser, "TestEvent2"), 0, "Should be no listener for test event 2"); + + loader.unload(); +}; + +exports['test unload clears listeners'] = function(assert) { + let window = getMostRecentBrowserWindow(); + let loader = Loader(module); + + // Any element will do here + let gBrowser = window.gBrowser; + + // Other parts of the app may be listening for this + let windowListeners = countListeners(window, "DOMWindowClose"); + + // We can assume we're the only ones using the test events + assert.equal(countListeners(gBrowser, "TestEvent1"), 0, "Should be no listener for test event 1"); + assert.equal(countListeners(gBrowser, "TestEvent2"), 0, "Should be no listener for test event 2"); + + let { open } = loader.require('sdk/event/dom'); + + open(gBrowser, "TestEvent1"); + assert.equal(countListeners(window, "DOMWindowClose"), windowListeners + 1, + "Should have added a DOMWindowClose listener"); + assert.equal(countListeners(gBrowser, "TestEvent1"), 1, "Should be a listener for test event 1"); + assert.equal(countListeners(gBrowser, "TestEvent2"), 0, "Should be no listener for test event 2"); + + open(gBrowser, "TestEvent2"); + assert.equal(countListeners(window, "DOMWindowClose"), windowListeners + 1, + "Should not have added another DOMWindowClose listener"); + assert.equal(countListeners(gBrowser, "TestEvent1"), 1, "Should be a listener for test event 1"); + assert.equal(countListeners(gBrowser, "TestEvent2"), 1, "Should be a listener for test event 2"); + + loader.unload(); + + assert.equal(countListeners(window, "DOMWindowClose"), windowListeners, + "Should have removed a DOMWindowClose listener"); + assert.equal(countListeners(gBrowser, "TestEvent1"), 0, "Should be no listener for test event 1"); + assert.equal(countListeners(gBrowser, "TestEvent2"), 0, "Should be no listener for test event 2"); +}; + +require('sdk/test').run(exports); diff --git a/addon-sdk/source/test/test-native-loader.js b/addon-sdk/source/test/test-native-loader.js index a945310269e0..69a4b810bfd7 100644 --- a/addon-sdk/source/test/test-native-loader.js +++ b/addon-sdk/source/test/test-native-loader.js @@ -48,6 +48,14 @@ exports['test nodeResolve'] = function (assert) { './node_modules/test-math/node_modules/test-add/index.js', 'Dependencies\' dependencies can be found'); + resolveTest('resource://gre/modules/commonjs/sdk/tabs.js', './index.js', undefined, + 'correctly ignores absolute URIs.'); + + resolveTest('../tabs', 'resource://gre/modules/commonjs/sdk/addon/bootstrap.js', undefined, + 'correctly ignores attempts to resolve from a module at an absolute URI.'); + + resolveTest('sdk/tabs', 'resource://gre/modules/commonjs/sdk/addon/bootstrap.js', undefined, + 'correctly ignores attempts to resolve from a module at an absolute URI.'); function resolveTest (id, requirer, expected, msg) { let result = nodeResolve(id, requirer, { manifest: manifest, rootURI: rootURI }); diff --git a/addon-sdk/source/test/test-ui-sidebar.js b/addon-sdk/source/test/test-ui-sidebar.js index 49394f5bb909..2302d40d9028 100644 --- a/addon-sdk/source/test/test-ui-sidebar.js +++ b/addon-sdk/source/test/test-ui-sidebar.js @@ -1491,12 +1491,17 @@ exports.testShowHideRawWindowArg = function*(assert) { const { Sidebar } = require('sdk/ui/sidebar'); let testName = 'testShowHideRawWindowArg'; + + assert.pass("Creating sidebar"); + let sidebar = Sidebar({ id: testName, title: testName, url: 'data:text/html;charset=utf-8,' + testName }); + assert.pass("Created sidebar"); + let mainWindow = getMostRecentBrowserWindow(); let newWindow = yield windowPromise(mainWindow.OpenBrowserWindow(), 'load'); assert.pass("Created the new window"); @@ -1504,21 +1509,26 @@ exports.testShowHideRawWindowArg = function*(assert) { yield focus(newWindow); assert.pass("Focused the new window"); - yield focus(mainWindow); - assert.pass("Focused the old window"); + let newWindow2 = yield windowPromise(mainWindow.OpenBrowserWindow(), 'load'); + assert.pass("Created the second new window"); + + yield focus(newWindow2); + assert.pass("Focused the second new window"); yield sidebar.show(newWindow); assert.pass('the sidebar was shown'); assert.equal(isSidebarShowing(mainWindow), false, 'sidebar is not showing in main window'); + assert.equal(isSidebarShowing(newWindow2), false, 'sidebar is not showing in second window'); assert.equal(isSidebarShowing(newWindow), true, 'sidebar is showing in new window'); - assert.ok(isFocused(mainWindow), 'main window is still focused'); + assert.ok(isFocused(newWindow2), 'main window is still focused'); yield sidebar.hide(newWindow); - assert.equal(isFocused(mainWindow), true, 'main window is still focused'); + assert.equal(isFocused(newWindow2), true, 'second window is still focused'); assert.equal(isSidebarShowing(mainWindow), false, 'sidebar is not showing in main window'); + assert.equal(isSidebarShowing(newWindow2), false, 'sidebar is not showing in second window'); assert.equal(isSidebarShowing(newWindow), false, 'sidebar is not showing in new window'); sidebar.destroy(); diff --git a/addon-sdk/source/test/util.js b/addon-sdk/source/test/util.js index d57afacb45d3..e3bc01bc11b1 100644 --- a/addon-sdk/source/test/util.js +++ b/addon-sdk/source/test/util.js @@ -31,7 +31,7 @@ const openWindow = () => { exports.openWindow = openWindow; const closeWindow = (window) => { - const closed = when(window, "unload", true).then(_target); + const closed = when(window, "unload", true).then(_ => window); window.close(); return closed; }; diff --git a/addon-sdk/source/test/windows/test-firefox-windows.js b/addon-sdk/source/test/windows/test-firefox-windows.js index 4f6e6e8a551c..52993b77e807 100644 --- a/addon-sdk/source/test/windows/test-firefox-windows.js +++ b/addon-sdk/source/test/windows/test-firefox-windows.js @@ -7,7 +7,7 @@ const { Cc, Ci } = require('chrome'); const { setTimeout } = require('sdk/timers'); const { Loader } = require('sdk/test/loader'); const { onFocus, getMostRecentWindow, windows, isBrowser, getWindowTitle, isFocused } = require('sdk/window/utils'); -const { open, close, focus } = require('sdk/window/helpers'); +const { open, close, focus, promise: windowPromise } = require('sdk/window/helpers'); const { browserWindows } = require("sdk/windows"); const tabs = require("sdk/tabs"); const winUtils = require("sdk/deprecated/window-utils"); @@ -17,6 +17,9 @@ const { viewFor } = require("sdk/view/core"); const { defer } = require("sdk/lang/functional"); const { cleanUI } = require("sdk/test/utils"); const { after } = require("sdk/test/utils"); +const { merge } = require("sdk/util/object"); +const self = require("sdk/self"); +const { openTab } = require("../tabs/utils"); // TEST: open & close window exports.testOpenAndCloseWindow = function(assert, done) { @@ -59,12 +62,9 @@ exports.testNeWindowIsFocused = function(assert, done) { }); } -exports.testOpenRelativePathWindow = function(assert, done) { +exports.testOpenRelativePathWindow = function*(assert) { assert.equal(browserWindows.length, 1, "Only one window open"); - const { merge } = require("sdk/util/object"); - const self = require("sdk/self"); - let loader = Loader(module, null, null, { modules: { "sdk/self": merge({}, self, { @@ -72,17 +72,31 @@ exports.testOpenRelativePathWindow = function(assert, done) { }) } }); + assert.pass("Created a new loader"); - loader.require("sdk/windows").browserWindows.open({ - url: "./test.html", - onOpen: (window) => { - window.tabs.activeTab.once("ready", (tab) => { - assert.equal(tab.title, "foo", - "tab opened a document with relative path"); - done(); - }); - } - }) + let tabReady = new Promise(resolve => { + loader.require("sdk/tabs").on("ready", (tab) => { + if (!/test\.html$/.test(tab.url)) + return; + assert.equal(tab.title, "foo", + "tab opened a document with relative path"); + resolve(); + }); + }); + + + yield new Promise(resolve => { + loader.require("sdk/windows").browserWindows.open({ + url: "./test.html", + onOpen: (window) => { + assert.pass("Created a new window"); + resolve(); + } + }) + }); + + yield tabReady; + loader.unload(); } exports.testAutomaticDestroy = function(assert, done) { @@ -218,52 +232,26 @@ exports.testOnOpenOnCloseListeners = function(assert, done) { exports.testActiveWindow = function*(assert) { let windows = browserWindows; - - // API window objects - let window2, window3; + let window = getMostRecentWindow(); // Raw window objects - let rawWindow2, rawWindow3; + let rawWindow2 = yield windowPromise(window.OpenBrowserWindow(), "load").then(focus); + assert.pass("Window 2 was created"); - yield new Promise(resolve => { - windows.open({ - url: "data:text/html;charset=utf-8,window 2", - onOpen: (window) => { - assert.pass('window 2 open'); + // open a tab in window 2 + yield openTab(rawWindow2, "data:text/html;charset=utf-8,window 2"); - window.tabs.activeTab.once('ready', () => { - assert.pass('window 2 tab activated'); + assert.equal(rawWindow2.content.document.title, "window 2", "Got correct raw window 2"); + assert.equal(rawWindow2.document.title, windows[1].title, "Saw correct title on window 2"); - window2 = window; - rawWindow2 = viewFor(window); + let rawWindow3 = yield windowPromise(window.OpenBrowserWindow(), "load").then(focus);; + assert.pass("Window 3 was created"); - assert.equal(rawWindow2.content.document.title, "window 2", "Got correct raw window 2"); - assert.equal(rawWindow2.document.title, window2.title, "Saw correct title on window 2"); + // open a tab in window 3 + yield openTab(rawWindow3, "data:text/html;charset=utf-8,window 3"); - windows.open({ - url: "data:text/html;charset=utf-8,window 3", - onOpen: (window) => { - assert.pass('window 3 open'); - - window.tabs.activeTab.once('ready', () => { - assert.pass('window 3 tab activated'); - - window3 = window; - rawWindow3 = viewFor(window); - - assert.equal(rawWindow3.content.document.title, "window 3", "Got correct raw window 3"); - assert.equal(rawWindow3.document.title, window3.title, "Saw correct title on window 3"); - - resolve(); - }); - } - }); - }); - } - }); - }); - - yield focus(rawWindow3); + assert.equal(rawWindow3.content.document.title, "window 3", "Got correct raw window 3"); + assert.equal(rawWindow3.document.title, windows[2].title, "Saw correct title on window 3"); assert.equal(windows.length, 3, "Correct number of browser windows"); @@ -272,11 +260,13 @@ exports.testActiveWindow = function*(assert) { count++; } assert.equal(count, 3, "Correct number of windows returned by iterator"); - assert.equal(windows.activeWindow.title, window3.title, "Correct active window title - 3"); + assert.equal(windows.activeWindow.title, windows[2].title, "Correct active window title - 3"); + let window3 = windows[2]; yield focus(rawWindow2); - assert.equal(windows.activeWindow.title, window2.title, "Correct active window title - 2"); + assert.equal(windows.activeWindow.title, windows[1].title, "Correct active window title - 2"); + let window2 = windows[1]; yield new Promise(resolve => { onFocus(rawWindow2).then(resolve); @@ -284,7 +274,7 @@ exports.testActiveWindow = function*(assert) { assert.pass("activating window2"); }); - assert.equal(windows.activeWindow.title, window2.title, "Correct active window - 2"); + assert.equal(windows.activeWindow.title, windows[1].title, "Correct active window - 2"); yield new Promise(resolve => { onFocus(rawWindow3).then(resolve); @@ -391,21 +381,32 @@ exports.testTrackWindows = function(assert, done) { } // test that it is not possible to open a private window by default -exports.testWindowOpenPrivateDefault = function(assert, done) { - browserWindows.open({ - url: 'about:mozilla', +exports.testWindowOpenPrivateDefault = function*(assert) { + const TITLE = "yo"; + const URL = "data:text/html," + TITLE + ""; + + let tabReady = new Promise(resolve => { + tabs.on('ready', function onTabReady(tab) { + if (tab.url != URL) + return; + + tabs.removeListener('ready', onTabReady); + assert.equal(tab.title, TITLE, 'opened correct tab'); + assert.equal(isPrivate(tab), false, 'tab is not private'); + resolve(); + }); + }) + + yield new Promise(resolve => browserWindows.open({ + url: URL, isPrivate: true, onOpen: function(window) { - let tab = window.tabs[0]; - - tab.once('ready', function() { - assert.equal(tab.url, 'about:mozilla', 'opened correct tab'); - assert.equal(isPrivate(tab), false, 'tab is not private'); - - done(); - }); + assert.pass("the new window was opened"); + resolve(); } - }); + })); + + yield tabReady; } // test that it is not possible to find a private window in diff --git a/browser/base/content/browser-loop.js b/browser/base/content/browser-loop.js index ac9b6d43ebaf..45c199134130 100644 --- a/browser/base/content/browser-loop.js +++ b/browser/base/content/browser-loop.js @@ -490,7 +490,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "PanelFrame", "resource:///modules/Panel let wasVisible = false; // Hide the infobar from the previous tab. - if (event.detail.previousTabfromTab) { + if (event.detail.previousTab) { wasVisible = this._hideBrowserSharingInfoBar(false, event.detail.previousTab.linkedBrowser); } diff --git a/browser/base/content/popup-notifications.inc b/browser/base/content/popup-notifications.inc index 4082f4a36c0a..2fd8731bfb57 100644 --- a/browser/base/content/popup-notifications.inc +++ b/browser/base/content/popup-notifications.inc @@ -62,7 +62,7 @@