Bug 1075429 - Uplift Add-on SDK to Firefox

cbf6cdd0d6...34141d4d4c
This commit is contained in:
Erik Vold 2014-10-02 19:41:36 +01:00
parent 463669b918
commit 94442589b3
38 changed files with 15799 additions and 5672 deletions

View File

@ -184,7 +184,6 @@ EXTRA_JS_MODULES.commonjs.node += [
]
EXTRA_JS_MODULES.commonjs.sdk += [
'source/lib/sdk/addon-page.js',
'source/lib/sdk/base64.js',
'source/lib/sdk/clipboard.js',
'source/lib/sdk/context-menu.js',

View File

@ -3,9 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// bug 673569 - let each frame script have its own anonymous scope
(function() {
const observerSvc = Components.classes["@mozilla.org/observer-service;1"].
getService(Components.interfaces.nsIObserverService);
@ -18,27 +15,20 @@ const EVENTS = {
// 'content-page-shown': 'pageshow', // bug 1024105
}
let listener = {
observe: function(subject, topic) {
// observer service keeps a strong reference to the listener, and this
// method can get called after the tab is closed, so we should remove it.
if (!docShell) {
observerSvc.removeObserver(this, topic);
}
else {
if (subject === content.document)
sendAsyncMessage('sdk/tab/event', { type: EVENTS[topic] });
}
}
function listener(subject, topic) {
// observer service keeps a strong reference to the listener, and this
// method can get called after the tab is closed, so we should remove it.
if (!docShell)
observerSvc.removeObserver(listener, topic);
else if (subject === content.document)
sendAsyncMessage('sdk/tab/event', { type: EVENTS[topic] });
}
Object.keys(EVENTS).forEach( (topic) =>
observerSvc.addObserver(listener, topic, false));
for (let topic in EVENTS)
observerSvc.addObserver(listener, topic, false);
// bug 1024105 - content-page-shown notification doesn't pass persisted param
docShell.chromeEventHandler.addEventListener('pageshow', (e) => {
if (e.target === content.document)
sendAsyncMessage('sdk/tab/event', { type: e.type, persisted: e.persisted });
addEventListener('pageshow', ({ target, type, persisted }) => {
if (target === content.document)
sendAsyncMessage('sdk/tab/event', { type, persisted });
}, true);
})();

View File

@ -1,73 +0,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/. */
'use strict';
module.metadata = {
'stability': 'deprecated'
};
const { WindowTracker } = require('./deprecated/window-utils');
const { isXULBrowser } = require('./window/utils');
const { add, remove } = require('./util/array');
const { getTabs, closeTab, getURI } = require('./tabs/utils');
const { data } = require('./self');
const { ns } = require("./core/namespace");
const addonURL = data.url('index.html');
const windows = ns();
require("./util/deprecate").deprecateUsage(
"The addon-page module is deprecated." +
"In the new Firefox UI design all pages will include navigational elements;" +
"once the new design ships, using the addon-page module will not have any effect."
);
WindowTracker({
onTrack: function onTrack(window) {
if (!isXULBrowser(window) || windows(window).hideChromeForLocation)
return;
let { XULBrowserWindow } = window;
let { hideChromeForLocation } = XULBrowserWindow;
windows(window).hideChromeForLocation = hideChromeForLocation;
// Augmenting the behavior of `hideChromeForLocation` method, as
// suggested by https://developer.mozilla.org/en-US/docs/Hiding_browser_chrome
XULBrowserWindow.hideChromeForLocation = function(url) {
return isAddonURL(url) || hideChromeForLocation.call(this, url);
}
},
onUntrack: function onUntrack(window) {
if (isXULBrowser(window))
getTabs(window).filter(tabFilter).forEach(untrackTab.bind(null, window));
}
});
function isAddonURL(url) {
if (url.indexOf(addonURL) === 0) {
let rest = url.substr(addonURL.length);
return ((rest.length === 0) || (['#','?'].indexOf(rest.charAt(0)) > -1));
}
return false;
}
function tabFilter(tab) {
return isAddonURL(getURI(tab));
}
function untrackTab(window, tab) {
// Note: `onUntrack` will be called for all windows on add-on unloads,
// so we want to clean them up from these URLs.
let { hideChromeForLocation } = windows(window);
if (hideChromeForLocation) {
window.XULBrowserWindow.hideChromeForLocation = hideChromeForLocation.bind(window.XULBrowserWindow);
windows(window).hideChromeForLocation = null;
}
closeTab(tab);
}

View File

@ -73,6 +73,7 @@ TestRunner.prototype = {
this.console.info("pass:", message);
this.passed++;
this.test.passed++;
this.test.last = message;
}
else {
this.expectFailure = false;
@ -110,6 +111,7 @@ TestRunner.prototype = {
this.console.info("pass:", message);
this.passed++;
this.test.passed++;
this.test.last = message;
}
},
@ -467,10 +469,11 @@ TestRunner.prototype = {
function tiredOfWaiting() {
self._logTestFailed("timed out");
if ("testMessage" in self.console) {
self.console.testMessage(false, false, self.test.name, "Test timed out");
self.console.testMessage(false, false, self.test.name,
`Test timed out (after: ${self.test.last})`);
}
else {
self.console.error("fail:", "Timed out")
self.console.error("fail:", `Timed out (after: ${self.test.last})`)
}
if (self.waitUntilCallback) {
self.waitUntilCallback(true);
@ -514,6 +517,7 @@ TestRunner.prototype = {
this.test.passed = 0;
this.test.failed = 0;
this.test.errors = {};
this.test.last = 'START';
PromiseDebugging.clearUncaughtErrorObservers();
PromiseDebugging.addUncaughtErrorObserver(this._uncaughtErrorObserver.bind(this));

View File

@ -142,6 +142,7 @@ const PageMod = Class({
}
pagemods.add(this);
model.seenDocuments = new WeakMap();
// `applyOnExistingDocuments` has to be called after `pagemods.add()`
// otherwise its calls to `onContent` method won't do anything.
@ -232,6 +233,12 @@ function onContent (mod, window) {
if (!isTopDocument && !has(mod.attachTo, "frame"))
return;
// ensure we attach only once per document
let seen = modelFor(mod).seenDocuments;
if (seen.has(window.document))
return;
seen.set(window.document, true);
let style = styleFor(mod);
if (style)
attach(style, window);

View File

@ -63,6 +63,10 @@ exports.exit = function exit(code) {
let resultsFile = 'resultFile' in options && options.resultFile;
function unloader() {
if (!options.resultFile) {
return;
}
// This is used by 'cfx' to find out exit code.
let mode = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE;
let stream = openFile(options.resultFile, mode);
@ -70,6 +74,7 @@ exports.exit = function exit(code) {
stream.write(status, status.length);
stream.flush();
stream.close();
return;
}
if (code == 0) {
@ -78,10 +83,7 @@ exports.exit = function exit(code) {
// Bug 856999: Prevent automatic kill of Firefox when running tests
if (options.noQuit) {
if (resultsFile) {
unload(unloader);
}
return;
return unload(unloader);
}
unloader();

View File

@ -4,11 +4,7 @@
"use strict";
module.metadata = {
"stability": "unstable",
"engines": {
"Firefox": "*",
"Fennec": "*"
}
"stability": "unstable"
};
const { modelFor } = require("./model/core");

View File

@ -22,9 +22,7 @@ const { getURL } = require('../url/utils');
const { viewFor } = require('../view/core');
const { observer } = require('./observer');
// cfx doesn't know require() now handles JSM modules
const FRAMESCRIPT_MANAGER = '../../framescript/FrameScriptManager.jsm';
require(FRAMESCRIPT_MANAGER).enableTabEvents();
require('../../framescript/FrameScriptManager.jsm').enableTabEvents();
// Array of the inner instances of all the wrapped tabs.
const TABS = [];
@ -62,7 +60,7 @@ const TabTrait = Trait.compose(EventEmitter, {
this.on(EVENTS.close.name, this.destroy.bind(this));
this._onContentEvent = this._onContentEvent.bind(this);
this._browser.messageManager.addMessageListener('sdk/tab/event', this._onContentEvent);
this._window.messageManager.addMessageListener('sdk/tab/event', this._onContentEvent);
// bug 1024632 - first tab inNewWindow gets events from the synthetic
// about:blank document. ignore them unless that is the actual target url.
@ -86,11 +84,7 @@ const TabTrait = Trait.compose(EventEmitter, {
destroy: function destroy() {
this._removeAllListeners();
if (this._tab) {
let browser = this._browser;
// The tab may already be removed from DOM -or- not yet added
if (browser) {
browser.messageManager.removeMessageListener('sdk/tab/event', this._onContentEvent);
}
this._window.messageManager.removeMessageListener('sdk/tab/event', this._onContentEvent);
this._tab = null;
TABS.splice(TABS.indexOf(this), 1);
}
@ -100,7 +94,10 @@ const TabTrait = Trait.compose(EventEmitter, {
* internal message listener emits public events (ready, load and pageshow)
* forwarded from content frame script tab-event.js
*/
_onContentEvent: function({ data }) {
_onContentEvent: function({ target, data }) {
if (target !== this._browser)
return;
// bug 1024632 - skip initial events from synthetic about:blank document
if (this._skipBlankEvents && this.window.tabs.length === 1 && this.url === 'about:blank')
return;

View File

@ -4,11 +4,7 @@
'use strict';
module.metadata = {
'stability': 'unstable',
'engines': {
'Firefox': '*',
'Fennec': '*'
}
'stability': 'unstable'
};
const { getTargetWindow } = require("../content/mod");

File diff suppressed because it is too large Load Diff

View File

@ -145,15 +145,20 @@ function URL(url, base) {
Object.defineProperties(this, {
toString: {
value: function URL_toString() new String(uri.spec).toString(),
value() new String(uri.spec).toString(),
enumerable: false
},
valueOf: {
value: function() new String(uri.spec).valueOf(),
value() new String(uri.spec).valueOf(),
enumerable: false
},
toSource: {
value: function() new String(uri.spec).toSource(),
value() new String(uri.spec).toSource(),
enumerable: false
},
// makes more sense to flatten to string, easier to travel across JSON
toJSON: {
value() new String(uri.spec).toString(),
enumerable: false
}
});

View File

@ -11,7 +11,7 @@ const { getWindowTitle } = require('./utils');
const unload = require('../system/unload');
const { EventTarget } = require('../event/target');
const { isPrivate } = require('../private-browsing/utils');
const { isWindowPrivate } = require('../window/utils');
const { isWindowPrivate, isFocused } = require('../window/utils');
const { viewFor } = require('../view/core');
const ERR_FENNEC_MSG = 'This method is not yet supported by Fennec, consider using require("sdk/tabs") instead';
@ -43,5 +43,6 @@ exports.BrowserWindow = BrowserWindow;
const getWindowView = window => windowNS(window).window;
isPrivate.define(BrowserWindow, window => isWindowPrivate(windowNS(this).window));
viewFor.define(BrowserWindow, getWindowView);
isPrivate.define(BrowserWindow, (window) => isWindowPrivate(viewFor(window).window));
isFocused.define(BrowserWindow, (window) => isFocused(viewFor(window).window));

View File

@ -10,6 +10,7 @@ module.metadata = {
const { Cc, Ci } = require('chrome');
const array = require('../util/array');
const { defer } = require('sdk/core/promise');
const { dispatcher } = require("../util/dispatcher");
const windowWatcher = Cc['@mozilla.org/embedcomp/window-watcher;1'].
getService(Ci.nsIWindowWatcher);
@ -216,7 +217,8 @@ function onFocus(window) {
}
exports.onFocus = onFocus;
function isFocused(window) {
let isFocused = dispatcher("window-isFocused");
isFocused.when(x => x instanceof Ci.nsIDOMWindow, (window) => {
const FM = Cc["@mozilla.org/focus-manager;1"].
getService(Ci.nsIFocusManager);
@ -231,7 +233,7 @@ function isFocused(window) {
}
return (focusedChildWindow === childTargetWindow);
}
});
exports.isFocused = isFocused;
/**

View File

@ -4,11 +4,7 @@
'use strict';
module.metadata = {
'stability': 'stable',
'engines': {
'Firefox': '*',
'Fennec': '*'
}
'stability': 'stable'
};
const { isBrowser } = require('./window/utils');

View File

@ -10,7 +10,7 @@ const { Cc, Ci, Cr } = require('chrome'),
{ WindowTabs, WindowTabTracker } = require('./tabs-firefox'),
{ WindowDom } = require('./dom'),
{ WindowLoader } = require('./loader'),
{ isBrowser, getWindowDocShell,
{ isBrowser, getWindowDocShell, isFocused,
windows: windowIterator, isWindowPrivate } = require('../window/utils'),
{ Options } = require('../tabs/common'),
apiUtils = require('../deprecated/api-utils'),
@ -79,9 +79,7 @@ const BrowserWindowTrait = Trait.compose(
this._load();
windowNS(this._public).window = this._window;
isPrivate.implement(this._public, window => isWindowPrivate(getChromeWindow(window)));
viewFor.implement(this._public, getChromeWindow);
viewFor.implement(this._public, (w) => windowNS(w).window);
return this;
},
@ -265,8 +263,8 @@ const browserWindows = Trait.resolve({ toString: null }).compose(
}).resolve({ toString: null })
)();
function getChromeWindow(window) {
return windowNS(window).window;
}
const isBrowserWindow = (x) => x instanceof BrowserWindow;
isPrivate.when(isBrowserWindow, (w) => isWindowPrivate(viewFor(w)));
isFocused.when(isBrowserWindow, (w) => isFocused(viewFor(w)));
exports.browserWindows = browserWindows;

View File

@ -397,49 +397,6 @@ const resolve = iced(function resolve(id, base) {
});
exports.resolve = resolve;
function fileExists(uri) {
let url = NetUtil.newURI(uri);
switch (url.scheme) {
case "jar":
let jarfile = url.QueryInterface(Ci.nsIJARURI).JARFile;
// Don't support nested JARs for now
if (!(jarfile instanceof Ci.nsIFileURL))
return false;
let zipcache = Cc["@mozilla.org/libjar/zip-reader-cache;1"].
getService(Ci.nsIZipReaderCache);
let zipreader = zipcache.getZip(jarfile.file);
return zipreader.hasEntry(jarfile.JAREntry);
case "file":
return url.QueryInterface(Ci.nsIFileURL).file.exists();
case "chrome":
let registry = Cc["@mozilla.org/chrome/chrome-registry;1"].
getService(Ci.nsIChromeRegistry)
return fileExists(ChromeRegistry.convertChromeURL(url).spec);
case "resource":
let handler = Cc["@mozilla.org/network/protocol;1?name=resource"].
getService(Ci.nsIResProtocolHandler);
let resolved;
try {
resolved = handler.resolveURI(url);
}
catch (e) {
// Resource protocol handler throws for unknown mappings
return false;
}
return fileExists(resolved);
default:
// Don't handle other URI schemes for now
return false;
}
}
// Node-style module lookup
// Takes an id and path and attempts to load a file using node's resolving
// algorithm.
@ -454,7 +411,7 @@ const nodeResolve = iced(function nodeResolve(id, requirer, { rootURI }) {
let fullId = join(rootURI, id);
let resolvedPath;
if ((resolvedPath = findFile(fullId)))
if ((resolvedPath = loadAsFile(fullId)))
return stripBase(rootURI, resolvedPath);
if ((resolvedPath = loadAsDirectory(fullId)))
@ -464,7 +421,7 @@ const nodeResolve = iced(function nodeResolve(id, requirer, { rootURI }) {
// in the `dependencies` list
let dirs = getNodeModulePaths(dirname(join(rootURI, requirer))).map(dir => join(dir, id));
for (let i = 0; i < dirs.length; i++) {
if ((resolvedPath = findFile(dirs[i])))
if ((resolvedPath = loadAsFile(dirs[i])))
return stripBase(rootURI, resolvedPath);
if ((resolvedPath = loadAsDirectory(dirs[i])))
@ -478,20 +435,23 @@ const nodeResolve = iced(function nodeResolve(id, requirer, { rootURI }) {
});
exports.nodeResolve = nodeResolve;
// Attempts to find `path` and then `path.js`
// Attempts to load `path` and then `path.js`
// Returns `path` with valid file, or `undefined` otherwise
function findFile (path) {
function loadAsFile (path) {
let found;
// As per node's loader spec,
// we first should try and load 'path' (with no extension)
// before trying 'path.js'. We will not support this feature
// due to performance, but may add it if necessary for adoption.
try {
// Append '.js' to path name unless it's another support filetype
path = normalizeExt(path);
readURI(path);
found = path;
} catch (e) {}
// Append '.js' to path name unless it's another support filetype
path = normalizeExt(path);
if (fileExists(path))
return path;
return null;
return found;
}
// Attempts to load `path/package.json`'s `main` entry,
@ -500,21 +460,25 @@ function loadAsDirectory (path) {
try {
// If `path/package.json` exists, parse the `main` entry
// and attempt to load that
if (fileExists(path + '/package.json')) {
let main = getManifestMain(JSON.parse(readURI(path + '/package.json')));
if (main != null) {
let tmpPath = join(path, main);
let found = findFile(tmpPath);
if (found)
return found
}
let main = getManifestMain(JSON.parse(readURI(path + '/package.json')));
if (main != null) {
let tmpPath = join(path, main);
let found = loadAsFile(tmpPath);
if (found)
return found
}
} catch (e) { }
let tmpPath = path + '/index.js';
if (fileExists(tmpPath))
return tmpPath;
try {
let tmpPath = path + '/index.js';
readURI(tmpPath);
return tmpPath;
} catch (e) {}
} catch (e) {
try {
let tmpPath = path + '/index.js';
readURI(tmpPath);
return tmpPath;
} catch (e) {}
}
return void 0;
}

View File

@ -49,9 +49,6 @@
"collection": "sdk/util/collection",
"array": "sdk/util/array",
"cortex": "sdk/deprecated/cortex",
"addon-page": "sdk/addon-page",
"clipboard": "sdk/clipboard",
"context-menu": "sdk/context-menu",
"hotkeys": "sdk/hotkeys",
@ -72,7 +69,6 @@
"timers": "sdk/timers",
"widget": "sdk/widget",
"windows": "sdk/windows",
"harness": "sdk/test/harness",
"run-tests": "sdk/test/runner",
"test": "sdk/test"

View File

@ -1,7 +1,7 @@
/* 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";
'use strict';
const { id } = require("sdk/self");
const { getAddonByID } = require("sdk/addon/manager");
@ -11,4 +11,4 @@ exports["test getAddonByID"] = function*(assert) {
assert.equal(addon.id, id, "getAddonByID works");
}
require("sdk/test").run(exports);
require('sdk/test/runner').runTestsFromModule(module);

View File

@ -0,0 +1,3 @@
{
"id": "test-addon-manager"
}

View File

@ -1,13 +0,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/. -->
<html>
<head>
<meta charset="UTF-8">
<title>Add-on Page</title>
</head>
<body>
<p>This is an add-on page test!</p>
</body>
</html>

View File

@ -1,202 +0,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/. */
'use strict';
const { isTabOpen, activateTab, openTab,
closeTab, getTabURL, getWindowHoldingTab } = require('sdk/tabs/utils');
const windows = require('sdk/deprecated/window-utils');
const { LoaderWithHookedConsole } = require('sdk/test/loader');
const { setTimeout } = require('sdk/timers');
const app = require("sdk/system/xul-app");
const tabs = require('sdk/tabs');
const isAustralis = "gCustomizeMode" in windows.activeBrowserWindow;
const { set: setPref, get: getPref } = require("sdk/preferences/service");
const { PrefsTarget } = require("sdk/preferences/event-target");
const { defer } = require('sdk/core/promise');
const DEPRECATE_PREF = "devtools.errorconsole.deprecation_warnings";
let uri = require('sdk/self').data.url('index.html');
function closeTabPromise(tab) {
let { promise, resolve } = defer();
let url = getTabURL(tab);
tabs.on('close', function onCloseTab(t) {
if (t.url == url) {
tabs.removeListener('close', onCloseTab);
setTimeout(_ => resolve(tab))
}
});
closeTab(tab);
return promise;
}
function isChromeVisible(window) {
let x = window.document.documentElement.getAttribute('disablechrome')
return x !== 'true';
}
// Once Bug 903018 is resolved, just move the application testing to
// module.metadata.engines
if (app.is('Firefox')) {
exports['test add-on page deprecation message'] = function(assert, done) {
let { loader, messages } = LoaderWithHookedConsole(module);
loader.require('sdk/preferences/event-target').PrefsTarget({
branchName: "devtools.errorconsole."
}).on("deprecation_warnings", function() {
if (!getPref(DEPRECATE_PREF, false)) {
return undefined;
}
loader.require('sdk/addon-page');
assert.equal(messages.length, 1, "only one error is dispatched");
assert.equal(messages[0].type, "error", "the console message is an error");
let msg = messages[0].msg;
assert.ok(msg.indexOf("DEPRECATED") === 0,
"The message is deprecation message");
loader.unload();
done();
return undefined;
});
setPref(DEPRECATE_PREF, false);
setPref(DEPRECATE_PREF, true);
};
exports['test that add-on page has no chrome'] = function(assert, done) {
let { loader } = LoaderWithHookedConsole(module);
loader.require('sdk/addon-page');
let window = windows.activeBrowserWindow;
let tab = openTab(window, uri);
assert.ok(isChromeVisible(window), 'chrome is visible for non addon page');
// need to do this in another turn to make sure event listener
// that sets property has time to do that.
setTimeout(function() {
activateTab(tab);
assert.equal(isChromeVisible(window), app.is('Fennec') || isAustralis,
'chrome is not visible for addon page');
closeTabPromise(tab).then(function() {
assert.ok(isChromeVisible(window), 'chrome is visible again');
loader.unload();
assert.ok(!isTabOpen(tab), 'add-on page tab is closed on unload');
done();
}).then(null, assert.fail);
});
};
exports['test that add-on page with hash has no chrome'] = function(assert, done) {
let { loader } = LoaderWithHookedConsole(module);
loader.require('sdk/addon-page');
let window = windows.activeBrowserWindow;
let tab = openTab(window, uri + "#foo");
assert.ok(isChromeVisible(window), 'chrome is visible for non addon page');
// need to do this in another turn to make sure event listener
// that sets property has time to do that.
setTimeout(function() {
activateTab(tab);
assert.equal(isChromeVisible(window), app.is('Fennec') || isAustralis,
'chrome is not visible for addon page');
closeTabPromise(tab).then(function() {
assert.ok(isChromeVisible(window), 'chrome is visible again');
loader.unload();
assert.ok(!isTabOpen(tab), 'add-on page tab is closed on unload');
done();
}).then(null, assert.fail);
});
};
exports['test that add-on page with querystring has no chrome'] = function(assert, done) {
let { loader } = LoaderWithHookedConsole(module);
loader.require('sdk/addon-page');
let window = windows.activeBrowserWindow;
let tab = openTab(window, uri + '?foo=bar');
assert.ok(isChromeVisible(window), 'chrome is visible for non addon page');
// need to do this in another turn to make sure event listener
// that sets property has time to do that.
setTimeout(function() {
activateTab(tab);
assert.equal(isChromeVisible(window), app.is('Fennec') || isAustralis,
'chrome is not visible for addon page');
closeTabPromise(tab).then(function() {
assert.ok(isChromeVisible(window), 'chrome is visible again');
loader.unload();
assert.ok(!isTabOpen(tab), 'add-on page tab is closed on unload');
done();
}).then(null, assert.fail);
});
};
exports['test that add-on page with hash and querystring has no chrome'] = function(assert, done) {
let { loader } = LoaderWithHookedConsole(module);
loader.require('sdk/addon-page');
let window = windows.activeBrowserWindow;
let tab = openTab(window, uri + '#foo?foo=bar');
assert.ok(isChromeVisible(window), 'chrome is visible for non addon page');
// need to do this in another turn to make sure event listener
// that sets property has time to do that.
setTimeout(function() {
activateTab(tab);
assert.equal(isChromeVisible(window), app.is('Fennec') || isAustralis,
'chrome is not visible for addon page');
closeTabPromise(tab).then(function() {
assert.ok(isChromeVisible(window), 'chrome is visible again');
loader.unload();
assert.ok(!isTabOpen(tab), 'add-on page tab is closed on unload');
done();
}).then(null, assert.fail);
});
};
exports['test that malformed uri is not an addon-page'] = function(assert, done) {
let { loader } = LoaderWithHookedConsole(module);
loader.require('sdk/addon-page');
let window = windows.activeBrowserWindow;
let tab = openTab(window, uri + 'anguage');
// need to do this in another turn to make sure event listener
// that sets property has time to do that.
setTimeout(function() {
activateTab(tab);
assert.ok(isChromeVisible(window), 'chrome is visible for malformed uri');
closeTabPromise(tab).then(function() {
loader.unload();
done();
}).then(null, assert.fail);
});
};
} else {
exports['test unsupported'] = (assert) => assert.pass('This application is unsupported.');
}
require('sdk/test/runner').runTestsFromModule(module);

View File

@ -1,3 +0,0 @@
{
"id": "test-addon-page"
}

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@
const { PageMod } = require("sdk/page-mod");
const tabs = require("sdk/tabs");
const { startServerAsync } = require("sdk/test/httpd");
const { startServerAsync } = require("./httpd");
const serverPort = 8099;
const TEST_TAB_URL = "about:mozilla";

View File

@ -1,4 +1,4 @@
[addon-page.xpi]
[addon-manager.xpi]
[author-email.xpi]
[child_process.xpi]
[chrome.xpi]

View File

@ -138,9 +138,6 @@ exports["test compatibility"] = function(assert) {
assert.equal(require("querystring"),
require("sdk/querystring"), "sdk/querystring -> querystring");
assert.equal(loader.require("addon-page"),
loader.require("sdk/addon-page"), "sdk/addon-page -> addon-page");
assert.equal(require("tabs/utils"),
require("sdk/tabs/utils"), "sdk/tabs/utils -> tabs/utils");

View File

@ -6,7 +6,7 @@ const { Cc, Ci, Cu } = require('chrome');
const { Loader } = require('sdk/test/loader');
const loader = Loader(module);
const file = require('sdk/io/file');
const httpd = loader.require('sdk/test/httpd');
const httpd = loader.require('./httpd');
const { pathFor } = require('sdk/system');
const { startServerAsync } = httpd;
const basePath = pathFor('ProfD');

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,6 @@ support-files =
test-tmp-file.txt
[test-addon-installer.js]
[test-addon-manager.js]
[test-addon-window.js]
[test-api-utils.js]
[test-array.js]

File diff suppressed because it is too large Load Diff

View File

@ -564,20 +564,6 @@ exports["test Collections 2"] = createProxyTest(html, function (helper) {
});
exports["test valueOf"] = createProxyTest("", function (helper) {
helper.createWorker(
'new ' + function ContentScriptScope() {
// Bug 787013: Until this bug is fixed, we are missing some methods
// on JS objects that comes from global `Object` object
assert(!('valueOf' in window), "valueOf is missing");
assert(!('toLocateString' in window), "toLocaleString is missing");
done();
}
);
});
exports["test XMLHttpRequest"] = createProxyTest("", function (helper) {
helper.createWorker(
@ -751,7 +737,7 @@ exports["testGlobalScope"] = createProxyTest("", function (helper) {
// Create an http server in order to simulate real cross domain documents
exports["test Cross Domain Iframe"] = createProxyTest("", function (helper) {
let serverPort = 8099;
let server = require("sdk/test/httpd").startServerAsync(serverPort);
let server = require("./lib/httpd").startServerAsync(serverPort);
server.registerPathHandler("/", function handle(request, response) {
// Returns the webpage that receive a message and forward it back to its
// parent document by appending ' world'.

View File

@ -9,9 +9,9 @@ const { Loader } = require("sdk/test/loader");
const options = require("sdk/test/options");
const loader = Loader(module);
const httpd = loader.require("sdk/test/httpd");
const httpd = loader.require("./lib/httpd");
if (options.parseable || options.verbose)
loader.sandbox("sdk/test/httpd").DEBUG = true;
loader.sandbox("./lib/httpd").DEBUG = true;
exports.testBasicHTTPServer = function(assert, done) {
// Use the profile directory for the temporary file as that will be deleted

View File

@ -584,6 +584,34 @@ exports.testExistingOnlyFrameMatchesInclude = function(assert, done) {
});
};
exports.testAttachOnlyOncePerDocument = function(assert, done) {
let iframeURL = 'data:text/html;charset=utf-8,testAttachOnlyOncePerDocument';
let iframe = '<iframe src="' + iframeURL + '" />';
let url = 'data:text/html;charset=utf-8,' + encodeURIComponent(iframe);
let count = 0;
tabs.open({
url: url,
onReady: function onReady(tab) {
let pagemod = new PageMod({
include: iframeURL,
attachTo: ['existing', 'frame'],
onAttach: (worker) => {
count++;
assert.equal(iframeURL, worker.url,
"PageMod attached to existing iframe");
assert.equal(count, 1, "PageMod attached only once");
setTimeout(_ => {
assert.equal(count, 1, "PageMod attached only once");
pagemod.destroy();
tab.close(done);
}, 1);
}
});
}
});
}
exports.testContentScriptWhenDefault = function(assert) {
let pagemod = PageMod({include: '*'});

View File

@ -11,9 +11,9 @@ const { Loader } = require("sdk/test/loader");
const options = require("sdk/test/options");
const loader = Loader(module);
const httpd = loader.require("sdk/test/httpd");
const httpd = loader.require("./lib/httpd");
if (options.parseable || options.verbose)
loader.sandbox("sdk/test/httpd").DEBUG = true;
loader.sandbox("./lib/httpd").DEBUG = true;
const { startServerAsync } = httpd;
const { Cc, Ci, Cu } = require("chrome");

View File

@ -122,13 +122,13 @@ exports.testWaitUntilTimeoutInCallback = function(test) {
let message = 0;
if (require("sdk/test/options").parseable) {
expected.push(["print", "TEST-START | wait4ever\n"]);
expected.push(["error", "fail:", "Timed out"]);
expected.push(["error", "fail:", "Timed out (after: START)"]);
expected.push(["error", "test assertion never became true:\n", "assertion failed, value is false\n"]);
expected.push(["print", "TEST-END | wait4ever\n"]);
}
else {
expected.push(["info", "executing 'wait4ever'"]);
expected.push(["error", "fail:", "Timed out"]);
expected.push(["error", "fail:", "Timed out (after: START)"]);
expected.push(["error", "test assertion never became true:\n", "assertion failed, value is false\n"]);
}

View File

@ -17,7 +17,7 @@ const file = require('sdk/io/file');
const tabs = require('sdk/tabs');
const { decode } = require('sdk/base64');
const httpd = require('sdk/test/httpd');
const httpd = require('./lib/httpd');
const port = 8099;
const defaultLocation = '{\'scheme\':\'about\',\'userPass\':null,\'host\':null,\'hostname\':null,\'port\':null,\'path\':\'addons\',\'pathname\':\'addons\',\'hash\':\'\',\'href\':\'about:addons\',\'origin\':\'about:\',\'protocol\':\'about:\',\'search\':\'\'}'.replace(/'/g, '"');
@ -220,8 +220,12 @@ exports.testStringInterface = function(assert) {
'enumerable key list check for URL.');
assert.equal(
JSON.stringify(a),
defaultLocation,
'JSON.stringify should return a object with correct props and vals.');
JSON.stringify(EM),
'JSON.stringify on url should return the url as a flat string');
// JSON.parse(JSON.stringify(url)) wont work like an url object
// (missing methods). this makes it easier to re-create an url
// instance from the whole string, and every place that
// accepts an url also works with a flat string.
// make sure that the String interface exists and works as expected
assert.equal(a.indexOf(':'), EM.indexOf(':'), 'indexOf on URL works');

View File

@ -5,6 +5,7 @@
const { Loader } = require('sdk/test/loader');
const { browserWindows } = require('sdk/windows');
const { isFocused } = require('sdk/window/utils');
const { viewFor } = require('sdk/view/core');
const { modelFor } = require('sdk/model/core');
const { Ci } = require("chrome");
@ -31,6 +32,9 @@ exports.testBrowserWindowsIterator = function(assert) {
}
};
exports.testActiveWindowIsFocused = function(assert) {
assert.ok(isFocused(browserWindows.activeWindow), 'the active window is focused');
}
exports.testWindowTabsObject_alt = function(assert, done) {
let window = browserWindows.activeWindow;

View File

@ -6,7 +6,7 @@
const { Cc, Ci } = require('chrome');
const { setTimeout } = require('sdk/timers');
const { Loader } = require('sdk/test/loader');
const { onFocus, getMostRecentWindow, windows, isBrowser, getWindowTitle } = require('sdk/window/utils');
const { onFocus, getMostRecentWindow, windows, isBrowser, getWindowTitle, isFocused } = require('sdk/window/utils');
const { open, close, focus } = require('sdk/window/helpers');
const { browserWindows } = require("sdk/windows");
const tabs = require("sdk/tabs");
@ -42,6 +42,22 @@ exports.testOpenAndCloseWindow = function(assert, done) {
});
};
exports.testNeWindowIsFocused = function(assert, done) {
let mainWindow = browserWindows.activeWindow;
browserWindows.open({
url: "about:blank",
onOpen: function(window) {
focus(viewFor(window)).then((window) => {
assert.ok(isFocused(window), 'the new window is focused');
assert.ok(isFocused(browserWindows.activeWindow), 'the active window is focused');
assert.ok(!isFocused(mainWindow), 'the main window is not focused');
close(window).then(done).catch(assert.fail);
})
}
});
}
exports.testOpenRelativePathWindow = function(assert, done) {
assert.equal(browserWindows.length, 1, "Only one window open");