Bug 1068440: Uplift Add-on SDK to Firefox.

cc3242d1ca...cbf6cdd0d6
This commit is contained in:
Dave Townsend 2014-09-26 08:32:55 -07:00
parent a2dc4e9ede
commit 252035c9dd
88 changed files with 1206 additions and 1464 deletions

View File

@ -1,4 +1,4 @@
# AUTOMATICALLY GENERATED FROM moz.build.in AND mach. DO NOT EDIT.
# AUTOMATICALLY GENERATED FROM mozbuild.template AND mach. DO NOT EDIT.
# 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/.
@ -13,12 +13,15 @@ BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
JETPACK_PACKAGE_MANIFESTS += ['source/test/jetpack-package.ini']
JETPACK_ADDON_MANIFESTS += ['source/test/addons/jetpack-addon.ini']
DIRS += ["source/modules/system"]
EXTRA_JS_MODULES.sdk += [
'source/app-extension/bootstrap.js',
]
EXTRA_JS_MODULES.sdk.system += [
'source/modules/system/Startup.js',
'source/modules/system/XulApp.js',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] != "gonk":
EXTRA_JS_MODULES.commonjs.method.test += [
'source/lib/method/test/browser.js',
@ -148,6 +151,10 @@ EXTRA_JS_MODULES.commonjs.dev += [
'source/lib/dev/volcan.js',
]
EXTRA_JS_MODULES.commonjs.dev.panel += [
'source/lib/dev/panel/view.js',
]
EXTRA_JS_MODULES.commonjs.diffpatcher += [
'source/lib/diffpatcher/diff.js',
'source/lib/diffpatcher/index.js',
@ -211,6 +218,7 @@ EXTRA_JS_MODULES.commonjs.sdk.addon += [
'source/lib/sdk/addon/events.js',
'source/lib/sdk/addon/host.js',
'source/lib/sdk/addon/installer.js',
'source/lib/sdk/addon/manager.js',
'source/lib/sdk/addon/runner.js',
'source/lib/sdk/addon/window.js',
]

View File

@ -229,6 +229,10 @@ function startup(data, reasonCode) {
resultFile: options.resultFile,
// Arguments passed as --static-args
staticArgs: options.staticArgs,
// Option to prevent automatic kill of firefox during tests
noQuit: options.no_quit,
// Add-on preferences branch name
preferencesBranch: options.preferencesBranch,

View File

@ -18,40 +18,73 @@
</body>
<script>
function debounce(fn, ms) {
var id
var id;
return function(...args) {
clearTimeout(id)
id = setTimeout(fn, ms, ...args)
}
clearTimeout(id);
id = setTimeout(fn, ms, ...args);
};
}
function Try(fn) {
return function(...args) {
try { return fn(...args) }
catch (error) { return null }
try { return fn(...args); }
catch (error) { return null; }
};
}
var parse = Try(JSON.parse);
var CommandHistory = {
init: function() {
this._state = {};
this._state.els = document.querySelectorAll("body > section.task > .request");
this._state.idx = this._state.els.length;
},
get prev() {
if (!!this._state.els && this._state.idx > 0) {
this._state.idx--;
return this._state.els[this._state.idx].textContent;
}
return "";
},
get next() {
if (!!this._state.els && this._state.idx < this._state.els.length-1) {
this._state.idx++;
return this._state.els[this._state.idx].textContent;
}
return "";
}
}
var parse = Try(JSON.parse)
function cmdHistory(fn, editor) {
editor.setValue(fn());
document.querySelector(".input").scrollIntoView();
}
var cmdHistoryNext = cmdHistory.bind(null, () => CommandHistory.next);
var cmdHistoryBack = cmdHistory.bind(null, () => CommandHistory.prev);
function send(editor) {
var input = editor.getWrapperElement().parentNode
var code = editor.getValue().trim()
var packet = parse(code)
var input = editor.getWrapperElement().parentNode;
var code = editor.getValue().trim();
var packet = parse(code);
if (packet) {
var task = document.querySelector("views .task").cloneNode(true)
var request = task.querySelector(".request")
var response = task.querySelector(".response")
var task = document.querySelector("views .task").cloneNode(true);
var request = task.querySelector(".request");
var response = task.querySelector(".response");
input.parentNode.insertBefore(task, input)
input.parentNode.insertBefore(task, input);
CodeMirror.runMode(JSON.stringify(packet, 2, 2),
"application/json",
request)
response.classList.add("pending")
request);
response.classList.add("pending");
editor.setValue("")
document.activeElement.scrollIntoView()
editor.setValue("");
document.querySelector(".input").scrollIntoView();
port.postMessage(packet);
}
@ -63,19 +96,23 @@
matchBrackets: true,
value: '{"to": "root", "type": "requestTypes"}',
extraKeys: {"Cmd-Enter": send,
"Ctrl-Enter": send}
"Ctrl-Enter": send,
"Cmd-Down": cmdHistoryNext,
"Ctrl-Down": cmdHistoryNext,
"Cmd-Up": cmdHistoryBack,
"Ctrl-Up": cmdHistoryBack}
});
editor.on("change", debounce(function(editor) {
var input = editor.getWrapperElement().parentNode;
if (parse(editor.getValue().trim()))
input.classList.remove("invalid")
else
input.classList.add("invalid")
}, 800))
if (parse(editor.getValue().trim())) {
input.classList.remove("invalid");
} else {
input.classList.add("invalid");
}
}, 800));
</script>
<script>
window.addEventListener("message", event => {
console.log("REPL", event);
window.port = event.ports[0];
port.onmessage = onMessage;
});
@ -84,25 +121,27 @@
var packet = event.data;
var code = JSON.stringify(packet, 2, 2);
var input = editor.getWrapperElement().parentNode;
var response = document.querySelector(".task .response.pending")
var input = document.querySelector(".input");
var response = document.querySelector(".task .response.pending");
if (!response) {
message = document.querySelector("views .task").cloneNode(true)
response = message.querySelector(".response")
response.classList.add("message")
message = document.querySelector("views .task").cloneNode(true);
response = message.querySelector(".response");
response.classList.add("message");
input.parentNode.insertBefore(message, input);
}
if (packet.error)
if (packet.error) {
response.classList.add("error");
}
CodeMirror.runMode(code, "application/json", response);
response.classList.remove("pending");
document.activeElement.scrollIntoView()
document.querySelector(".input").scrollIntoView();
CommandHistory.init();
};
</script>
</html>

View File

@ -0,0 +1,39 @@
/* 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 data = require('sdk/self').data;
var tabs = require('sdk/tabs');
var { notify } = require('sdk/notifications');
var { ActionButton, ToggleButton } = require('sdk/ui');
var icon = 'chrome://mozapps/skin/extensions/extensionGeneric.png';
exports.icon = icon;
// your basic action button
var action = ActionButton({
id: 'test-action-button',
label: 'Action Button',
icon: icon,
onClick: function (state) {
notify({
title: "Action!",
text: "This notification was triggered from an action button!",
});
}
});
exports.actionButton = action;
var toggle = ToggleButton({
id: 'test-toggle-button',
label: 'Toggle Button',
icon: icon,
onClick: function (state) {
notify({
title: "Toggled!",
text: "The current state of the button is " + state.checked,
});
}
});
exports.toggleButton = toggle;

View File

@ -0,0 +1,9 @@
{
"name": "ui-button-apis",
"title": "Australis Button API Examples",
"id": "ui-button-apis@mozilla.org",
"description": "A Button API example",
"author": "jeff@canuckistani.ca (Jeff Griffiths | @canuckistani)",
"license": "MPL 2.0",
"version": "0.1"
}

View File

@ -0,0 +1,21 @@
/* 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 { actionButton, toggleButton, icon } = require("main");
var self = require("sdk/self");
exports.testActionButton = function(assert) {
assert.equal(actionButton.id, "test-action-button", "action button id is correct");
assert.equal(actionButton.label, "Action Button", "action button label is correct");
assert.equal(actionButton.icon, icon, "action button icon is correct");
}
exports.testToggleButton = function(assert) {
assert.equal(toggleButton.id, "test-toggle-button", "toggle button id is correct");
assert.equal(toggleButton.label, "Toggle Button", "toggle button label is correct");
assert.equal(toggleButton.icon, icon, "toggle button icon is correct");
}
require("sdk/test").run(exports);

View File

@ -22,7 +22,6 @@ const inputFor = port => inputs.get(port);
const outputFor = port => outputs.get(port);
const transportFor = port => transports.get(port);
const fromTarget = target => {
const debuggee = new Debuggee();
const { port1, port2 } = new MessageChannel();

View File

@ -8,7 +8,6 @@ module.metadata = {
"stability": "experimental"
};
const { Cu } = require("chrome");
const { Class } = require("../sdk/core/heritage");
const { curry } = require("../sdk/lang/functional");
@ -21,12 +20,13 @@ const { contract, validate } = require("../sdk/util/contract");
const { data: { url: resolve }} = require("../sdk/self");
const { identify } = require("../sdk/ui/id");
const { isLocalURL, URL } = require("../sdk/url");
const { defer } = require("../sdk/core/promise");
const { encode } = require("../sdk/base64");
const { marshal, demarshal } = require("./ports");
const { fromTarget } = require("./debuggee");
const { removed } = require("../sdk/dom/events");
const { id: addonID } = require("../sdk/self");
const { viewFor } = require("../sdk/view/core");
const { createView } = require("./panel/view");
const OUTER_FRAME_URI = module.uri.replace(/\.js$/, ".html");
const FRAME_SCRIPT = module.uri.replace("/panel.js", "/frame-script.js");
@ -56,6 +56,9 @@ const panelFor = frame => panels.get(frame);
const debuggees = new WeakMap();
const debuggeeFor = panel => debuggees.get(panel);
const frames = new WeakMap();
const frameFor = panel => frames.get(panel);
const setAttributes = (node, attributes) => {
for (var key in attributes)
node.setAttribute(key, attributes[key]);
@ -165,22 +168,29 @@ setup.define(Panel, (panel, {window, toolbox, url}) => {
// we obtain original iframe and replace it with the one that has
// desired configuration.
const original = getFrameElement(window);
const frame = original.cloneNode(true);
const container = original.parentNode;
original.remove();
const frame = createView(panel, container.ownerDocument);
// Following modifications are a temporary workaround until Bug 1049188
// is fixed.
// Enforce certain iframe customizations regardless of users request.
setAttributes(frame, {
"id": original.id,
"src": url,
"sandbox": "allow-scripts",
// It would be great if we could allow remote iframes for sandboxing
// panel documents in a content process, but for now platform implementation
// is buggy on linux so this is disabled.
// "remote": true,
"type": "content",
"transparent": true,
"seamless": "seamless"
"flex": 1,
"forceOwnRefreshDriver": "",
"tooltip": "aHTMLTooltip"
});
original.parentNode.replaceChild(frame, original);
frame.style.visibility = "hidden";
frame.classList.add("toolbox-panel-iframe");
// Inject iframe into designated node until add-on author decides
// to inject it elsewhere instead.
if (!frame.parentNode)
container.appendChild(frame);
// associate view with a panel
frames.set(panel, frame);
// associate panel model with a frame view.
panels.set(frame, panel);
@ -213,11 +223,29 @@ setup.define(Panel, (panel, {window, toolbox, url}) => {
panel.setup({ debuggee: debuggee });
});
createView.define(Panel, (panel, document) => {
const frame = document.createElement("iframe");
setAttributes(frame, {
"sandbox": "allow-scripts",
// It would be great if we could allow remote iframes for sandboxing
// panel documents in a content process, but for now platform implementation
// is buggy on linux so this is disabled.
// "remote": true,
"type": "content",
"transparent": true,
"seamless": "seamless",
});
return frame;
});
dispose.define(Panel, function(panel) {
debuggeeFor(panel).close();
debuggees.delete(panel);
managers.delete(panel);
frames.delete(panel);
panel.readyState = "destroyed";
panel.dispose();
});
viewFor.define(Panel, frameFor);

View File

@ -0,0 +1,14 @@
/* 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": "experimental"
};
const { method } = require("method/core");
const createView = method("dev/panel/view#createView");
exports.createView = createView;

View File

@ -0,0 +1,18 @@
/* 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": "experimental"
};
const { AddonManager } = require("resource://gre/modules/AddonManager.jsm");
const { defer } = require("../core/promise");
function getAddonByID(id) {
let { promise, resolve } = defer();
AddonManager.getAddonByID(id, resolve);
return promise;
}
exports.getAddonByID = getAddonByID;

View File

@ -46,15 +46,9 @@ Object.freeze({
}
return results;
}
function hasListenerFor(name) {
if (!(name in listeners))
return false;
return listeners[name].length > 0;
}
return {
eventEmitter: eventEmitter,
emit: onEvent,
hasListenerFor: hasListenerFor
emit: onEvent
};
},
@ -83,7 +77,7 @@ Object.freeze({
emitToChrome(str);
}
let { eventEmitter, emit, hasListenerFor } =
let { eventEmitter, emit } =
ContentWorker.createEventEmitter(onEvent);
return {
@ -95,8 +89,7 @@ Object.freeze({
// and modules (only used for context-menu API)
let args = typeof array == "string" ? JSON.parse(array) : array;
return emit.apply(null, args);
},
hasListenerFor: hasListenerFor
}
};
},
@ -325,7 +318,7 @@ Object.freeze({
inject: function (exports, chromeAPI, emitToChrome, options) {
let ContentWorker = this;
let { pipe, onChromeEvent, hasListenerFor } =
let { pipe, onChromeEvent } =
ContentWorker.createPipe(emitToChrome);
ContentWorker.injectConsole(exports, pipe);
@ -337,9 +330,6 @@ Object.freeze({
Object.freeze( exports.self );
return {
emitToContent: onChromeEvent,
hasListenerFor: hasListenerFor
};
return onChromeEvent;
}
});

View File

@ -77,15 +77,6 @@ const WorkerSandbox = Class({
return emitToContent(this, args);
},
/**
* Tells if content script has at least one listener registered for one event,
* through `self.on('xxx', ...)`.
* /!\ Shouldn't be used. Implemented to avoid breaking context-menu API.
*/
hasListenerFor: function hasListenerFor(name) {
return modelFor(this).hasListenerFor(name);
},
/**
* Configures sandbox and loads content scripts into it.
* @param {Worker} worker
@ -190,10 +181,9 @@ const WorkerSandbox = Class({
let chromeAPI = createChromeAPI();
let result = Cu.waiveXrays(ContentWorker).inject(content, chromeAPI, onEvent, options);
// Merge `emitToContent` and `hasListenerFor` into our private
// model of the WorkerSandbox so we can communicate with content
// script
merge(model, result);
// Merge `emitToContent` into our private model of the
// WorkerSandbox so we can communicate with content script
model.emitToContent = result;
let console = new PlainTextConsole(null, getInnerId(window));

View File

@ -48,8 +48,9 @@ const OVERFLOW_THRESH_PREF =
// The label of the overflow sub-xul:menu.
//
// TODO: Localize this.
// TODO: Localize these.
const OVERFLOW_MENU_LABEL = "Add-ons";
const OVERFLOW_MENU_ACCESSKEY = "A";
// The class of the overflow sub-xul:menu.
const OVERFLOW_MENU_CLASS = "addon-content-menu-overflow-menu";
@ -277,7 +278,7 @@ function removeItemFromArray(array, item) {
// Converts anything that isn't false, null or undefined into a string
function stringOrNull(val) val ? String(val) : val;
// Shared option validation rules for Item and Menu
// Shared option validation rules for Item, Menu, and Separator
let baseItemRules = {
parentMenu: {
is: ["object", "undefined"],
@ -313,6 +314,17 @@ let labelledItemRules = mix(baseItemRules, {
ok: function (v) !!v,
msg: "The item must have a non-empty string label."
},
accesskey: {
map: stringOrNull,
is: ["string", "undefined", "null"],
ok: (v) => {
if (!v) {
return true;
}
return typeof v == "string" && v.length === 1;
},
msg: "The item must have a single character accesskey, or no accesskey."
},
image: {
map: stringOrNull,
is: ["string", "undefined", "null"],
@ -352,18 +364,15 @@ let menuRules = mix(labelledItemRules, {
let ContextWorker = Class({
implements: [ Worker ],
//Returns true if any context listeners are defined in the worker's port.
anyContextListeners: function anyContextListeners() {
return this.getSandbox().hasListenerFor("context");
},
// Calls the context workers context listeners and returns the first result
// that is either a string or a value that evaluates to true. If all of the
// listeners returned false then returns false. If there are no listeners
// then returns null.
// listeners returned false then returns false. If there are no listeners,
// returns true (show the menu item by default).
getMatchedContext: function getCurrentContexts(popupNode) {
let results = this.getSandbox().emitSync("context", popupNode);
return results.reduce(function(val, result) val || result, null);
if (!results.length)
return true;
return results.reduce((val, result) => val || result);
},
// Emits a click event in the worker's port. popupNode is the node that was
@ -389,7 +398,7 @@ function hasMatchingContext(contexts, popupNode) {
// or no matched context then returns false.
function getCurrentWorkerContext(item, popupNode) {
let worker = getItemWorkerForWindow(item, popupNode.ownerDocument.defaultView);
if (!worker || !worker.anyContextListeners())
if (!worker)
return true;
return worker.getMatchedContext(popupNode);
}
@ -399,7 +408,7 @@ function getCurrentWorkerContext(item, popupNode) {
function isItemVisible(item, popupNode, defaultVisibility) {
if (!item.context.length) {
let worker = getItemWorkerForWindow(item, popupNode.ownerDocument.defaultView);
if (!worker || !worker.anyContextListeners())
if (!worker)
return defaultVisibility;
}
@ -445,7 +454,7 @@ function getItemWorkerForWindow(item, window) {
// Called when an item is clicked to send out click events to the content
// scripts
function itemClicked(item, clickedItem, popupNode) {
function itemActivated(item, clickedItem, popupNode) {
let worker = getItemWorkerForWindow(item, popupNode.ownerDocument.defaultView);
if (worker) {
@ -456,7 +465,7 @@ function itemClicked(item, clickedItem, popupNode) {
}
if (item.parentMenu)
itemClicked(item.parentMenu, clickedItem, popupNode);
itemActivated(item.parentMenu, clickedItem, popupNode);
}
// All things that appear in the context menu extend this
@ -533,6 +542,16 @@ let LabelledItem = Class({
MenuManager.updateItem(this);
},
get accesskey() {
return internal(this).options.accesskey;
},
set accesskey(val) {
internal(this).options.accesskey = val;
MenuManager.updateItem(this);
},
get image() {
return internal(this).options.image;
},
@ -874,6 +893,8 @@ let MenuWrapper = Class({
xulNode.setAttribute("class", ITEM_CLASS);
if (item instanceof LabelledItem) {
xulNode.setAttribute("label", item.label);
if (item.accesskey)
xulNode.setAttribute("accesskey", item.accesskey);
if (item.image) {
xulNode.setAttribute("image", item.image);
if (item instanceof Menu)
@ -890,7 +911,7 @@ let MenuWrapper = Class({
if (event.target !== xulNode)
return;
itemClicked(item, item, self.contextMenu.triggerNode);
itemActivated(item, item, self.contextMenu.triggerNode);
}, false);
}
@ -915,6 +936,7 @@ let MenuWrapper = Class({
// TODO figure out why this requires setAttribute
xulNode.setAttribute("label", item.label);
xulNode.setAttribute("accesskey", item.accesskey || "");
if (item.image) {
xulNode.setAttribute("image", item.image);
@ -1050,6 +1072,7 @@ let MenuWrapper = Class({
let overflowMenu = this.window.document.createElement("menu");
overflowMenu.setAttribute("class", OVERFLOW_MENU_CLASS);
overflowMenu.setAttribute("label", OVERFLOW_MENU_LABEL);
overflowMenu.setAttribute("accesskey", OVERFLOW_MENU_ACCESSKEY);
this.contextMenu.insertBefore(overflowMenu, this.separator.nextSibling);
overflowPopup = this.window.document.createElement("menupopup");

View File

@ -86,15 +86,6 @@ const WorkerSandbox = EventEmitter.compose({
return this._emitToContent(args);
},
/**
* Tells if content script has at least one listener registered for one event,
* through `self.on('xxx', ...)`.
* /!\ Shouldn't be used. Implemented to avoid breaking context-menu API.
*/
hasListenerFor: function hasListenerFor(name) {
return this._hasListenerFor(name);
},
/**
* Method called by the worker sandbox when it needs to send a message
*/
@ -223,8 +214,7 @@ const WorkerSandbox = EventEmitter.compose({
};
let onEvent = this._onContentEvent.bind(this);
let result = Cu.waiveXrays(ContentWorker).inject(content, chromeAPI, onEvent, options);
this._emitToContent = result.emitToContent;
this._hasListenerFor = result.hasListenerFor;
this._emitToContent = result;
// Handle messages send by this script:
let self = this;

View File

@ -12,8 +12,9 @@ const timer = require("../timers");
const cfxArgs = require("../test/options");
const { getTabs, closeTab, getURI } = require("../tabs/utils");
const { windows, isBrowser, getMostRecentBrowserWindow } = require("../window/utils");
const { defer, all, Debugging: PromiseDebugging } = require("../core/promise");
const { defer, all, Debugging: PromiseDebugging, resolve } = require("../core/promise");
const { getInnerId } = require("../window/utils");
const { cleanUI } = require("../test/utils")
const findAndRunTests = function findAndRunTests(options) {
var TestFinder = require("./unit-test-finder").TestFinder;
@ -268,88 +269,91 @@ TestRunner.prototype = {
},
done: function done() {
if (!this.isDone) {
this.isDone = true;
if(this.test.teardown) {
this.test.teardown(this);
}
if (this.waitTimeout !== null) {
timer.clearTimeout(this.waitTimeout);
this.waitTimeout = null;
}
// Do not leave any callback set when calling to `waitUntil`
this.waitUntilCallback = null;
if (this.test.passed == 0 && this.test.failed == 0) {
this._logTestFailed("empty test");
if ("testMessage" in this.console) {
this.console.testMessage(false, false, this.test.name, "Empty test");
}
else {
this.console.error("fail:", "Empty test")
}
this.failed++;
this.test.failed++;
}
let wins = windows(null, { includePrivate: true });
let winPromises = wins.map(win => {
let { promise, resolve } = defer();
if (["interactive", "complete"].indexOf(win.document.readyState) >= 0) {
resolve()
}
else {
win.addEventListener("DOMContentLoaded", function onLoad() {
win.removeEventListener("DOMContentLoaded", onLoad, false);
resolve();
}, false);
}
return promise;
});
PromiseDebugging.flushUncaughtErrors();
all(winPromises).then(_ => {
let tabs = [];
for (let win of wins.filter(isBrowser)) {
for (let tab of getTabs(win)) {
tabs.push(tab);
}
}
let leftover = tabs.slice(1);
if (wins.length != 1 || getInnerId(wins[0]) !== runnerWindows.get(this))
this.fail("Should not be any unexpected windows open");
if (tabs.length != 1)
this.fail("Should not be any unexpected tabs open");
if (tabs.length != 1 || wins.length != 1) {
console.log("Windows open:");
for (let win of wins) {
if (isBrowser(win)) {
tabs = getTabs(win);
console.log(win.location + " - " + tabs.map(getURI).join(", "));
}
else {
console.log(win.location);
}
}
}
leftover.forEach(closeTab);
this.testRunSummary.push({
name: this.test.name,
passed: this.test.passed,
failed: this.test.failed,
errors: [error for (error in this.test.errors)].join(", ")
});
if (this.onDone !== null) {
let onDone = this.onDone;
this.onDone = null;
timer.setTimeout(_ => onDone(this), 0);
}
});
if (this.isDone) {
return resolve();
}
this.isDone = true;
if (this.test.teardown) {
this.test.teardown(this);
}
if (this.waitTimeout !== null) {
timer.clearTimeout(this.waitTimeout);
this.waitTimeout = null;
}
// Do not leave any callback set when calling to `waitUntil`
this.waitUntilCallback = null;
if (this.test.passed == 0 && this.test.failed == 0) {
this._logTestFailed("empty test");
if ("testMessage" in this.console) {
this.console.testMessage(false, false, this.test.name, "Empty test");
}
else {
this.console.error("fail:", "Empty test")
}
this.failed++;
this.test.failed++;
}
let wins = windows(null, { includePrivate: true });
let winPromises = wins.map(win => {
let { promise, resolve } = defer();
if (["interactive", "complete"].indexOf(win.document.readyState) >= 0) {
resolve()
}
else {
win.addEventListener("DOMContentLoaded", function onLoad() {
win.removeEventListener("DOMContentLoaded", onLoad, false);
resolve();
}, false);
}
return promise;
});
PromiseDebugging.flushUncaughtErrors();
return all(winPromises).then(() => {
let browserWins = wins.filter(isBrowser);
let tabs = browserWins.reduce((tabs, window) => tabs.concat(getTabs(window)), []);
if (wins.length != 1 || getInnerId(wins[0]) !== runnerWindows.get(this))
this.fail("Should not be any unexpected windows open");
let hasMoreTabsOpen = browserWins.length && tabs.length != 1;
if (hasMoreTabsOpen)
this.fail("Should not be any unexpected tabs open");
if (hasMoreTabsOpen || wins.length != 1) {
console.log("Windows open:");
for (let win of wins) {
if (isBrowser(win)) {
tabs = getTabs(win);
console.log(win.location + " - " + tabs.map(getURI).join(", "));
}
else {
console.log(win.location);
}
}
}
return null;
}).
then(cleanUI).
then(() => {
this.testRunSummary.push({
name: this.test.name,
passed: this.test.passed,
failed: this.test.failed,
errors: [error for (error in this.test.errors)].join(", ")
});
if (this.onDone !== null) {
let onDone = this.onDone;
this.onDone = null;
timer.setTimeout(_ => onDone(this));
}
}).
catch(e => console.exception(e));
},
// Set of assertion functions to wait for an assertion to become true

View File

@ -16,7 +16,7 @@ const { getInnerId, getOuterId, windows, isDocumentLoaded, isBrowser,
getMostRecentBrowserWindow, getMostRecentWindow } = require('../window/utils');
const errors = require('../deprecated/errors');
const { deprecateFunction } = require('../util/deprecate');
const { ignoreWindow, isGlobalPBSupported } = require('sdk/private-browsing/utils');
const { ignoreWindow } = require('sdk/private-browsing/utils');
const { isPrivateBrowsingSupported } = require('../self');
const windowWatcher = Cc['@mozilla.org/embedcomp/window-watcher;1'].
@ -25,7 +25,7 @@ const appShellService = Cc['@mozilla.org/appshell/appShellService;1'].
getService(Ci.nsIAppShellService);
// Bug 834961: ignore private windows when they are not supported
function getWindows() windows(null, { includePrivate: isPrivateBrowsingSupported || isGlobalPBSupported });
function getWindows() windows(null, { includePrivate: isPrivateBrowsingSupported });
/**
* An iterator for XUL windows currently in the application.

View File

@ -137,6 +137,7 @@ Buffer.concat = function(list, length) {
// that typically can be used in combination with `DataView` while preserving
// access by index. Since in SDK each module has it's own set of bult-ins it
// ok to patch ours to make it nodejs Buffer compatible.
const Uint8ArraySet = Uint8Array.prototype.set
Buffer.prototype = Uint8Array.prototype;
Object.defineProperties(Buffer.prototype, {
parent: {
@ -204,7 +205,7 @@ Object.defineProperties(Buffer.prototype, {
end = start + remainingTarget;
}
Uint8Array.set(target, this.subarray(start, end), offset);
Uint8ArraySet.call(target, this.subarray(start, end), offset);
return end - start;
}
},
@ -267,7 +268,7 @@ Object.defineProperties(Buffer.prototype, {
if (buffer.length !== length)
buffer = buffer.subarray(0, length);
Uint8Array.set(this, buffer, offset);
Uint8ArraySet.call(this, buffer, offset);
return result;
}
},

View File

@ -647,26 +647,26 @@ exports.close = close;
/**
* Synchronous open(2).
*/
function openSync(path, flags, mode) {
let [ fd, flags_, mode_, file ] =
[ { path: path }, Flags(flags), Mode(mode), nsILocalFile(path) ];
function openSync(aPath, aFlag, aMode) {
let [ fd, flags, mode, file ] =
[ { path: aPath }, Flags(aFlag), Mode(aMode), nsILocalFile(aPath) ];
nsIFile(fd, file);
// If trying to open file for just read that does not exists
// need to throw exception as node does.
if (!file.exists() && !isWritable(flags_))
throw FSError("open", "ENOENT", 34, path);
if (!file.exists() && !isWritable(flags))
throw FSError("open", "ENOENT", 34, aPath);
// If we want to open file in read mode we initialize input stream.
if (isReadable(flags_)) {
let input = FileInputStream(file, flags_, mode_, DEFER_OPEN);
if (isReadable(flags)) {
let input = FileInputStream(file, flags, mode, DEFER_OPEN);
nsIFileInputStream(fd, input);
}
// If we want to open file in write mode we initialize output stream for it.
if (isWritable(flags_)) {
let output = FileOutputStream(file, flags_, mode_, DEFER_OPEN);
if (isWritable(flags)) {
let output = FileOutputStream(file, flags, mode, DEFER_OPEN);
nsIFileOutputStream(fd, output);
}
@ -822,7 +822,8 @@ function readFile(path, encoding, callback) {
readStream.destroy();
callback(null, buffer);
});
} catch (error) {
}
catch (error) {
setTimeout(callback, 0, error);
}
};

View File

@ -15,12 +15,11 @@ module.metadata = {
const { getMostRecentBrowserWindow, windows: getWindows } = require('../window/utils');
const { ignoreWindow } = require('../private-browsing/utils');
const { isPrivateBrowsingSupported } = require('../self');
const { isGlobalPBSupported } = require('../private-browsing/utils');
function getWindow(anchor) {
let window;
let windows = getWindows("navigator:browser", {
includePrivate: isPrivateBrowsingSupported || isGlobalPBSupported
includePrivate: isPrivateBrowsingSupported
});
if (anchor) {

View File

@ -7,43 +7,6 @@ module.metadata = {
"stability": "stable"
};
const { setMode, getMode, on: onStateChange, isPrivate } = require('./private-browsing/utils');
const { emit, on, once, off } = require('./event/core');
const { when: unload } = require('./system/unload');
const { deprecateFunction, deprecateEvent } = require('./util/deprecate');
onStateChange('start', function onStart() {
emit(exports, 'start');
});
onStateChange('stop', function onStop() {
emit(exports, 'stop');
});
Object.defineProperty(exports, "isActive", {
get: deprecateFunction(getMode, 'require("private-browsing").isActive is deprecated.')
});
exports.activate = function activate() setMode(true);
exports.deactivate = function deactivate() setMode(false);
exports.on = deprecateEvents(on.bind(null, exports));
exports.once = deprecateEvents(once.bind(null, exports));
exports.removeListener = deprecateEvents(function removeListener(type, listener) {
// Note: We can't just bind `off` as we do it for other methods cause skipping
// a listener argument will remove all listeners for the given event type
// causing misbehavior. This way we make sure all arguments are passed.
off(exports, type, listener);
});
const { isPrivate } = require('./private-browsing/utils');
exports.isPrivate = isPrivate;
function deprecateEvents(func) deprecateEvent(
func,
'The require("sdk/private-browsing") module\'s "start" and "stop" events ' +
'are deprecated.',
['start', 'stop']
);
// Make sure listeners are cleaned up.
unload(function() off(exports));

View File

@ -8,51 +8,28 @@ module.metadata = {
};
const { Cc, Ci, Cu } = require('chrome');
const { defer } = require('../lang/functional');
const { emit, on, once, off } = require('../event/core');
const { when: unload } = require('../system/unload');
const events = require('../system/events');
const { deprecateFunction } = require('../util/deprecate');
const { isOneOf, is, satisfiesVersion, version } = require('../system/xul-app');
const { is } = require('../system/xul-app');
const { isWindowPrivate } = require('../window/utils');
const { isPrivateBrowsingSupported } = require('../self');
const { dispatcher } = require("../util/dispatcher");
let deferredEmit = defer(emit);
let pbService;
let PrivateBrowsingUtils;
// Private browsing is only supported in Fx
if (isOneOf(['Firefox', 'Fennec'])) {
// get the nsIPrivateBrowsingService if it exists
try {
pbService = Cc["@mozilla.org/privatebrowsing;1"].
getService(Ci.nsIPrivateBrowsingService);
// a dummy service exists for the moment (Fx20 atleast), but will be removed eventually
// ie: the service will exist, but it won't do anything and the global private browing
// feature is not really active. See Bug 818800 and Bug 826037
if (!('privateBrowsingEnabled' in pbService))
pbService = undefined;
}
catch(e) { /* Private Browsing Service has been removed (Bug 818800) */ }
try {
PrivateBrowsingUtils = Cu.import('resource://gre/modules/PrivateBrowsingUtils.jsm', {}).PrivateBrowsingUtils;
}
catch(e) { /* if this file DNE then an error will be thrown */ }
try {
PrivateBrowsingUtils = Cu.import('resource://gre/modules/PrivateBrowsingUtils.jsm', {}).PrivateBrowsingUtils;
}
catch (e) {}
// checks that global private browsing is implemented
let isGlobalPBSupported = exports.isGlobalPBSupported = !!pbService && is('Firefox');
exports.isGlobalPBSupported = false;
// checks that per-window private browsing is implemented
let isWindowPBSupported = exports.isWindowPBSupported =
!pbService && !!PrivateBrowsingUtils && is('Firefox');
!!PrivateBrowsingUtils && is('Firefox');
// checks that per-tab private browsing is implemented
let isTabPBSupported = exports.isTabPBSupported =
!pbService && !!PrivateBrowsingUtils && is('Fennec') && satisfiesVersion(version, '>=20.0*');
!!PrivateBrowsingUtils && is('Fennec');
function isPermanentPrivateBrowsing() {
return !!(PrivateBrowsingUtils && PrivateBrowsingUtils.permanentPrivateBrowsing);
@ -60,58 +37,18 @@ function isPermanentPrivateBrowsing() {
exports.isPermanentPrivateBrowsing = isPermanentPrivateBrowsing;
function ignoreWindow(window) {
return !isPrivateBrowsingSupported && isWindowPrivate(window) && !isGlobalPBSupported;
return !isPrivateBrowsingSupported && isWindowPrivate(window);
}
exports.ignoreWindow = ignoreWindow;
function onChange() {
// Emit event with in next turn of event loop.
deferredEmit(exports, pbService.privateBrowsingEnabled ? 'start' : 'stop');
}
// Currently, only Firefox implements the private browsing service.
if (isGlobalPBSupported) {
// set up an observer for private browsing switches.
events.on('private-browsing-transition-complete', onChange);
}
// We toggle private browsing mode asynchronously in order to work around
// bug 659629. Since private browsing transitions are asynchronous
// anyway, this doesn't significantly change the behavior of the API.
let setMode = defer(function setMode(value) {
value = !!value; // Cast to boolean.
// default
return pbService && (pbService.privateBrowsingEnabled = value);
});
exports.setMode = deprecateFunction(
setMode,
'require("sdk/private-browsing").activate and ' +
'require("sdk/private-browsing").deactivate ' +
'are deprecated.'
);
let getMode = function getMode(chromeWin) {
if (chromeWin !== undefined && isWindowPrivate(chromeWin))
return true;
// default
return isGlobalPrivateBrowsing();
return (chromeWin !== undefined && isWindowPrivate(chromeWin));
};
exports.getMode = getMode;
function isGlobalPrivateBrowsing() {
return pbService ? pbService.privateBrowsingEnabled : false;
}
const isPrivate = dispatcher("isPrivate");
isPrivate.when(isPermanentPrivateBrowsing, _ => true);
isPrivate.when(x => x instanceof Ci.nsIDOMWindow, isWindowPrivate);
isPrivate.when(x => Ci.nsIPrivateBrowsingChannel && x instanceof Ci.nsIPrivateBrowsingChannel, x => x.isChannelPrivate);
isPrivate.define(isGlobalPrivateBrowsing);
isPrivate.define(() => false);
exports.isPrivate = isPrivate;
exports.on = on.bind(null, exports);
// Make sure listeners are cleaned up.
unload(function() off(exports));

View File

@ -1,7 +1,6 @@
/* 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 = {
@ -12,6 +11,7 @@ const { Cc, Ci, CC } = require('chrome');
const options = require('@loader/options');
const file = require('./io/file');
const runtime = require("./system/runtime");
const { when: unload } = require("./system/unload");
const appStartup = Cc['@mozilla.org/toolkit/app-startup;1'].
getService(Ci.nsIAppStartup);
@ -61,8 +61,9 @@ exports.exit = function exit(code) {
return;
}
// This is used by 'cfx' to find out exit code.
if ('resultFile' in options && options.resultFile) {
let resultsFile = 'resultFile' in options && options.resultFile;
function unloader() {
// 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);
let status = code ? 'FAIL' : 'OK';
@ -74,6 +75,16 @@ exports.exit = function exit(code) {
if (code == 0) {
forcedExit = true;
}
// Bug 856999: Prevent automatic kill of Firefox when running tests
if (options.noQuit) {
if (resultsFile) {
unload(unloader);
}
return;
}
unloader();
appStartup.quit(code ? E_ATTEMPT : E_FORCE);
};
@ -109,7 +120,7 @@ exports.pathFor = function pathFor(id) {
*/
exports.platform = runtime.OS.toLowerCase();
const [, architecture, compiler] = runtime.XPCOMABI ?
const [, architecture, compiler] = runtime.XPCOMABI ?
runtime.XPCOMABI.match(/^([^-]*)-(.*)$/) :
[, null, null];

View File

@ -15,10 +15,9 @@ const { Ci } = require('chrome');
const { defer } = require("../lang/functional");
const { windows, isBrowser } = require('../window/utils');
const { isPrivateBrowsingSupported } = require('../self');
const { isGlobalPBSupported } = require('../private-browsing/utils');
// Bug 834961: ignore private windows when they are not supported
function getWindows() windows(null, { includePrivate: isPrivateBrowsingSupported || isGlobalPBSupported });
function getWindows() windows(null, { includePrivate: isPrivateBrowsingSupported });
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";

View File

@ -1,7 +1,6 @@
/* 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 = {
@ -10,6 +9,9 @@ module.metadata = {
const { defer } = require('../core/promise');
const { setInterval, clearInterval } = require('../timers');
const { getTabs, closeTab } = require("../tabs/utils");
const { windows: getWindows } = require("../window/utils");
const { close: closeWindow } = require("../window/helpers");
function getTestNames (exports)
Object.keys(exports).filter(name => /^test/.test(name))
@ -107,3 +109,19 @@ function waitUntil (predicate, delay) {
return promise;
}
exports.waitUntil = waitUntil;
let cleanUI = function cleanUI() {
let { promise, resolve } = defer();
let windows = getWindows(null, { includePrivate: true });
if (windows.length > 1) {
return closeWindow(windows[1]).then(cleanUI);
}
getTabs(windows[0]).slice(1).forEach(closeTab);
resolve();
return promise;
}
exports.cleanUI = cleanUI;

View File

@ -1,7 +1,6 @@
/* 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 = {
@ -15,17 +14,12 @@ function MatchPattern(pattern) {
if (cache[pattern]) return cache[pattern];
if (typeof pattern.test == "function") {
// For compatibility with -moz-document rules, we require the RegExp's
// global, ignoreCase, and multiline flags to be set to false.
if (pattern.global) {
throw new Error("A RegExp match pattern cannot be set to `global` " +
"(i.e. //g).");
}
if (pattern.ignoreCase) {
throw new Error("A RegExp match pattern cannot be set to `ignoreCase` " +
"(i.e. //i).");
}
if (pattern.multiline) {
throw new Error("A RegExp match pattern cannot be set to `multiline` " +
"(i.e. //m).");
@ -71,7 +65,6 @@ function MatchPattern(pattern) {
}
MatchPattern.prototype = {
test: function MatchPattern_test(urlStr) {
try {
var url = URL(urlStr);
@ -88,13 +81,13 @@ MatchPattern.prototype = {
// Assuming most URLs don't match most match patterns, we call `test` for
// speed when determining whether or not the URL matches, then call `exec`
// for the small subset that match to make sure the entire URL matches.
//
if (this.regexp && this.regexp.test(urlStr) &&
this.regexp.exec(urlStr)[0] == urlStr)
return true;
if (this.anyWebPage && /^(https?|ftp)$/.test(url.scheme))
return true;
if (this.exactURL && this.exactURL == urlStr)
return true;
@ -107,6 +100,7 @@ MatchPattern.prototype = {
(url.host === this.domain ||
url.host.slice(-this.domain.length - 1) === "." + this.domain))
return true;
if (this.urlPrefix && 0 == urlStr.indexOf(this.urlPrefix))
return true;
@ -114,7 +108,6 @@ MatchPattern.prototype = {
},
toString: function () '[object MatchPattern]'
};
exports.MatchPattern = MatchPattern;

View File

@ -4,8 +4,7 @@
'use strict';
const { Trait } = require('../deprecated/traits');
const { isWindowPrivate, getWindowTitle } = require('../window/utils');
const { deprecateUsage } = require('../util/deprecate');
const { getWindowTitle } = require('../window/utils');
module.metadata = {
"stability": "unstable"
@ -25,13 +24,6 @@ const WindowDom = Trait.compose({
let window = this._window;
if (window) window.focus();
return this._public;
},
get isPrivateBrowsing() {
deprecateUsage('`browserWindow.isPrivateBrowsing` is deprecated, please ' +
'consider using ' +
'`require("sdk/private-browsing").isPrivate(browserWindow)` ' +
'instead.');
return isWindowPrivate(this._window);
}
});
exports.WindowDom = WindowDom;

View File

@ -229,6 +229,10 @@ const Sandbox = iced(function Sandbox(options) {
metadata: 'metadata' in options ? options.metadata : {}
};
if (options.metadata && options.metadata.addonID) {
options.addonId = options.metadata.addonID;
}
let sandbox = Cu.Sandbox(options.principal, options);
// Each sandbox at creation gets set of own properties that will be shadowing
@ -393,6 +397,49 @@ 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.
@ -407,7 +454,7 @@ const nodeResolve = iced(function nodeResolve(id, requirer, { rootURI }) {
let fullId = join(rootURI, id);
let resolvedPath;
if ((resolvedPath = loadAsFile(fullId)))
if ((resolvedPath = findFile(fullId)))
return stripBase(rootURI, resolvedPath);
if ((resolvedPath = loadAsDirectory(fullId)))
@ -417,7 +464,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 = loadAsFile(dirs[i])))
if ((resolvedPath = findFile(dirs[i])))
return stripBase(rootURI, resolvedPath);
if ((resolvedPath = loadAsDirectory(dirs[i])))
@ -431,23 +478,20 @@ const nodeResolve = iced(function nodeResolve(id, requirer, { rootURI }) {
});
exports.nodeResolve = nodeResolve;
// Attempts to load `path` and then `path.js`
// Attempts to find `path` and then `path.js`
// Returns `path` with valid file, or `undefined` otherwise
function loadAsFile (path) {
let found;
function findFile (path) {
// 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) {}
return found;
// Append '.js' to path name unless it's another support filetype
path = normalizeExt(path);
if (fileExists(path))
return path;
return null;
}
// Attempts to load `path/package.json`'s `main` entry,
@ -456,25 +500,21 @@ function loadAsDirectory (path) {
try {
// If `path/package.json` exists, parse the `main` entry
// and attempt to load that
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
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
}
}
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) {}
}
} catch (e) { }
let tmpPath = path + '/index.js';
if (fileExists(tmpPath))
return tmpPath;
return void 0;
}

View File

@ -152,7 +152,7 @@ parser_groups = (
"thunderbird"),
metavar=None,
type="choice",
choices=["firefox", "fennec",
choices=["firefox",
"fennec-on-device", "thunderbird",
"xulrunner"],
default="firefox",
@ -189,6 +189,12 @@ parser_groups = (
action="store_true",
default=False,
cmds=['run', 'test'])),
(("", "--no-quit",), dict(dest="no_quit",
help=("Prevent from killing Firefox when"
"running tests"),
action="store_true",
default=False,
cmds=['run', 'test'])),
(("", "--no-strip-xpi",), dict(dest="no_strip_xpi",
help="retain unused modules in XPI",
action="store_true",
@ -664,7 +670,7 @@ def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None,
use_main = False
inherited_options = ['verbose', 'enable_e10s', 'parseable', 'check_memory',
'abort_on_missing']
'no_quit', 'abort_on_missing']
enforce_timeouts = False
if command == "xpi":
@ -855,7 +861,8 @@ def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None,
jid=jid,
update_url=options.update_url,
bootstrap=True,
enable_mobile=options.enable_mobile)
enable_mobile=options.enable_mobile,
harness_options=harness_options)
if command == "xpi" and options.update_link:
if not options.update_link.startswith("https"):
@ -936,6 +943,7 @@ def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None,
args=options.cmdargs,
extra_environment=extra_environment,
norun=options.no_run,
noquit=options.no_quit,
used_files=used_files,
enable_mobile=options.enable_mobile,
mobile_app_name=options.mobile_app_name,

View File

@ -1,25 +1,18 @@
/* 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 Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Components.utils.import("resource://gre/modules/Services.jsm");
const DEBUG = false;
let log = DEBUG ? dump : function (){};
Cu.import("resource://gre/modules/Services.jsm");
let { log } = console;
function startup(data, reason) {
// This code allow to make all stdIO work
try {
Components.utils.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://gre/modules/ctypes.jsm");
let libdvm = ctypes.open("libdvm.so");
let dvmStdioConverterStartup;
// Starting with Android ICS, dalvik uses C++.
@ -32,7 +25,7 @@ function startup(data, reason) {
dvmStdioConverterStartup = libdvm.declare("dvmStdioConverterStartup", ctypes.default_abi, ctypes.void_t);
}
dvmStdioConverterStartup();
log("MU: console redirected to adb logcat.\n");
log("MU: console redirected to adb logcat.");
} catch(e) {
Cu.reportError("MU: unable to execute jsctype hack: "+e);
}
@ -45,9 +38,9 @@ function startup(data, reason) {
}
};
Services.obs.addObserver(QuitObserver, "quit-application", false);
log("MU: ready to watch firefox exit.\n");
log("MU: ready to watch firefox exit.");
} catch(e) {
log("MU: unable to register quit-application observer: " + e + "\n");
log("MU: unable to register quit-application observer: " + e);
}
}

View File

@ -85,7 +85,7 @@ DEFAULT_FIREFOX_PREFS = {
# Point the url-classifier to a nonexistent local URL for fast failures.
'browser.safebrowsing.provider.0.gethashURL' : 'http://localhost/safebrowsing-dummy/gethash',
'browser.safebrowsing.provider.0.updateURL' : 'http://localhost/safebrowsing-dummy/update',
}
}
# When launching a temporary new Thunderbird profile, use these preferences.
# Note that these were taken from:
@ -139,4 +139,9 @@ DEFAULT_THUNDERBIRD_PREFS = {
'mail.smtpservers' : "smtp1",
'mail.startup.enabledMailCheckOnce' : True,
'mailnews.start_page_override.mstone' : "ignore",
}
}
DEFAULT_TEST_PREFS = {
'general.useragent.locale': "en-US",
'intl.locale.matchOS': "en-US"
}

View File

@ -5,6 +5,8 @@
import os
import xml.dom.minidom
import StringIO
import codecs
import glob
RDF_NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
EM_NS = "http://www.mozilla.org/2004/em-rdf#"
@ -20,9 +22,10 @@ class RDF(object):
# have .encoding hardwired to "ascii" and put only bytes in
# the backing store, so we can't use them here).
#
# The encoding= argument to dom.writexml() merely sets the XML header's
# encoding= attribute. It still writes unencoded unicode to the output file,
# so we have to encode it for real afterwards.
# The encoding= argument to dom.writexml() merely sets the
# XML header's encoding= attribute. It still writes unencoded
# unicode to the output file, so we have to encode it for
# real afterwards.
#
# Also see: https://bugzilla.mozilla.org/show_bug.cgi?id=567660
@ -112,7 +115,12 @@ class RDFManifest(RDF):
return True;
def gen_manifest(template_root_dir, target_cfg, jid,
def add_node(self, node):
top = self.dom.documentElement.getElementsByTagName("Description")[0];
top.appendChild(node)
def gen_manifest(template_root_dir, target_cfg, jid, harness_options={},
update_url=None, bootstrap=True, enable_mobile=False):
install_rdf = os.path.join(template_root_dir, "install.rdf")
manifest = RDFManifest(install_rdf)
@ -121,13 +129,51 @@ def gen_manifest(template_root_dir, target_cfg, jid,
manifest.set("em:id", jid)
manifest.set("em:version",
target_cfg.get('version', '1.0'))
if "locale" in harness_options:
# addon_title -> <em:name>
# addon_author -> <em:creator>
# addon_description -> <em:description>
# addon_homepageURL -> <em:homepageURL>
localizable_in = ["title", "author", "description", "homepage"]
localized_out = ["name", "creator", "description", "homepageURL"]
for lang in harness_options["locale"]:
desc = dom.createElement("Description")
for value_in in localizable_in:
key_in = "extensions." + target_cfg.get("id", "") + "." + value_in
tag_out = localized_out[localizable_in.index(value_in)]
if key_in in harness_options["locale"][lang]:
elem = dom.createElement("em:" + tag_out)
elem_value = harness_options["locale"][lang][key_in]
elem.appendChild(dom.createTextNode(elem_value))
desc.appendChild(elem)
# Don't add language if no localizeable field was localized
if desc.hasChildNodes():
locale = dom.createElement("em:locale")
locale.appendChild(dom.createTextNode(lang))
desc.appendChild(locale)
localized = dom.createElement("em:localized")
localized.appendChild(desc)
manifest.add_node(localized)
manifest.set("em:name",
target_cfg.get('title', target_cfg.get('fullName', target_cfg['name'])))
manifest.set("em:description",
target_cfg.get("description", ""))
manifest.set("em:creator",
target_cfg.get("author", ""))
if target_cfg.get("homepage"):
manifest.set("em:homepageURL", target_cfg.get("homepage"))
else:
manifest.remove("em:homepageURL")
manifest.set("em:bootstrap", str(bootstrap).lower())
# XPIs remain packed by default, but package.json can override that. The
# RDF format accepts "true" as True, anything else as False. We expect
# booleans in the .json file, not strings.
@ -136,7 +182,7 @@ def gen_manifest(template_root_dir, target_cfg, jid,
for translator in target_cfg.get("translators", [ ]):
elem = dom.createElement("em:translator");
elem.appendChild(dom.createTextNode(translator))
dom.documentElement.getElementsByTagName("Description")[0].appendChild(elem)
manifest.add_node(elem)
for developer in target_cfg.get("developers", [ ]):
elem = dom.createElement("em:developer");
@ -146,7 +192,7 @@ def gen_manifest(template_root_dir, target_cfg, jid,
for contributor in target_cfg.get("contributors", [ ]):
elem = dom.createElement("em:contributor");
elem.appendChild(dom.createTextNode(contributor))
dom.documentElement.getElementsByTagName("Description")[0].appendChild(elem)
manifest.add_node(elem)
if update_url:
manifest.set("em:updateURL", update_url)
@ -169,7 +215,7 @@ def gen_manifest(template_root_dir, target_cfg, jid,
if enable_mobile:
target_app = dom.createElement("em:targetApplication")
dom.documentElement.getElementsByTagName("Description")[0].appendChild(target_app)
manifest.add_node(target_app)
ta_desc = dom.createElement("Description")
target_app.appendChild(ta_desc)
@ -186,11 +232,6 @@ def gen_manifest(template_root_dir, target_cfg, jid,
elem.appendChild(dom.createTextNode("30.0a1"))
ta_desc.appendChild(elem)
if target_cfg.get("homepage"):
manifest.set("em:homepageURL", target_cfg.get("homepage"))
else:
manifest.remove("em:homepageURL")
return manifest
if __name__ == "__main__":

View File

@ -18,6 +18,7 @@ from cuddlefish.prefs import DEFAULT_FIREFOX_PREFS
from cuddlefish.prefs import DEFAULT_THUNDERBIRD_PREFS
from cuddlefish.prefs import DEFAULT_FENNEC_PREFS
from cuddlefish.prefs import DEFAULT_NO_CONNECTIONS_PREFS
from cuddlefish.prefs import DEFAULT_TEST_PREFS
# Used to remove noise from ADB output
CLEANUP_ADB = re.compile(r'^(I|E)/(stdout|stderr|GeckoConsole)\s*\(\s*\d+\):\s*(.*)$')
@ -104,30 +105,6 @@ class FennecProfile(mozrunner.Profile):
preferences = {}
names = ['fennec']
class FennecRunner(mozrunner.Runner):
profile_class = FennecProfile
names = ['fennec']
__DARWIN_PATH = '/Applications/Fennec.app/Contents/MacOS/fennec'
def __init__(self, binary=None, **kwargs):
if sys.platform == 'darwin' and binary and binary.endswith('.app'):
# Assume it's a Fennec app dir.
binary = os.path.join(binary, 'Contents/MacOS/fennec')
self.__real_binary = binary
mozrunner.Runner.__init__(self, **kwargs)
def find_binary(self):
if not self.__real_binary:
if sys.platform == 'darwin':
if os.path.exists(self.__DARWIN_PATH):
return self.__DARWIN_PATH
self.__real_binary = mozrunner.Runner.find_binary(self)
return self.__real_binary
FENNEC_REMOTE_PATH = '/mnt/sdcard/jetpack-profile'
class RemoteFennecRunner(mozrunner.Runner):
@ -167,11 +144,11 @@ class RemoteFennecRunner(mozrunner.Runner):
# or use name given as cfx `--mobile-app` argument.
intents = self.getIntentNames()
if not intents:
raise ValueError("Unable to found any Firefox "
raise ValueError("Unable to find any Firefox "
"application on your device.")
elif mobile_app_name:
if not mobile_app_name in intents:
raise ValueError("Unable to found Firefox application "
raise ValueError("Unable to find Firefox application "
"with intent name '%s'\n"
"Available ones are: %s" %
(mobile_app_name, ", ".join(intents)))
@ -412,7 +389,7 @@ def run_app(harness_root_dir, manifest_rdf, harness_options,
app_type, binary=None, profiledir=None, verbose=False,
parseable=False, enforce_timeouts=False,
logfile=None, addons=None, args=None, extra_environment={},
norun=None,
norun=None, noquit=None,
used_files=None, enable_mobile=False,
mobile_app_name=None,
env_root=None,
@ -433,6 +410,9 @@ def run_app(harness_root_dir, manifest_rdf, harness_options,
cmdargs = []
preferences = dict(DEFAULT_COMMON_PREFS)
if is_running_tests:
preferences.update(DEFAULT_TEST_PREFS)
if no_connections:
preferences.update(DEFAULT_NO_CONNECTIONS_PREFS)
@ -440,7 +420,7 @@ def run_app(harness_root_dir, manifest_rdf, harness_options,
preferences['browser.tabs.remote.autostart'] = True
# For now, only allow running on Mobile with --force-mobile argument
if app_type in ["fennec", "fennec-on-device"] and not enable_mobile:
if app_type in ["fennec-on-device"] and not enable_mobile:
print """
WARNING: Firefox Mobile support is still experimental.
If you would like to run an addon on this platform, use --force-mobile flag:
@ -454,10 +434,6 @@ def run_app(harness_root_dir, manifest_rdf, harness_options,
runner_class = RemoteFennecRunner
# We pass the intent name through command arguments
cmdargs.append(mobile_app_name)
elif enable_mobile or app_type == "fennec":
profile_class = FennecProfile
preferences.update(DEFAULT_FENNEC_PREFS)
runner_class = FennecRunner
elif app_type == "xulrunner":
profile_class = XulrunnerAppProfile
runner_class = XulrunnerAppRunner
@ -763,7 +739,8 @@ def run_app(harness_root_dir, manifest_rdf, harness_options,
raise Timeout("Test run exceeded timeout (%ds)." %
RUN_TIMEOUT, test_name, parseable)
except:
runner.stop()
if not noquit:
runner.stop()
raise
else:
runner.wait(10)

View File

@ -0,0 +1,11 @@
{
"name": "nolocalization",
"id": "jid1-TBF7sWF7yT6xSQ",
"license": "MPL 2.0",
"version": "0.1",
"title": "tilteUnlocalized",
"author": "authorUnlocalized",
"description": "descriptionUnlocalized",
"homepage": "homepageUnlocalized"
}

View File

@ -0,0 +1,4 @@
extensions.jid1-TBF7sWF7yT6xSQ@jetpack.title = title-en-GB
extensions.jid1-TBF7sWF7yT6xSQ@jetpack.author = author-en-GB
extensions.jid1-TBF7sWF7yT6xSQ@jetpack.description = description-en-GB
extensions.jid1-TBF7sWF7yT6xSQ@jetpack.homepage = homepage-en-GB

View File

@ -0,0 +1,4 @@
extensions.jid1-TBF7sWF7yT6xSQ@jetpack.title = title-en-US
extensions.jid1-TBF7sWF7yT6xSQ@jetpack.author = author-en-US
extensions.jid1-TBF7sWF7yT6xSQ@jetpack.description = description-en-US
extensions.jid1-TBF7sWF7yT6xSQ@jetpack.homepage = homepage-en-US

View File

@ -0,0 +1,11 @@
{
"name": "nolocalization",
"id": "jid1-TBF7sWF7yT6xSQ@jetpack",
"license": "MPL 2.0",
"version": "0.1",
"title": "tilteUnlocalized",
"author": "authorUnlocalized",
"description": "descriptionUnlocalized",
"homepage": "homepageUnlocalized"
}

View File

View File

@ -6,7 +6,7 @@ import unittest
import xml.dom.minidom
import os.path
from cuddlefish import rdf, packaging
from cuddlefish import rdf, packaging, property_parser
parent = os.path.dirname
test_dir = parent(os.path.abspath(__file__))
@ -49,6 +49,52 @@ class RDFTests(unittest.TestCase):
self.failUnlessEqual(m.get('em:name'), 'a long ' + n)
self.failUnlessIn('<em:name>a long ' + n + '</em:name>', str(m), n)
def testLocalization(self):
# addon_title -> <em:name>
# addon_author -> <em:creator>
# addon_description -> <em:description>
# addon_homepageURL -> <em:homepageURL>
localizable_in = ["title", "author", "description", "homepage"]
localized_out = ["name", "creator", "description", "homepageURL"]
basedir = os.path.join(test_dir, "bug-661083-files/packages")
for n in ["noLocalization", "twoLanguages"]:
harness_options = { "locale" : {} }
pkgdir = os.path.join(basedir, n)
localedir = os.path.join(pkgdir, "locale")
files = os.listdir(localedir)
for file in files:
filepath = os.path.join(localedir, file)
if os.path.isfile(filepath) and file.endswith(".properties"):
language = file[:-len(".properties")]
try:
parsed_file = property_parser.parse_file(filepath)
except property_parser.MalformedLocaleFileError, msg:
self.fail(msg)
harness_options["locale"][language] = parsed_file
cfg = packaging.get_config_in_dir(pkgdir)
m = rdf.gen_manifest(template_dir, cfg, 'JID', harness_options)
if n == "noLocalization":
self.failIf("<em:locale>" in str(m))
continue
for lang in harness_options["locale"]:
rdfstr = str(m)
node = "<em:locale>" + lang + "</em:locale>"
self.failUnlessIn(node, rdfstr, n)
for value_in in localizable_in:
key_in = "extensions." + m.get('em:id') + "." + value_in
tag_out = localized_out[localizable_in.index(value_in)]
if key_in in harness_options["locale"][lang]:
# E.g. "<em:creator>author-en-US</em:creator>"
node = "<em:" + tag_out + ">" + value_in + "-" + lang \
+ "</em:" + tag_out + ">"
self.failUnlessIn(node , rdfstr, n)
if __name__ == '__main__':
unittest.main()

View File

@ -3,15 +3,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { Cu } = require('chrome');
const self = require('sdk/self');
const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {});
const { id } = require('sdk/self');
const { getAddonByID } = require('sdk/addon/manager');
exports.testContributors = function(assert, done) {
AddonManager.getAddonByID(self.id, (addon) => {
assert.equal(addon.creator.name, 'test <test@mozilla.com>', '< and > characters work');
done();
});
exports.testContributors = function*(assert) {
let addon = yield getAddonByID(id);
assert.equal(addon.creator.name, 'test <test@mozilla.com>', '< and > characters work');
}
require('sdk/test/runner').runTestsFromModule(module);

View File

@ -9,6 +9,7 @@ const { WindowTracker } = require('sdk/deprecated/window-utils');
const { close, open } = require('sdk/window/helpers');
const { data } = require('sdk/self');
const { Panel } = require('sdk/panel');
const { setTimeout } = require("sdk/timers")
const XUL_URL = 'chrome://test/content/new-window.xul'
@ -78,11 +79,12 @@ exports.testChromeInPanel = function(assert, done) {
panel.port.once('echo', _ => {
assert.pass('got echo');
panel.once('hide', _ => {
assert.pass('panel hidden');
panel.destroy();
assert.pass('panel is destroyed');
done();
});
panel.hide();
setTimeout(() => panel.hide());
});
panel.port.emit('echo');
});

View File

@ -3,21 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { Cu } = require('chrome');
const self = require('sdk/self');
const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {});
const { id } = require('sdk/self');
const { getAddonByID } = require('sdk/addon/manager');
exports.testContributors = function(assert, done) {
AddonManager.getAddonByID(self.id, function(addon) {
let count = 0;
addon.contributors.forEach(function({ name }) {
count++;
assert.equal(name, count == 1 ? 'A' : 'B', 'The contributors keys are correct');
});
assert.equal(count, 2, 'The key count is correct');
assert.equal(addon.contributors.length, 2, 'The key length is correct');
done();
exports.testContributors = function*(assert) {
let addon = yield getAddonByID(id);
let count = 0;
addon.contributors.forEach(({ name }) => {
assert.equal(name, ++count == 1 ? 'A' : 'B', 'The contributors keys are correct');
});
assert.equal(count, 2, 'The key count is correct');
assert.equal(addon.contributors.length, 2, 'The key length is correct');
}
require('sdk/test/runner').runTestsFromModule(module);

View File

@ -6,38 +6,29 @@
const simple = require('sdk/simple-prefs');
const service = require('sdk/preferences/service');
const { id, preferencesBranch } = require('sdk/self');
const { AddonManager } = require('chrome').Cu.import('resource://gre/modules/AddonManager.jsm');
const { getAddonByID } = require('sdk/addon/manager');
exports.testCurlyID = function(assert) {
assert.equal(id, '{34a1eae1-c20a-464f-9b0e-000000000000}', 'curly ID is curly');
assert.equal(simple.prefs.test13, 26, 'test13 is 26');
simple.prefs.test14 = '15';
assert.equal(service.get('extensions.{34a1eae1-c20a-464f-9b0e-000000000000}.test14'), '15', 'test14 is 15');
assert.equal(service.get('extensions.{34a1eae1-c20a-464f-9b0e-000000000000}.test14'), simple.prefs.test14, 'simple test14 also 15');
}
exports.testInvalidPreferencesBranch = function(assert) {
assert.notEqual(preferencesBranch, 'invalid^branch*name', 'invalid preferences-branch value ignored');
assert.equal(preferencesBranch, '{34a1eae1-c20a-464f-9b0e-000000000000}', 'preferences-branch is {34a1eae1-c20a-464f-9b0e-000000000000}');
}
// from `/test/test-self.js`, adapted to `sdk/test/assert` API
exports.testSelfID = function(assert, done) {
exports.testSelfID = function*(assert) {
assert.equal(typeof(id), 'string', 'self.id is a string');
assert.ok(id.length > 0, 'self.id not empty');
AddonManager.getAddonByID(id, function(addon) {
assert.ok(addon, 'found addon with self.id');
done();
});
let addon = yield getAddonByID(id);
assert.ok(addon, 'found addon with self.id');
}
require('sdk/test/runner').runTestsFromModule(module);

View File

@ -3,21 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { Cu } = require('chrome');
const { id } = require('sdk/self');
const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {});
const { getAddonByID } = require('sdk/addon/manager');
exports.testDevelopers = function(assert, done) {
AddonManager.getAddonByID(id, (addon) => {
let count = 0;
addon.developers.forEach(({ name }) => {
count++;
assert.equal(name, count == 1 ? 'A' : 'B', 'The developers keys are correct');
});
assert.equal(count, 2, 'The key count is correct');
assert.equal(addon.developers.length, 2, 'The key length is correct');
done();
exports.testDevelopers = function*(assert) {
let addon = yield getAddonByID(id);
let count = 0;
addon.developers.forEach(({ name }) => {
assert.equal(name, ++count == 1 ? 'A' : 'B', 'The developers keys are correct');
});
assert.equal(count, 2, 'The key count is correct');
assert.equal(addon.developers.length, 2, 'The key length is correct');
}
require('sdk/test/runner').runTestsFromModule(module);

View File

@ -39,15 +39,6 @@ function LoaderWithHookedConsole(module) {
}
}
function deactivate(callback) {
if (pbUtils.isGlobalPBSupported) {
if (callback)
pb.once('stop', callback);
pb.deactivate();
}
}
exports.deactivate = deactivate;
exports.pb = pb;
exports.pbUtils = pbUtils;
exports.LoaderWithHookedConsole = LoaderWithHookedConsole;

View File

@ -4,7 +4,6 @@ const { getTabs } = require('sdk/tabs/utils');
const { isGlobalPBSupported, isWindowPBSupported, isTabPBSupported } = require('sdk/private-browsing/utils');
const { browserWindows } = require('sdk/windows');
const tabs = require('sdk/tabs');
const { pb } = require('./private-browsing/helper');
const { isPrivate } = require('sdk/private-browsing');
const { openTab, closeTab, getTabContentWindow, getOwnerWindow } = require('sdk/tabs/utils');
const { open, close } = require('sdk/window/helpers');

View File

@ -14,6 +14,7 @@ skip-if = true
[l10n-properties.xpi]
[layout-change.xpi]
[main.xpi]
[manifest-localized.xpi]
[packaging.xpi]
[packed.xpi]
[page-mod-debugger-post.xpi]

View File

@ -0,0 +1,4 @@
extensions.manifest-localized@jetpack.title = title-en
extensions.manifest-localized@jetpack.author = author-en
extensions.manifest-localized@jetpack.description = description-en
extensions.manifest-localized@jetpack.homepage = homepage-en

View 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/. */
"use strict";
const { id } = require('sdk/self');
const { getAddonByID } = require('sdk/addon/manager');
exports["test add-on manifest was localized"] = function*(assert) {
let addon = yield getAddonByID(id);
assert.equal(addon.name, "title-en", "title was translated");
assert.equal(addon.description, "description-en", "description was translated");
assert.equal(addon.creator, "author-en", "author was translated");
assert.equal(addon.homepageURL, "homepage-en", "homepage was translated");
};
require("sdk/test/runner").runTestsFromModule(module);

View File

@ -0,0 +1,10 @@
{
"name": "manifest-localized",
"id": "manifest-localized@jetpack",
"license": "MPL 2.0",
"version": "0.1",
"title": "Manifest Not Localized",
"author": "Manifest Not Localized",
"description": "Manifest Not Localized",
"homepage": "Manifest Not Localized"
}

View File

@ -15,8 +15,7 @@ const { filter } = require('sdk/event/utils');
const { on, off } = require('sdk/event/core');
const { setTimeout } = require('sdk/timers');
const { newURI } = require('sdk/url/utils');
const { defer, all } = require('sdk/core/promise');
const { defer: async } = require('sdk/lang/functional');
const { defer, all, resolve } = require('sdk/core/promise');
const { before, after } = require('sdk/test/utils');
const {
@ -41,6 +40,7 @@ exports.testDefaultFolders = function (assert) {
bmsrv.toolbarFolder,
bmsrv.unfiledBookmarksFolder
];
[MENU, TOOLBAR, UNSORTED].forEach(function (g, i) {
assert.ok(g.id === ids[i], ' default group matches id');
});
@ -321,8 +321,7 @@ exports.testAddingToExistingParent = function (assert, done) {
secondBatch = data;
assert.equal(firstBatch[0].group.id, secondBatch[0].group.id,
'successfully saved to the same parent');
done();
}, assert.fail);
}).then(done).catch(assert.fail);
};
exports.testUpdateParent = function (assert, done) {
@ -332,8 +331,7 @@ exports.testUpdateParent = function (assert, done) {
return saveP(item[0]);
}).then(item => {
assert.equal(item[0].title, 'mozgroup-resave', 'group saved successfully');
done();
});
}).then(done).catch(assert.fail);
};
exports.testUpdateSeparator = function (assert, done) {
@ -343,8 +341,7 @@ exports.testUpdateSeparator = function (assert, done) {
return saveP(item[0]);
}).then(item => {
assert.equal(item[0].index, 2, 'updated index of separator');
done();
});
}).then(done).catch(assert.fail);
};
exports.testPromisedSave = function (assert, done) {
@ -369,8 +366,7 @@ exports.testPromisedSave = function (assert, done) {
assert.equal(bmsrv.getItemIndex(first.id), 2, 'properly moved bookmark');
assert.equal(bmsrv.getItemIndex(second.id), 0, 'other bookmarks adjusted');
assert.equal(bmsrv.getItemIndex(third.id), 1, 'other bookmarks adjusted');
done();
});
}).then(done).catch(assert.fail);
};
exports.testPromisedErrorSave = function (assert, done) {
@ -379,6 +375,7 @@ exports.testPromisedErrorSave = function (assert, done) {
{ title: 'moz2', url: 'invalidurl', type: 'bookmark'},
{ title: 'moz3', url: 'http://moz3.com', type: 'bookmark'}
];
saveP(bookmarks).then(invalidResolve, reason => {
assert.ok(
/The `url` property must be a valid URL/.test(reason),
@ -386,13 +383,14 @@ exports.testPromisedErrorSave = function (assert, done) {
bookmarks[1].url = 'http://moz2.com';
return saveP(bookmarks);
}).then(res => {
return searchP({ query: 'moz' });
}).then(res => {
}).
then(res => searchP({ query: 'moz' })).
then(res => {
assert.equal(res.length, 3, 'all 3 should be saved upon retry');
res.map(item => assert.ok(/moz\d\.com/.test(item.url), 'correct item'));
done();
}, invalidReject);
}, invalidReject).
catch(assert.fail);
};
exports.testMovingChildren = function (assert, done) {
@ -403,6 +401,7 @@ exports.testMovingChildren = function (assert, done) {
Bookmark({ title: 'moz2', url: 'http://moz2.com', group: midFolder}),
Bookmark({ title: 'moz3', url: 'http://moz3.com', group: midFolder})
];
save(bookmarks).on('end', bms => {
let first = bms.filter(b => b.title === 'moz1')[0];
let second = bms.filter(b => b.title === 'moz2')[0];
@ -488,7 +487,7 @@ exports.testRemove = function (assert, done) {
}, 'item should no longer exist');
done();
});
});
}).catch(assert.fail);
};
/*
@ -524,7 +523,7 @@ exports.testResolution = function (assert, done) {
assert.ok(item.updated, 'bookmark has updated time');
item.title = 'my title';
// Ensure delay so a different save time is set
return delayed(item);
return resolve(item);
}).then(saveP)
.then(items => {
let item = items[0];
@ -546,8 +545,7 @@ exports.testResolution = function (assert, done) {
}).then((results) => {
let result = results[0];
assert.equal(result.title, 'a new title', 'resolve handles results');
done();
});
}).then(done).catch(assert.fail);;
};
/*
@ -556,13 +554,15 @@ exports.testResolution = function (assert, done) {
exports.testResolutionMapping = function (assert, done) {
let bookmark = Bookmark({ title: 'moz', url: 'http://bookmarks4life.com/' });
let saved;
saveP(bookmark).then(data => {
saved = data[0];
saved.title = 'updated title';
// Ensure a delay for different updated times
return delayed(saved);
}).then(saveP)
.then(() => {
return resolve(saved);
}).
then(saveP).
then(() => {
bookmark.title = 'conflicting title';
return saveP(bookmark, { resolve: (mine, theirs) => {
assert.equal(mine.title, 'conflicting title', 'correct data for my object');
@ -579,8 +579,7 @@ exports.testResolutionMapping = function (assert, done) {
}).then((results) => {
let result = results[0];
assert.equal(result.title, 'a new title', 'resolve handles results');
done();
});
}).then(done).catch(assert.fail);
};
exports.testUpdateTags = function (assert, done) {
@ -595,7 +594,7 @@ exports.testUpdateTags = function (assert, done) {
assert.ok(!saved.tags.has('spidermonkey'), 'should not have removed tag');
done();
});
});
}).catch(assert.fail);
};
/*
@ -625,8 +624,7 @@ exports.testSearchByGroupSimple = function (assert, done) {
'returns all children bookmarks/folders');
assert.ok(results.filter(({url}) => url === 'http://w3schools.com/'),
'returns nested children');
done();
}).then(null, assert.fail);
}).then(done).catch(assert.fail);
};
exports.testSearchByGroupComplex = function (assert, done) {
@ -643,8 +641,7 @@ exports.testSearchByGroupComplex = function (assert, done) {
assert.ok(
!results.filter(({url}) => /developer.mozilla/.test(url)).length,
'does not find results from other folders');
done();
}, assert.fail);
}).then(done).catch(assert.fail);
};
exports.testSearchEmitters = function (assert, done) {
@ -666,7 +663,7 @@ exports.testSearchEmitters = function (assert, done) {
assert.equal(data[0] + '', '[object Bookmark]', 'returns bookmarks');
done();
});
});
}).catch(assert.fail);
};
exports.testSearchTags = function (assert, done) {
@ -685,8 +682,7 @@ exports.testSearchTags = function (assert, done) {
// OR tags
assert.equal(data.length, 6,
'should return all bookmarks with firefox OR javascript tag');
done();
});
}).then(done).catch(assert.fail);
};
/*
@ -724,9 +720,7 @@ exports.testSearchURL = function (assert, done) {
assert.equal(data[0].url, 'http://mozilla.org/');
assert.equal(data[1].url, 'http://mozilla.org/thunderbird/');
assert.equal(data[2].url, 'http://component.fm/');
}).then(() => {
done();
});
}).then(done).catch(assert.fail);
};
/*
@ -752,9 +746,7 @@ exports.testSearchQuery = function (assert, done) {
assert.equal(data.length, 1);
assert.equal(data[0].title, 'mdn',
'only one item matches moz query AND has a javascript tag');
}).then(() => {
done();
});
}).then(done).catch(assert.fail);
};
/*
@ -804,8 +796,7 @@ exports.testCaching = function (assert, done) {
// require a lookup
assert.equal(count, 6, 'lookup occurs once for each item and parent');
off(stream, 'data', handle);
done();
});
}).then(done).catch(assert.fail);
function handle ({data}) count++
};
@ -822,9 +813,8 @@ exports.testSearchCount = function (assert, done) {
.then(testCount(3))
.then(testCount(5))
.then(testCount(10))
.then(() => {
done();
});
.then(done)
.catch(assert.fail);;
function testCount (n) {
return function () {
@ -901,9 +891,7 @@ exports.testSearchSort = function (assert, done) {
}).then(results => {
assert.equal(results[0].url, 'http://mozilla.com/webfwd/',
'last modified should be first');
}).then(() => {
done();
});
}).then(done).catch(assert.fail);;
function checkOrder (results, nums) {
assert.equal(results.length, nums.length, 'expected return count');
@ -926,8 +914,7 @@ exports.testSearchComplexQueryWithOptions = function (assert, done) {
];
for (let i = 0; i < expected.length; i++)
assert.equal(results[i].url, expected[i], 'correct ordering and item');
done();
});
}).then(done).catch(assert.fail);;
};
exports.testCheckSaveOrder = function (assert, done) {
@ -943,8 +930,7 @@ exports.testCheckSaveOrder = function (assert, done) {
for (let i = 0; i < bookmarks.length; i++)
assert.equal(results[i].url, bookmarks[i].url,
'correct ordering of bookmark results');
done();
});
}).then(done).catch(assert.fail);;
};
before(exports, (name, assert, done) => resetPlaces(done));
@ -957,9 +943,3 @@ function saveP () {
function searchP () {
return promisedEmitter(search.apply(null, Array.slice(arguments)));
}
function delayed (value, ms) {
let { promise, resolve } = defer();
setTimeout(() => resolve(value), ms || 10);
return promise;
}

View File

@ -305,8 +305,16 @@ exports['test history-delete-visits'] = function (assert) {
assert.pass('TODO test history-delete-visits');
};
// Bug 1060843
// Wait a tick before finishing tests, as some bookmark activities require
// completion of a result for events. For example, when creating a bookmark,
// a `bookmark-item-added` event is fired, listened to by the first test here,
// while constructing the bookmark item requires subsequent calls to that bookmark item.
// If we destroy the underlying bookmark immediately, these calls will fail.
//
// The places SDK abstraction around this alleviates it, but these are low level events.
after(exports, (name, assert, done) => setTimeout(() => resetPlaces(done), 1));
before(exports, (name, assert, done) => resetPlaces(done));
after(exports, (name, assert, done) => resetPlaces(done));
function saveP () {
return promisedEmitter(save.apply(null, Array.slice(arguments)));

View File

@ -6,7 +6,7 @@
const { id, preferencesBranch } = require('sdk/self');
const simple = require('sdk/simple-prefs');
const service = require('sdk/preferences/service');
const { AddonManager } = require('chrome').Cu.import('resource://gre/modules/AddonManager.jsm', {});
const { getAddonByID } = require('sdk/addon/manager');
const expected_id = 'predefined-id@test';
@ -21,14 +21,12 @@ exports.testExpectedID = function(assert) {
assert.equal(service.get('extensions.'+expected_id+'.test2'), simple.prefs.test2, 'test pref is 25');
}
exports.testSelfID = function(assert, done) {
exports.testSelfID = function*(assert) {
assert.equal(typeof(id), 'string', 'self.id is a string');
assert.ok(id.length > 0, 'self.id not empty');
AddonManager.getAddonByID(id, function(addon) {
assert.equal(addon.id, id, 'found addon with self.id');
done();
});
let addon = yield getAddonByID(id);
assert.equal(addon.id, id, 'found addon with self.id');
}
require('sdk/test/runner').runTestsFromModule(module);

View File

@ -1,17 +1,15 @@
/* 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 { id, preferencesBranch } = require('sdk/self');
const simple = require('sdk/simple-prefs');
const service = require('sdk/preferences/service');
const { AddonManager } = require('chrome').Cu.import('resource://gre/modules/AddonManager.jsm');
const { getAddonByID } = require('sdk/addon/manager');
exports.testPreferencesBranch = function(assert) {
assert.equal(preferencesBranch, 'human-readable', 'preferencesBranch is human-readable');
assert.equal(simple.prefs.test42, true, 'test42 is true');
simple.prefs.test43 = 'movie';
@ -20,16 +18,11 @@ exports.testPreferencesBranch = function(assert) {
}
// from `/test/test-self.js`, adapted to `sdk/test/assert` API
exports.testSelfID = function(assert, done) {
exports.testSelfID = function*(assert) {
assert.equal(typeof(id), 'string', 'self.id is a string');
assert.ok(id.length > 0, 'self.id not empty');
AddonManager.getAddonByID(id, function(addon) {
assert.ok(addon, 'found addon with self.id');
done();
});
let addon = yield getAddonByID(id);
assert.ok(addon, 'found addon with self.id');
}
require('sdk/test/runner').runTestsFromModule(module);

View File

@ -5,14 +5,12 @@
const { merge } = require('sdk/util/object');
const app = require('sdk/system/xul-app');
const { isGlobalPBSupported } = require('sdk/private-browsing/utils');
merge(module.exports,
require('./test-tabs'),
require('./test-page-mod'),
require('./test-private-browsing'),
require('./test-sidebar'),
isGlobalPBSupported ? require('./test-global-private-browsing') : {}
require('./test-sidebar')
);
// Doesn't make sense to test window-utils and windows on fennec,

View File

@ -1,150 +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 windowUtils = require('sdk/deprecated/window-utils');
const { isWindowPBSupported, isGlobalPBSupported } = require('sdk/private-browsing/utils');
const { getFrames, getWindowTitle, onFocus, isWindowPrivate, windows, isBrowser } = require('sdk/window/utils');
const { open, close, focus } = require('sdk/window/helpers');
const { isPrivate } = require('sdk/private-browsing');
const { Panel } = require('sdk/panel');
const { Widget } = require('sdk/widget');
const { fromIterator: toArray } = require('sdk/util/array');
let { Loader } = require('sdk/test/loader');
let loader = Loader(module, {
console: Object.create(console, {
error: {
value: function(e) !/DEPRECATED:/.test(e) ? console.error(e) : undefined
}
})
});
const pb = loader.require('sdk/private-browsing');
function makeEmptyBrowserWindow(options) {
options = options || {};
return open('chrome://browser/content/browser.xul', {
features: {
chrome: true,
private: !!options.private,
toolbar: true
}
});
}
exports.testShowPanelAndWidgetOnPrivateWindow = function(assert, done) {
var myPrivateWindow;
var finished = false;
var privateWindow;
var privateWindowClosed = false;
pb.once('start', function() {
assert.pass('private browsing mode started');
// make a new private window
makeEmptyBrowserWindow().then(function(window) {
myPrivateWindow = window;
let wt = windowUtils.WindowTracker({
onTrack: function(window) {
if (!isBrowser(window) || window !== myPrivateWindow) return;
assert.ok(isWindowPrivate(window), 'window is private onTrack!');
let panel = Panel({
onShow: function() {
assert.ok(this.isShowing, 'the panel is showing on the private window');
let count = 0;
let widget = Widget({
id: "testShowPanelAndWidgetOnPrivateWindow-id",
label: "My Hello Widget",
content: "Hello!",
onAttach: function(mod) {
count++;
if (count == 2) {
panel.destroy();
widget.destroy();
close(window);
}
}
});
}
}).show(null, window.gBrowser);
},
onUntrack: function(window) {
if (window === myPrivateWindow) {
wt.unload();
pb.once('stop', function() {
assert.pass('private browsing mode end');
done();
});
pb.deactivate();
}
}
});
assert.equal(isWindowPrivate(window), true, 'the opened window is private');
assert.equal(isPrivate(window), true, 'the opened window is private');
assert.ok(getFrames(window).length > 1, 'there are frames for private window');
assert.equal(getWindowTitle(window), window.document.title,
'getWindowTitle works');
});
});
pb.activate();
};
exports.testWindowTrackerDoesNotIgnorePrivateWindows = function(assert, done) {
var myPrivateWindow;
var count = 0;
let wt = windowUtils.WindowTracker({
onTrack: function(window) {
if (!isBrowser(window) || !isWindowPrivate(window)) return;
assert.ok(isWindowPrivate(window), 'window is private onTrack!');
if (++count == 1)
close(window);
},
onUntrack: function(window) {
if (count == 1 && isWindowPrivate(window)) {
wt.unload();
pb.once('stop', function() {
assert.pass('private browsing mode end');
done();
});
pb.deactivate();
}
}
});
pb.once('start', function() {
assert.pass('private browsing mode started');
makeEmptyBrowserWindow();
});
pb.activate();
}
exports.testWindowIteratorDoesNotIgnorePrivateWindows = function(assert, done) {
pb.once('start', function() {
// make a new private window
makeEmptyBrowserWindow().then(function(window) {
assert.ok(isWindowPrivate(window), "window is private");
assert.equal(isPrivate(window), true, 'the opened window is private');
assert.ok(toArray(windowUtils.windowIterator()).indexOf(window) > -1,
"window is in windowIterator()");
assert.ok(windows(null, { includePrivate: true }).indexOf(window) > -1,
"window is in windows()");
return close(window).then(function() {
pb.once('stop', function() {
done();
});
pb.deactivate();
});
}).then(null, assert.fail);
});
pb.activate();
};

View File

@ -6,27 +6,24 @@
const { Cu } = require('chrome');
const sp = require('sdk/simple-prefs');
const app = require('sdk/system/xul-app');
const self = require('sdk/self');
const tabs = require('sdk/tabs');
const { preferencesBranch } = require('sdk/self');
const { preferencesBranch, id } = require('sdk/self');
const { getAddonByID } = require('sdk/addon/manager');
const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {});
exports.testRegression = function(assert) {
assert.equal(self.preferencesBranch, self.id, 'preferencesBranch returns id here');
exports.testRegression = (assert) => {
assert.equal(preferencesBranch, id, 'preferencesBranch returns id here');
}
exports.testDefaultValues = function (assert) {
exports.testDefaultValues = (assert) => {
assert.equal(sp.prefs.myHiddenInt, 5, 'myHiddenInt default is 5');
assert.equal(sp.prefs.myInteger, 8, 'myInteger default is 8');
assert.equal(sp.prefs.somePreference, 'TEST', 'somePreference default is correct');
}
exports.testOptionsType = function(assert, done) {
AddonManager.getAddonByID(self.id, function(aAddon) {
assert.equal(aAddon.optionsType, AddonManager.OPTIONS_TYPE_INLINE, 'options type is inline');
done();
});
exports.testOptionsType = function*(assert) {
let addon = yield getAddonByID(id);
assert.equal(addon.optionsType, AddonManager.OPTIONS_TYPE_INLINE, 'options type is inline');
}
if (app.is('Firefox')) {
@ -38,7 +35,7 @@ if (app.is('Firefox')) {
contentScriptWhen: 'end',
contentScript: 'function onLoad() {\n' +
'unsafeWindow.removeEventListener("load", onLoad, false);\n' +
'AddonManager.getAddonByID("' + self.id + '", function(aAddon) {\n' +
'AddonManager.getAddonByID("' + id + '", function(aAddon) {\n' +
'unsafeWindow.gViewController.viewObjects.detail.node.addEventListener("ViewChanged", function whenViewChanges() {\n' +
'unsafeWindow.gViewController.viewObjects.detail.node.removeEventListener("ViewChanged", whenViewChanges, false);\n' +
'setTimeout(function() {\n' + // TODO: figure out why this is necessary..
@ -70,13 +67,13 @@ if (app.is('Firefox')) {
onMessage: function(msg) {
// test somePreference
assert.equal(msg.somePreference.type, 'string', 'some pref is a string');
assert.equal(msg.somePreference.pref, 'extensions.'+self.preferencesBranch+'.somePreference', 'somePreference path is correct');
assert.equal(msg.somePreference.pref, 'extensions.'+preferencesBranch+'.somePreference', 'somePreference path is correct');
assert.equal(msg.somePreference.title, 'some-title', 'somePreference title is correct');
assert.equal(msg.somePreference.desc, 'Some short description for the preference', 'somePreference description is correct');
// test myInteger
assert.equal(msg.myInteger.type, 'integer', 'myInteger is a int');
assert.equal(msg.myInteger.pref, 'extensions.'+self.preferencesBranch+'.myInteger', 'extensions.test-simple-prefs.myInteger');
assert.equal(msg.myInteger.pref, 'extensions.'+preferencesBranch+'.myInteger', 'extensions.test-simple-prefs.myInteger');
assert.equal(msg.myInteger.title, 'my-int', 'myInteger title is correct');
assert.equal(msg.myInteger.desc, 'How many of them we have.', 'myInteger desc is correct');

View File

@ -6,14 +6,13 @@
const { Cu } = require('chrome');
const sp = require('sdk/simple-prefs');
const app = require('sdk/system/xul-app');
const self = require('sdk/self');
const { preferencesBranch } = self;
const { id, preferencesBranch } = require('sdk/self');
const { open } = require('sdk/preferences/utils');
const { getTabForId } = require('sdk/tabs/utils');
const { Tab } = require('sdk/tabs/tab');
require('sdk/tabs');
const { getAddonByID } = require('sdk/addon/manager');
const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {});
require('sdk/tabs');
exports.testDefaultValues = function (assert) {
assert.equal(sp.prefs.myHiddenInt, 5, 'myHiddenInt default is 5');
@ -21,15 +20,13 @@ exports.testDefaultValues = function (assert) {
assert.equal(sp.prefs.somePreference, 'TEST', 'somePreference default is correct');
}
exports.testOptionsType = function(assert, done) {
AddonManager.getAddonByID(self.id, function(aAddon) {
assert.equal(aAddon.optionsType, AddonManager.OPTIONS_TYPE_INLINE, 'options type is inline');
done();
});
exports.testOptionsType = function*(assert) {
let addon = yield getAddonByID(id);
assert.equal(addon.optionsType, AddonManager.OPTIONS_TYPE_INLINE, 'options type is inline');
}
exports.testButton = function(assert, done) {
open(self).then(({ tabId, document }) => {
open({ id: id }).then(({ tabId, document }) => {
let tab = Tab({ tab: getTabForId(tabId) });
sp.once('sayHello', _ => {
assert.pass('The button was pressed!');
@ -44,7 +41,7 @@ exports.testButton = function(assert, done) {
if (app.is('Firefox')) {
exports.testAOM = function(assert, done) {
open(self).then(({ tabId }) => {
open({ id: id }).then(({ tabId }) => {
let tab = Tab({ tab: getTabForId(tabId) });
assert.pass('the add-on prefs page was opened.');
@ -73,17 +70,17 @@ if (app.is('Firefox')) {
// test somePreference
assert.equal(msg.somePreference.type, 'string', 'some pref is a string');
assert.equal(msg.somePreference.pref, 'extensions.'+self.id+'.somePreference', 'somePreference path is correct');
assert.equal(msg.somePreference.pref, 'extensions.' + id + '.somePreference', 'somePreference path is correct');
assert.equal(msg.somePreference.title, 'some-title', 'somePreference title is correct');
assert.equal(msg.somePreference.desc, 'Some short description for the preference', 'somePreference description is correct');
assert.equal(msg.somePreference['data-jetpack-id'], self.id, 'data-jetpack-id attribute value is correct');
assert.equal(msg.somePreference['data-jetpack-id'], id, 'data-jetpack-id attribute value is correct');
// test myInteger
assert.equal(msg.myInteger.type, 'integer', 'myInteger is a int');
assert.equal(msg.myInteger.pref, 'extensions.'+self.id+'.myInteger', 'extensions.test-simple-prefs.myInteger');
assert.equal(msg.myInteger.pref, 'extensions.' + id + '.myInteger', 'extensions.test-simple-prefs.myInteger');
assert.equal(msg.myInteger.title, 'my-int', 'myInteger title is correct');
assert.equal(msg.myInteger.desc, 'How many of them we have.', 'myInteger desc is correct');
assert.equal(msg.myInteger['data-jetpack-id'], self.id, 'data-jetpack-id attribute value is correct');
assert.equal(msg.myInteger['data-jetpack-id'], id, 'data-jetpack-id attribute value is correct');
// test myHiddenInt
assert.equal(msg.myHiddenInt.type, undefined, 'myHiddenInt was not displayed');
@ -92,7 +89,7 @@ if (app.is('Firefox')) {
assert.equal(msg.myHiddenInt.desc, undefined, 'myHiddenInt was not displayed');
// test sayHello
assert.equal(msg.sayHello['data-jetpack-id'], self.id, 'data-jetpack-id attribute value is correct');
assert.equal(msg.sayHello['data-jetpack-id'], id, 'data-jetpack-id attribute value is correct');
tab.close(done);
}
@ -103,11 +100,10 @@ if (app.is('Firefox')) {
// run it again, to test against inline options document caching
// and duplication of <setting> nodes upon re-entry to about:addons
exports.testAgainstDocCaching = exports.testAOM;
}
exports.testDefaultPreferencesBranch = function(assert) {
assert.equal(preferencesBranch, self.id, 'preferencesBranch default the same as self.id');
assert.equal(preferencesBranch, id, 'preferencesBranch default the same as self.id');
}
require('sdk/test/runner').runTestsFromModule(module);

View File

@ -7,7 +7,7 @@
const { id, preferencesBranch } = require('sdk/self');
const simple = require('sdk/simple-prefs');
const service = require('sdk/preferences/service');
const { AddonManager } = require('chrome').Cu.import('resource://gre/modules/AddonManager.jsm');
const { getAddonByID } = require('sdk/addon/manager');
exports.testStandardID = function(assert) {
assert.equal(id, 'standard-id@jetpack', 'standard ID is standard');
@ -16,29 +16,20 @@ exports.testStandardID = function(assert) {
simple.prefs.test14 = '15';
assert.equal(service.get('extensions.standard-id@jetpack.test14'), '15', 'test14 is 15');
assert.equal(service.get('extensions.standard-id@jetpack.test14'), simple.prefs.test14, 'simple test14 also 15');
}
exports.testInvalidPreferencesBranch = function(assert) {
assert.notEqual(preferencesBranch, 'invalid^branch*name', 'invalid preferences-branch value ignored');
assert.equal(preferencesBranch, 'standard-id@jetpack', 'preferences-branch is standard-id@jetpack');
}
// from `/test/test-self.js`, adapted to `sdk/test/assert` API
exports.testSelfID = function(assert, done) {
exports.testSelfID = function*(assert) {
assert.equal(typeof(id), 'string', 'self.id is a string');
assert.ok(id.length > 0, 'self.id not empty');
AddonManager.getAddonByID(id, function(addon) {
assert.ok(addon, 'found addon with self.id');
done();
});
let addon = yield getAddonByID(id);
assert.ok(addon, 'found addon with self.id');
}
require('sdk/test/runner').runTestsFromModule(module);

View File

@ -3,21 +3,18 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { Cc, Ci, Cu, Cm, components } = require('chrome');
const self = require('sdk/self');
const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {});
const { id } = require('sdk/self');
const { getAddonByID } = require('sdk/addon/manager');
exports.testTranslators = function(assert, done) {
AddonManager.getAddonByID(self.id, function(addon) {
let count = 0;
addon.translators.forEach(function({ name }) {
count++;
assert.equal(name, 'Erik Vold', 'The translator keys are correct');
});
assert.equal(count, 1, 'The translator key count is correct');
assert.equal(addon.translators.length, 1, 'The translator key length is correct');
done();
exports.testTranslators = function*(assert) {
let addon = yield getAddonByID(id);
let count = 0;
addon.translators.forEach(function({ name }) {
count++;
assert.equal(name, 'Erik Vold', 'The translator keys are correct');
});
assert.equal(count, 1, 'The translator key count is correct');
assert.equal(addon.translators.length, 1, 'The translator key length is correct');
}
require('sdk/test/runner').runTestsFromModule(module);

View File

@ -18,6 +18,7 @@ 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]
@ -153,7 +154,6 @@ skip-if = true
[test-window-events.js]
[test-window-loader.js]
[test-window-observer.js]
[test-window-utils-global-private-browsing.js]
[test-window-utils-private-browsing.js]
[test-window-utils.js]
[test-window-utils2.js]

View File

@ -1,239 +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 timer = require("sdk/timers");
const { LoaderWithHookedConsole, deactivate, pb, pbUtils } = require("./helper");
const tabs = require("sdk/tabs");
const { getMostRecentBrowserWindow, isWindowPrivate } = require('sdk/window/utils');
const { set: setPref } = require("sdk/preferences/service");
const DEPRECATE_PREF = "devtools.errorconsole.deprecation_warnings";
exports["test activate private mode via handler"] = function(assert, done) {
function onReady(tab) {
if (tab.url == "about:robots")
tab.close(function() pb.activate());
}
function cleanup(tab) {
if (tab.url == "about:") {
tabs.removeListener("ready", cleanup);
tab.close(function onClose() {
done();
});
}
}
tabs.on("ready", onReady);
pb.once("start", function onStart() {
assert.pass("private mode was activated");
pb.deactivate();
});
pb.once("stop", function onStop() {
assert.pass("private mode was deactivated");
tabs.removeListener("ready", onReady);
tabs.on("ready", cleanup);
});
tabs.once("open", function onOpen() {
tabs.open("about:robots");
});
tabs.open("about:");
};
// tests that isActive has the same value as the private browsing service
// expects
exports.testGetIsActive = function (assert) {
assert.equal(pb.isActive, false,
"private-browsing.isActive is correct without modifying PB service");
assert.equal(pb.isPrivate(), false,
"private-browsing.sPrivate() is correct without modifying PB service");
pb.once("start", function() {
assert.ok(pb.isActive,
"private-browsing.isActive is correct after modifying PB service");
assert.ok(pb.isPrivate(),
"private-browsing.sPrivate() is correct after modifying PB service");
// Switch back to normal mode.
pb.deactivate();
});
pb.activate();
pb.once("stop", function() {
assert.ok(!pb.isActive,
"private-browsing.isActive is correct after modifying PB service");
assert.ok(!pb.isPrivate(),
"private-browsing.sPrivate() is correct after modifying PB service");
test.done();
});
};
exports.testStart = function(assert, done) {
pb.on("start", function onStart() {
assert.equal(this, pb, "`this` should be private-browsing module");
assert.ok(pbUtils.getMode(),
'private mode is active when "start" event is emitted');
assert.ok(pb.isActive,
'`isActive` is `true` when "start" event is emitted');
assert.ok(pb.isPrivate(),
'`isPrivate` is `true` when "start" event is emitted');
pb.removeListener("start", onStart);
deactivate(done);
});
pb.activate();
};
exports.testStop = function(assert, done) {
pb.once("stop", function onStop() {
assert.equal(this, pb, "`this` should be private-browsing module");
assert.equal(pbUtils.getMode(), false,
"private mode is disabled when stop event is emitted");
assert.equal(pb.isActive, false,
"`isActive` is `false` when stop event is emitted");
assert.equal(pb.isPrivate(), false,
"`isPrivate()` is `false` when stop event is emitted");
done();
});
pb.activate();
pb.once("start", function() {
pb.deactivate();
});
};
exports.testBothListeners = function(assert, done) {
let stop = false;
let start = false;
function onStop() {
assert.equal(stop, false,
"stop callback must be called only once");
assert.equal(pbUtils.getMode(), false,
"private mode is disabled when stop event is emitted");
assert.equal(pb.isActive, false,
"`isActive` is `false` when stop event is emitted");
assert.equal(pb.isPrivate(), false,
"`isPrivate()` is `false` when stop event is emitted");
pb.on("start", finish);
pb.removeListener("start", onStart);
pb.removeListener("start", onStart2);
pb.activate();
stop = true;
}
function onStart() {
assert.equal(false, start,
"stop callback must be called only once");
assert.ok(pbUtils.getMode(),
"private mode is active when start event is emitted");
assert.ok(pb.isActive,
"`isActive` is `true` when start event is emitted");
assert.ok(pb.isPrivate(),
"`isPrivate()` is `true` when start event is emitted");
pb.on("stop", onStop);
pb.deactivate();
start = true;
}
function onStart2() {
assert.ok(start, "start listener must be called already");
assert.equal(false, stop, "stop callback must not be called yet");
}
function finish() {
assert.ok(pbUtils.getMode(), true,
"private mode is active when start event is emitted");
assert.ok(pb.isActive,
"`isActive` is `true` when start event is emitted");
assert.ok(pb.isPrivate(),
"`isPrivate()` is `true` when start event is emitted");
pb.removeListener("start", finish);
pb.removeListener("stop", onStop);
pb.deactivate();
pb.once("stop", function () {
assert.equal(pbUtils.getMode(), false);
assert.equal(pb.isActive, false);
assert.equal(pb.isPrivate(), false);
done();
});
}
pb.on("start", onStart);
pb.on("start", onStart2);
pb.activate();
};
exports.testAutomaticUnload = function(assert, done) {
setPref(DEPRECATE_PREF, true);
// Create another private browsing instance and unload it
let { loader, errors } = LoaderWithHookedConsole(module);
let pb2 = loader.require("sdk/private-browsing");
let called = false;
pb2.on("start", function onStart() {
called = true;
assert.fail("should not be called:x");
});
loader.unload();
// Then switch to private mode in order to check that the previous instance
// is correctly destroyed
pb.once("start", function onStart() {
timer.setTimeout(function () {
assert.ok(!called,
"First private browsing instance is destroyed and inactive");
// Must reset to normal mode, so that next test starts with it.
deactivate(function() {
assert.ok(errors.length, 0, "should have been 1 deprecation error");
done();
});
}, 0);
});
pb.activate();
};
exports.testUnloadWhileActive = function(assert, done) {
let called = false;
let { loader, errors } = LoaderWithHookedConsole(module);
let pb2 = loader.require("sdk/private-browsing");
let ul = loader.require("sdk/system/unload");
let unloadHappened = false;
ul.when(function() {
unloadHappened = true;
timer.setTimeout(function() {
pb.deactivate();
});
});
pb2.once("start", function() {
loader.unload();
});
pb2.once("stop", function() {
called = true;
assert.ok(unloadHappened, "the unload event should have already occurred.");
assert.fail("stop should not have been fired");
});
pb.once("stop", function() {
assert.ok(!called, "stop was not called on unload");
assert.ok(errors.length, 2, "should have been 2 deprecation errors");
done();
});
pb.activate();
};
exports.testIgnoreWindow = function(assert, done) {
let window = getMostRecentBrowserWindow();
pb.once('start', function() {
assert.ok(isWindowPrivate(window), 'window is private');
assert.ok(!pbUtils.ignoreWindow(window), 'window is not ignored');
pb.once('stop', done);
pb.deactivate();
});
pb.activate();
};

View File

@ -3,12 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { Loader } = require('sdk/test/loader');
const { loader } = LoaderWithHookedConsole(module);
const pb = loader.require('sdk/private-browsing');
const pbUtils = loader.require('sdk/private-browsing/utils');
const xulApp = require("sdk/system/xul-app");
const { open: openWindow, getMostRecentBrowserWindow } = require('sdk/window/utils');
const { openTab, getTabContentWindow, getActiveTab, setTabURL, closeTab } = require('sdk/tabs/utils');
@ -16,42 +10,6 @@ const promise = require("sdk/core/promise");
const windowHelpers = require('sdk/window/helpers');
const events = require("sdk/system/events");
function LoaderWithHookedConsole(module) {
let globals = {};
let errors = [];
globals.console = Object.create(console, {
error: {
value: function(e) {
errors.push(e);
if (!/DEPRECATED:/.test(e)) {
console.error(e);
}
}
}
});
let loader = Loader(module, globals);
return {
loader: loader,
errors: errors
}
}
function deactivate(callback) {
if (pbUtils.isGlobalPBSupported) {
if (callback)
pb.once('stop', callback);
pb.deactivate();
}
}
exports.deactivate = deactivate;
exports.pb = pb;
exports.pbUtils = pbUtils;
exports.LoaderWithHookedConsole = LoaderWithHookedConsole;
exports.openWebpage = function openWebpage(url, enablePrivate) {
if (xulApp.is("Fennec")) {
let chromeWindow = getMostRecentBrowserWindow();

View File

@ -3,10 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { pb, pbUtils } = require('./helper');
const { onFocus, openDialog, open } = require('sdk/window/utils');
const { open: openPromise, close, focus, promise } = require('sdk/window/helpers');
const { isPrivate } = require('sdk/private-browsing');
const { getMode } = require('sdk/private-browsing/utils');
const { browserWindows: windows } = require('sdk/windows');
const { defer } = require('sdk/core/promise');
const tabs = require('sdk/tabs');
@ -14,45 +14,31 @@ const tabs = require('sdk/tabs');
// test openDialog() from window/utils with private option
// test isActive state in pwpb case
// test isPrivate on ChromeWindow
exports.testPerWindowPrivateBrowsingGetter = function(assert, done) {
let win = openDialog({
private: true
});
exports.testPerWindowPrivateBrowsingGetter = function*(assert) {
let win = openDialog({ private: true });
promise(win, 'DOMContentLoaded').then(function onload() {
assert.equal(pbUtils.getMode(win),
true, 'Newly opened window is in PB mode');
assert.ok(isPrivate(win), 'isPrivate(window) is true');
assert.equal(pb.isActive, false, 'PB mode is not active');
yield promise(win, 'DOMContentLoaded');
close(win).then(function() {
assert.equal(pb.isActive, false, 'PB mode is not active');
done();
});
});
assert.equal(getMode(win), true, 'Newly opened window is in PB mode');
assert.ok(isPrivate(win), 'isPrivate(window) is true');
yield close(win);
}
// test open() from window/utils with private feature
// test isActive state in pwpb case
// test isPrivate on ChromeWindow
exports.testPerWindowPrivateBrowsingGetter = function(assert, done) {
exports.testPerWindowPrivateBrowsingGetter = function*(assert) {
let win = open('chrome://browser/content/browser.xul', {
features: {
private: true
}
});
promise(win, 'DOMContentLoaded').then(function onload() {
assert.equal(pbUtils.getMode(win),
true, 'Newly opened window is in PB mode');
assert.ok(isPrivate(win), 'isPrivate(window) is true');
assert.equal(pb.isActive, false, 'PB mode is not active');
close(win).then(function() {
assert.equal(pb.isActive, false, 'PB mode is not active');
done();
});
});
yield promise(win, 'DOMContentLoaded');
assert.equal(getMode(win), true, 'Newly opened window is in PB mode');
assert.ok(isPrivate(win), 'isPrivate(window) is true');
yield close(win)
}
exports.testIsPrivateOnWindowOpen = function(assert, done) {

View File

@ -175,4 +175,4 @@ exports['test Enable failure'] = function (assert, done) {
).then(done, assert.fail);
};
require("test").run(exports);
require("sdk/test").run(exports);

View File

@ -0,0 +1,14 @@
/* 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 { id } = require("sdk/self");
const { getAddonByID } = require("sdk/addon/manager");
exports["test getAddonByID"] = function*(assert) {
let addon = yield getAddonByID(id);
assert.equal(addon.id, id, "getAddonByID works");
}
require("sdk/test").run(exports);

View File

@ -391,7 +391,7 @@ exports.testBufferSlice = function (assert) {
assert.equal(buf.slice(0, 65536), '0123456789', 'buffer slice range correct');
assert.equal(buf.slice(65536, 0), '', 'buffer slice range correct');
let sliceTest = true;
sliceTest = true;
for (var i = 0, s = buf.toString(); i < buf.length; ++i) {
if (buf.slice(-i) != s.slice(-i)) sliceTest = false;
if (buf.slice(0, -i) != s.slice(0, -i)) sliceTest = false;
@ -463,7 +463,7 @@ exports.testBufferConcat = function (assert) {
assert.equal(flatZero.length, 0);
assert.equal(flatOne.toString(), 'asdf');
assert.equal(flatOne, one[0]);
assert.ok(flatLong.toString(), (new Array(10+1).join('asdf')));
assert.equal(flatLong.toString(), (new Array(10+1).join('asdf')));
assert.equal(flatLongLen.toString(), (new Array(10+1).join('asdf')));
};

View File

@ -10,6 +10,7 @@ require("sdk/context-menu");
const { Loader } = require('sdk/test/loader');
const timer = require("sdk/timers");
const { merge } = require("sdk/util/object");
const { defer } = require("sdk/core/promise");
// These should match the same constants in the module.
const ITEM_CLASS = "addon-context-menu-item";
@ -2664,6 +2665,58 @@ exports.testItemNoData = function (assert, done) {
}
exports.testItemNoAccessKey = function (assert, done) {
let test = new TestHelper(assert, done);
let loader = test.newLoader();
let item1 = new loader.cm.Item({ label: "item 1" });
let item2 = new loader.cm.Item({ label: "item 2", accesskey: null });
let item3 = new loader.cm.Item({ label: "item 3", accesskey: undefined });
assert.equal(item1.accesskey, undefined, "Should be no defined image");
assert.equal(item2.accesskey, null, "Should be no defined image");
assert.equal(item3.accesskey, undefined, "Should be no defined image");
test.showMenu().
then((popup) => test.checkMenu([item1, item2, item3], [], [])).
then(test.done).
catch(assert.fail);
}
// Test accesskey support.
exports.testItemAccessKey = function (assert, done) {
let test = new TestHelper(assert, done);
let loader = test.newLoader();
let item = new loader.cm.Item({ label: "item", accesskey: "i" });
assert.equal(item.accesskey, "i", "Should have set the image to i");
let menu = new loader.cm.Menu({ label: "menu", accesskey: "m", items: [
loader.cm.Item({ label: "subitem" })
]});
assert.equal(menu.accesskey, "m", "Should have set the accesskey to m");
test.showMenu().then((popup) => {
test.checkMenu([item, menu], [], []);
let accesskey = "e";
menu.accesskey = item.accesskey = accesskey;
assert.equal(item.accesskey, accesskey, "Should have set the accesskey to " + accesskey);
assert.equal(menu.accesskey, accesskey, "Should have set the accesskey to " + accesskey);
test.checkMenu([item, menu], [], []);
item.accesskey = null;
menu.accesskey = null;
assert.equal(item.accesskey, null, "Should have set the accesskey to " + accesskey);
assert.equal(menu.accesskey, null, "Should have set the accesskey to " + accesskey);
test.checkMenu([item, menu], [], []);
}).
then(test.done).
catch(assert.fail);
};
// Tests that items without an image don't attempt to show one
exports.testItemNoImage = function (assert, done) {
let test = new TestHelper(assert, done);
@ -3695,6 +3748,7 @@ function TestHelper(assert, done) {
getMostRecentWindow("navigator:browser");
this.overflowThreshValue = require("sdk/preferences/service").
get(OVERFLOW_THRESH_PREF, OVERFLOW_THRESH_DEFAULT);
this.done = this.done.bind(this);
}
TestHelper.prototype = {
@ -3753,6 +3807,20 @@ TestHelper.prototype = {
if (itemType === "Item" || itemType === "Menu") {
this.assert.equal(elt.getAttribute("label"), item.label,
"Item should have correct title");
// validate accesskey prop
if (item.accesskey) {
this.assert.equal(elt.getAttribute("accesskey"),
item.accesskey,
"Item should have correct accesskey");
}
else {
this.assert.equal(elt.getAttribute("accesskey"),
"",
"Item should not have accesskey");
}
// validate image prop
if (typeof(item.image) === "string") {
this.assert.equal(elt.getAttribute("image"), item.image,
"Item should have correct image");
@ -4034,11 +4102,16 @@ TestHelper.prototype = {
// menu is opened in the top-left corner. onShowncallback is passed the
// popup.
showMenu: function(targetNode, onshownCallback) {
let { promise, resolve } = defer();
function sendEvent() {
this.delayedEventListener(this.browserWindow, "popupshowing",
function (e) {
let popup = e.target;
onshownCallback.call(this, popup);
if (onshownCallback) {
onshownCallback.call(this, popup);
}
resolve(popup);
}, false);
let rect = targetNode ?
@ -4070,6 +4143,8 @@ TestHelper.prototype = {
}
else
sendEvent.call(this);
return promise;
},
hideMenu: function(onhiddenCallback) {

File diff suppressed because one or more lines are too long

View File

@ -254,8 +254,7 @@ exports["test disposables are GC-able"] = function(assert, done) {
let foo1 = Foo(arg1, arg2)
let foo2 = Foo(arg1, arg2)
let foo1 = null
let foo2 = null
foo1 = foo2 = null;
Cu.schedulePreciseGC(function() {
loader.unload();
@ -362,4 +361,4 @@ exports["test multiple destroy"] = function(assert) {
assert.equal(disposals, 3, "unload only disposed the remaining instance");
}
require('test').run(exports);
require('sdk/test').run(exports);

View File

@ -367,11 +367,11 @@ exports['test shared globals'] = function(assert) {
}
exports["test require#resolve"] = function(assert) {
let root = require.resolve("sdk/tabs").replace(/commonjs\.path\/(.*)$/, "") + "commonjs.path/";
assert.ok(/^resource:\/\/extensions\.modules\.[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}-at-jetpack\.commonjs\.path\/$/.test(root), "correct resolution root");
let foundRoot = require.resolve("sdk/tabs").replace(/sdk\/tabs.js$/, "");
assert.ok(root, foundRoot, "correct resolution root");
assert.equal(root + "sdk/tabs.js", require.resolve("sdk/tabs"), "correct resolution of sdk module");
assert.equal(root + "toolkit/loader.js", require.resolve("toolkit/loader"), "correct resolution of sdk module");
assert.equal(foundRoot + "sdk/tabs.js", require.resolve("sdk/tabs"), "correct resolution of sdk module");
assert.equal(foundRoot + "toolkit/loader.js", require.resolve("toolkit/loader"), "correct resolution of sdk module");
};
require('test').run(exports);

View File

@ -30,6 +30,8 @@ exports.testMatchPatternTestTrue = function(assert) {
ok("http://example.com/ice-cream", "http://example.com/ice-cream");
ok(/.*zilla.*/, "https://bugzilla.redhat.com/show_bug.cgi?id=569753");
ok(/.*A.*/i, "http://A.com");
ok(/.*A.*/i, "http://a.com");
ok(/https:.*zilla.*/, "https://bugzilla.redhat.com/show_bug.cgi?id=569753");
ok('*.sample.com', 'http://ex.sample.com/foo.html');
ok('*.amp.le.com', 'http://ex.amp.le.com');
@ -108,12 +110,6 @@ exports.testMatchPatternErrors = function(assert) {
"MatchPattern throws on a RegExp set to `global` (i.e. //g)."
);
assert.throws(
function() new MatchPattern(/ /i),
/^A RegExp match pattern cannot be set to `ignoreCase` \(i\.e\. \/\/i\)\.$/,
"MatchPattern throws on a RegExp set to `ignoreCase` (i.e. //i)."
);
assert.throws(
function() new MatchPattern( / /m ),
/^A RegExp match pattern cannot be set to `multiline` \(i\.e\. \/\/m\)\.$/,

View File

@ -165,8 +165,7 @@ exports["test require#resolve with relative, dependencies"] = function(assert, d
let program = main(loader);
let fixtureRoot = program.require.resolve("./").replace(/native-addon-test\/(.*)/, "") + "native-addon-test/";
assert.ok(/^resource:\/\/[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}-at-jetpack\/addon-sdk\/tests\/fixtures\/native-addon-test\/$/.test(fixtureRoot),
"correct resolution root");
assert.equal(root + "/fixtures/native-addon-test/", fixtureRoot, "correct resolution root");
assert.equal(program.require.resolve("test-math"), fixtureRoot + "node_modules/test-math/index.js", "works with node_modules");
assert.equal(program.require.resolve("./newmodule"), fixtureRoot + "newmodule/lib/file.js", "works with directory mains");
assert.equal(program.require.resolve("./dir/a"), fixtureRoot + "dir/a.js", "works with normal relative module lookups");

View File

@ -16,11 +16,10 @@ const { setTimeout } = require("sdk/timers");
const self = require('sdk/self');
const { open, close, focus, ready } = require('sdk/window/helpers');
const { isPrivate } = require('sdk/private-browsing');
const { isWindowPBSupported, isGlobalPBSupported } = require('sdk/private-browsing/utils');
const { isWindowPBSupported } = require('sdk/private-browsing/utils');
const { defer, all } = require('sdk/core/promise');
const { getMostRecentBrowserWindow } = require('sdk/window/utils');
const { getWindow } = require('sdk/panel/window');
const { pb } = require('./private-browsing/helper');
const { URL } = require('sdk/url');
const { wait } = require('./event/helpers');
@ -1006,7 +1005,7 @@ exports['test panel CSS'] = function(assert, done) {
assert.equal(div.clientHeight, 100,
"Panel contentStyle worked");
assert.equal(div.offsetHeight, 120,
"Panel contentStyleFile worked");
@ -1044,7 +1043,7 @@ exports['test panel contentScriptFile'] = function(assert, done) {
let panel = Panel({
contentURL: './test.html',
contentScriptFile: "./test-contentScriptFile.js",
contentScriptFile: "./test-contentScriptFile.js",
onMessage: (message) => {
assert.equal(message, "msg from contentScriptFile",
"Panel contentScriptFile with relative path worked");
@ -1155,7 +1154,7 @@ exports['test panel contextmenu validation'] = function(assert) {
assert.equal(panel.contextMenu, false,
'contextMenu option accepts boolean values');
assert.throws(() =>
Panel({contextMenu: 1}),
/The option "contextMenu" must be one of the following types: boolean, undefined, null/,
@ -1235,7 +1234,7 @@ exports['test panel contextmenu disabled'] = function*(assert) {
assert.equal(contextmenu.state, 'closed',
'contextmenu must be closed');
sendMouseEvent('contextmenu', 20, 20, 2, 1, 0);
contextmenu.addEventListener('popupshown', listener);
@ -1247,7 +1246,7 @@ exports['test panel contextmenu disabled'] = function*(assert) {
assert.equal(contextmenu.state, 'closed',
'contextmenu was never open');
loader.unload();
loader.unload();
}
exports["test panel addon global object"] = function*(assert) {
@ -1274,7 +1273,7 @@ exports["test panel addon global object"] = function*(assert) {
panel.port.emit('addon-to-document', 'ok');
yield wait(panel.port, "document-to-addon");
assert.pass("Received an event from the document");
loader.unload();
@ -1295,28 +1294,5 @@ if (isWindowPBSupported) {
}).then(close).then(done).then(null, assert.fail);
}
}
else if (isGlobalPBSupported) {
exports.testGetWindow = function(assert, done) {
let activeWindow = getMostRecentBrowserWindow();
assert.equal(getWindow(activeWindow.gBrowser), activeWindow, 'non-private window elements returns window');
pb.once('start', function() {
assert.ok(isPrivate(activeWindow), 'window is private');
assert.equal(getWindow(activeWindow.gBrowser), activeWindow, 'private window elements returns window');
open(null, { features: {
toolbar: true,
chrome: true
} }).then(window => {
assert.ok(isPrivate(window), 'window is private');
assert.equal(getWindow(window.gBrowser), window, 'private window elements returns window');
assert.equal(getWindow(activeWindow.gBrowser), activeWindow, 'active window elements returns window');
pb.once('stop', done);
pb.deactivate();
})
});
pb.activate();
}
}
require("test").run(exports);
require("sdk/test").run(exports);

View File

@ -18,6 +18,7 @@ const ORIGINAL_SDK_LOG_LEVEL = prefs.get(SDK_LOG_LEVEL_PREF);
exports.testPlainTextConsole = function(assert) {
let prints = [];
let tbLines;
function print(message) {
prints.push(message);
}
@ -80,15 +81,15 @@ exports.testPlainTextConsole = function(assert) {
assert.equal(lastPrint(), "console.log: " + name + ": testing {}\n",
"PlainTextConsole.log() must stringify custom bad toString.");
con.exception(new Error("blah"));
assert.equal(prints[0], "console.error: " + name + ": \n");
let tbLines = prints[1].split("\n");
assert.equal(tbLines[0], " Message: Error: blah");
assert.equal(tbLines[1], " Stack:");
assert.ok(prints[1].indexOf(module.uri + ":84") !== -1);
assert.equal(prints[0], "console.error: " + name + ": \n", "prints[0] is correct");
tbLines = prints[1].split("\n");
assert.equal(tbLines[0], " Message: Error: blah", "tbLines[0] is correct");
assert.equal(tbLines[1], " Stack:", "tbLines[1] is correct");
let lineNumber = prints[1].match(module.uri + ":(\\d+)")[1];
assert.equal(lineNumber, "84", "line number is correct")
assert.ok(prints[1].indexOf(module.uri + ":84") !== -1, "line number is correct");
prints = []
try {
@ -98,14 +99,14 @@ exports.testPlainTextConsole = function(assert) {
catch(e) {
con.exception(e);
}
assert.equal(prints[0], "console.error: " + name + ": \n");
assert.equal(prints[1], " Error creating URI (invalid URL scheme?)\n");
assert.equal(prints[0], "console.error: " + name + ": \n", "prints[0] is correct");
assert.equal(prints[1], " Error creating URI (invalid URL scheme?)\n", "prints[1] is correct");
prints = [];
con.trace();
let tbLines = prints[0].split("\n");
assert.equal(tbLines[0], "console.trace: " + name + ": ");
assert.ok(tbLines[1].indexOf("_ain-text-console.js 105") == 0);
tbLines = prints[0].split("\n");
assert.equal(tbLines[0], "console.trace: " + name + ": ", "contains correct console.trace");
assert.ok(tbLines[1].indexOf("_ain-text-console.js 106") == 0);
prints = [];
// Whether or not console methods should print at the various log levels,
@ -167,6 +168,7 @@ exports.testPlainTextConsole = function(assert) {
exports.testPlainTextConsoleBoundMethods = function(assert) {
let prints = [];
let tbLines;
function print(message) {
prints.push(message);
}
@ -207,24 +209,26 @@ exports.testPlainTextConsoleBoundMethods = function(assert) {
debug('testing', 1, [2, 3, 4]);
assert.equal(prints[0], "console.debug: " + name + ": \n",
"PlainTextConsole.debug() must work.");
assert.equal(prints[1], " testing\n")
assert.equal(prints[2], " 1\n")
assert.equal(prints[3], "Array\n - 0 = 2\n - 1 = 3\n - 2 = 4\n - length = 3\n");
assert.equal(prints[1], " testing\n", "prints[1] is correct");
assert.equal(prints[2], " 1\n", "prints[2] is correct");
assert.equal(prints[3],
"Array\n - 0 = 2\n - 1 = 3\n - 2 = 4\n - length = 3\n",
"prints[3] is correct");
prints = [];
exception(new Error("blah"));
assert.equal(prints[0], "console.error: " + name + ": \n");
let tbLines = prints[1].split("\n");
assert.equal(tbLines[0], " Message: Error: blah");
assert.equal(tbLines[1], " Stack:");
assert.ok(prints[1].indexOf(module.uri + ":215") !== -1);
assert.equal(prints[0], "console.error: " + name + ": \n", "prints[0] is correct");
tbLines = prints[1].split("\n");
assert.equal(tbLines[0], " Message: Error: blah", "tbLines[0] is correct");
assert.equal(tbLines[1], " Stack:", "tbLines[1] is correct");
assert.ok(prints[1].indexOf(module.uri + ":219") !== -1, "correct line number");
prints = []
trace();
let tbLines = prints[0].split("\n");
assert.equal(tbLines[0], "console.trace: " + name + ": ");
assert.ok(tbLines[1].indexOf("_ain-text-console.js 224") === 0);
tbLines = prints[0].split("\n");
assert.equal(tbLines[0], "console.trace: " + name + ": ", "console.trace is correct");
assert.ok(tbLines[1].indexOf("_ain-text-console.js 228") === 0, "correct line number");
prints = [];
restorePrefs();
@ -271,4 +275,4 @@ function restorePrefs() {
prefs.reset(SDK_LOG_LEVEL_PREF);
}
require("test").run(exports);
require("sdk/test").run(exports);

View File

@ -13,26 +13,15 @@ const { isPrivateBrowsingSupported } = require('sdk/self');
const { is } = require('sdk/system/xul-app');
const { isPrivate } = require('sdk/private-browsing');
const { LoaderWithHookedConsole } = require("sdk/test/loader");
const { getMode, isGlobalPBSupported,
isWindowPBSupported, isTabPBSupported } = require('sdk/private-browsing/utils');
const { getMode, isWindowPBSupported, isTabPBSupported } = require('sdk/private-browsing/utils');
const { pb } = require('./private-browsing/helper');
const prefs = require('sdk/preferences/service');
const { set: setPref } = require("sdk/preferences/service");
const DEPRECATE_PREF = "devtools.errorconsole.deprecation_warnings";
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
const kAutoStartPref = "browser.privatebrowsing.autostart";
// is global pb is enabled?
if (isGlobalPBSupported) {
safeMerge(module.exports, require('./private-browsing/global'));
exports.testGlobalOnlyOnFirefox = function(assert) {
assert.ok(is("Firefox"), "isGlobalPBSupported is only true on Firefox");
}
}
else if (isWindowPBSupported) {
if (isWindowPBSupported) {
safeMerge(module.exports, require('./private-browsing/windows'));
exports.testPWOnlyOnFirefox = function(assert) {
@ -58,26 +47,19 @@ exports.testIsPrivateDefaults = function(assert) {
};
exports.testWindowDefaults = function(assert) {
setPref(DEPRECATE_PREF, true);
// Ensure that browserWindow still works while being deprecated
let { loader, messages } = LoaderWithHookedConsole(module);
let windows = loader.require("sdk/windows").browserWindows;
assert.equal(windows.activeWindow.isPrivateBrowsing, false,
'window is not private browsing by default');
assert.ok(/DEPRECATED.+isPrivateBrowsing/.test(messages[0].msg),
'isPrivateBrowsing is deprecated');
assert.equal(windows.activeWindow.isPrivateBrowsing, undefined,
'window.isPrivateBrowsing is undefined');
assert.equal(undefined, messages[0],
'isPrivateBrowsing is deprecated');
let chromeWin = winUtils.getMostRecentBrowserWindow();
assert.equal(getMode(chromeWin), false);
assert.equal(isWindowPrivate(chromeWin), false);
};
// tests for the case where private browsing doesn't exist
exports.testIsActiveDefault = function(assert) {
assert.equal(pb.isActive, false,
'pb.isActive returns false when private browsing isn\'t supported');
};
exports.testIsPrivateBrowsingFalseDefault = function(assert) {
assert.equal(isPrivateBrowsingSupported, false,
'isPrivateBrowsingSupported property is false by default');

View File

@ -3,14 +3,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { Cc, Ci, Cu, Cm, components } = require("chrome");
const xulApp = require("sdk/system/xul-app");
const self = require("sdk/self");
const { Loader, main, unload } = require("toolkit/loader");
const loaderOptions = require("@loader/options");
const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {});
exports.testSelf = function(assert) {
// Likewise, we can't assert anything about the full URL, because that
// depends on self.id . We can only assert that it ends in the right

View File

@ -17,7 +17,7 @@ const file = require("sdk/io/file");
const { install, uninstall } = require("sdk/addon/installer");
const { open } = require('sdk/preferences/utils');
const { toFilename } = require('sdk/url');
const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {});
const { getAddonByID } = require('sdk/addon/manager');
const { ZipWriter } = require('./zip/utils');
const { getTabForId } = require('sdk/tabs/utils');
const { preferencesBranch, id } = require('sdk/self');
@ -44,7 +44,7 @@ exports.testIterations = function(assert) {
delete sp["test"];
delete sp["test.test"];
let prefAry = [];
prefAry = [];
for (var name in sp ) {
prefAry.push(name);
}
@ -247,7 +247,7 @@ exports.testPrefJSONStringification = function(assert) {
"JSON stringification should work.");
};
exports.testUnloadOfDynamicPrefGeneration = function(assert, done) {
exports.testUnloadOfDynamicPrefGeneration = function*(assert) {
let loader = Loader(module);
let branch = prefsrv.getDefaultBranch('extensions.' + preferencesBranch);
@ -259,92 +259,74 @@ exports.testUnloadOfDynamicPrefGeneration = function(assert, done) {
// zip the add-on
let zip = new ZipWriter(xpi_path);
assert.pass("start creating the xpi");
zip.addFile("", toFilename(fixtures.url("bootstrap-addon/"))).
then(zip.close()).
then(_ => install(xpi_path)).
// get the addon
then(id => {
let { promise, resolve } = defer();
AddonManager.getAddonByID(id, resolve);
return promise;
}).
zip.addFile("", toFilename(fixtures.url("bootstrap-addon/")));
yield zip.close();
// insatll the add-on
then(addon => {
assert.pass('installed');
let id = yield install(xpi_path);
assert.pass('addon id: ' + addon.id);
addon.userDisabled = false;
assert.ok(!addon.userDisabled, 'the add-on is enabled');
assert.ok(addon.isActive, 'the add-on is enabled');
// get the addon
let addon = yield getAddonByID(id);
assert.pass('installed');
assert.pass('addon id: ' + addon.id);
addon.userDisabled = false;
assert.ok(!addon.userDisabled, 'the add-on is enabled');
assert.ok(addon.isActive, 'the add-on is enabled');
// setup dynamic prefs
yield enable({
id: addon.id,
preferences: [{
"name": "test",
"description": "test",
"title": "Test",
"type": "string",
"value": "default"
}, {
"name": "test-int",
"description": "test",
"type": "integer",
"value": 5,
"title": "How Many?"
}]
});
assert.pass('enabled');
// setup dynamic prefs
return enable({
id: addon.id,
preferences: [{
"name": "test",
"description": "test",
"title": "Test",
"type": "string",
"value": "default"
}, {
"name": "test-int",
"description": "test",
"type": "integer",
"value": 5,
"title": "How Many?"
}]
});
}).
then(args => {
assert.pass('enabled');
return args;
}).
// show inline prefs
then(open).
then(args => {
assert.pass('opened');
return args;
}).
let { tabId, document } = yield open(addon);
assert.pass('opened');
// confirm dynamic pref generation did occur
then(args => {
let results = args.document.querySelectorAll("*[data-jetpack-id=\"" +args.id + "\"]");
assert.ok(results.length > 0, "the prefs were setup");
return args;
}).
let results = document.querySelectorAll("*[data-jetpack-id=\"" + id + "\"]");
assert.ok(results.length > 0, "the prefs were setup");
// unload dynamic prefs
then(args => {
loader.unload();
assert.pass('unload');
return args;
}).
loader.unload();
assert.pass('unload');
// hide and show the inline prefs
then(({ tabId, id, document }) => {
let { promise, resolve } = defer();
let tab = Tab({ tab: getTabForId(tabId) });
let { promise, resolve } = defer();
Tab({ tab: getTabForId(tabId) }).close(resolve);
yield promise;
tab.close(_ => resolve({ id: id }));
return promise;
}).
// reopen the add-on prefs page
then(open).
({ tabId, document }) = yield open(addon);
// confirm dynamic pref generation did not occur
then(({ id, tabId, document }) => {
let { promise, resolve } = defer();
let tab = Tab({ tab: getTabForId(tabId) });
({ promise, resolve }) = defer();
results = document.querySelectorAll("*[data-jetpack-id=\"" + id + "\"]");
assert.equal(0, results.length, "the prefs were not setup after unload");
Tab({ tab: getTabForId(tabId) }).close(resolve);
yield promise;
let results = document.querySelectorAll("*[data-jetpack-id=\"" + id + "\"]");
assert.equal(0, results.length, "the prefs were not setup after unload");
tab.close(_ => resolve({ id: id }));
return promise;
}).
// uninstall the add-on
then(({ id }) => uninstall(id)).
yield uninstall(id);
// delete the pref branch
then(_ => branch.deleteBranch('')).
then(done, assert.fail);
branch.deleteBranch('');
}
require("sdk/test").run(exports);

View File

@ -1,10 +1,9 @@
'use strict';
const { getTabs } = require('sdk/tabs/utils');
const { isGlobalPBSupported, isWindowPBSupported, isTabPBSupported } = require('sdk/private-browsing/utils');
const { isWindowPBSupported, isTabPBSupported } = require('sdk/private-browsing/utils');
const { browserWindows } = require('sdk/windows');
const tabs = require('sdk/tabs');
const { pb } = require('./private-browsing/helper');
const { isPrivate } = require('sdk/private-browsing');
const { openTab, closeTab, getTabContentWindow, getOwnerWindow } = require('sdk/tabs/utils');
const { open, close } = require('sdk/window/helpers');
@ -64,4 +63,4 @@ else if (isTabPBSupported) {
};
}
require('test').run(exports);
require('sdk/test').run(exports);

View File

@ -18,6 +18,7 @@ const { Style } = require('sdk/stylesheet/style');
const fixtures = require('./fixtures');
const { viewFor } = require('sdk/view/core');
const app = require("sdk/system/xul-app");
const { cleanUI } = require('sdk/test/utils');
const URL = 'data:text/html;charset=utf-8,<html><head><title>#title#</title></head></html>';

View File

@ -5,7 +5,8 @@
'use strict'
const { setTimeout } = require('sdk/timers');
const { waitUntil } = require('sdk/test/utils');
const { waitUntil, cleanUI } = require('sdk/test/utils');
const tabs = require('sdk/tabs');
exports.testWaitUntil = function (assert, done) {
let bool = false;
@ -43,4 +44,29 @@ exports.testWaitUntilInterval = function (assert, done) {
setTimeout(() => { bool = true; }, 10);
};
exports.testCleanUIWithExtraTabAndWindow = function(assert, done) {
tabs.open({
url: "about:blank",
inNewWindow: true,
onOpen: () => {
cleanUI().then(() => {
assert.pass("the ui was cleaned");
assert.equal(tabs.length, 1, 'there is only one tab open');
}).then(done).catch(assert.fail);
}
});
}
exports.testCleanUIWithOnlyExtraTab = function(assert, done) {
tabs.open({
url: "about:blank",
onOpen: () => {
cleanUI().then(() => {
assert.pass("the ui was cleaned");
assert.equal(tabs.length, 1, 'there is only one tab open');
}).then(done).catch(assert.fail);
}
});
}
require('sdk/test').run(exports);

View File

@ -383,6 +383,9 @@ exports['test button window state'] = function(assert, done) {
let nodes = [getWidget(button.id).node];
openBrowserWindow().then(focus).then(window => {
let node;
let state;
nodes.push(getWidget(button.id, window).node);
let { activeWindow } = browserWindows;
@ -402,7 +405,7 @@ exports['test button window state'] = function(assert, done) {
assert.equal(button.disabled, false,
'global disabled unchanged');
let state = button.state(mainWindow);
state = button.state(mainWindow);
assert.equal(state.label, 'my button',
'previous window label unchanged');
@ -411,7 +414,7 @@ exports['test button window state'] = function(assert, done) {
assert.equal(state.disabled, false,
'previous window disabled unchanged');
let state = button.state(activeWindow);
state = button.state(activeWindow);
assert.equal(state.label, 'New label',
'active window label updated');
@ -439,8 +442,8 @@ exports['test button window state'] = function(assert, done) {
'active window label inherited');
// check the nodes properties
let node = nodes[0];
let state = button.state(mainWindow);
node = nodes[0];
state = button.state(mainWindow);
assert.equal(node.getAttribute('label'), state.label,
'node label is correct');
@ -452,8 +455,8 @@ exports['test button window state'] = function(assert, done) {
assert.equal(node.hasAttribute('disabled'), state.disabled,
'disabled is correct');
let node = nodes[1];
let state = button.state(activeWindow);
node = nodes[1];
state = button.state(activeWindow);
assert.equal(node.getAttribute('label'), state.label,
'node label is correct');
@ -515,6 +518,8 @@ exports['test button tab state'] = function(assert, done) {
// check the states
Cu.schedulePreciseGC(() => {
let state;
assert.equal(button.label, 'my button',
'global label unchanged');
assert.equal(button.icon, './icon.png',
@ -522,7 +527,7 @@ exports['test button tab state'] = function(assert, done) {
assert.equal(button.disabled, false,
'global disabled unchanged');
let state = button.state(mainTab);
state = button.state(mainTab);
assert.equal(state.label, 'Tab label',
'previous tab label updated');
@ -531,7 +536,7 @@ exports['test button tab state'] = function(assert, done) {
assert.equal(state.disabled, false,
'previous tab disabled unchanged');
let state = button.state(tab);
state = button.state(tab);
assert.equal(state.label, 'Window label',
'active tab inherited from window state');
@ -561,7 +566,7 @@ exports['test button tab state'] = function(assert, done) {
// check the node properties
let state = button.state(tabs.activeTab);
state = button.state(tabs.activeTab);
assert.equal(node.getAttribute('label'), state.label,
'node label is correct');
@ -601,7 +606,7 @@ exports['test button tab state'] = function(assert, done) {
};
exports['test button click'] = function(assert, done) {
exports['test button click'] = function*(assert) {
let loader = Loader(module);
let { ActionButton } = loader.require('sdk/ui');
let { browserWindows } = loader.require('sdk/windows');
@ -618,28 +623,28 @@ exports['test button click'] = function(assert, done) {
let mainWindow = browserWindows.activeWindow;
let chromeWindow = getMostRecentBrowserWindow();
openBrowserWindow().then(focus).then(window => {
button.state(mainWindow, { label: 'nothing' });
button.state(mainWindow.tabs.activeTab, { label: 'foo'})
button.state(browserWindows.activeWindow, { label: 'bar' });
let window = yield openBrowserWindow().then(focus);
button.click();
button.state(mainWindow, { label: 'nothing' });
button.state(mainWindow.tabs.activeTab, { label: 'foo'})
button.state(browserWindows.activeWindow, { label: 'bar' });
focus(chromeWindow).then(() => {
button.click();
button.click();
assert.deepEqual(labels, ['bar', 'foo'],
'button click works');
yield focus(chromeWindow);
close(window).
then(loader.unload).
then(done, assert.fail);
});
}).then(null, assert.fail);
button.click();
assert.deepEqual(labels, ['bar', 'foo'],
'button click works');
yield close(window);
loader.unload();
}
exports['test button icon set'] = function(assert) {
let size;
const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
let loader = Loader(module);
let { ActionButton } = loader.require('sdk/ui');
@ -670,12 +675,12 @@ exports['test button icon set'] = function(assert) {
let { node, id: widgetId } = getWidget(button.id);
let { devicePixelRatio } = node.ownerDocument.defaultView;
let size = 16 * devicePixelRatio;
size = 16 * devicePixelRatio;
assert.equal(node.getAttribute('image'), data.url(button.icon[size].substr(2)),
'the icon is set properly in navbar');
let size = 32 * devicePixelRatio;
size = 32 * devicePixelRatio;
CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_PANEL);

View File

@ -201,6 +201,7 @@ exports["test content to host messaging"] = function* (assert) {
exports["test direct messaging"] = function* (assert) {
let message;
const url = "data:text/html,<script>new " + function() {
var n = 0;
window.addEventListener("message", (event) => {
@ -231,13 +232,13 @@ exports["test direct messaging"] = function* (assert) {
assert.deepEqual(e1.data, {n: 1}, "received message from window#1");
assert.deepEqual(e2.data, {n: 1}, "received message from window#2");
let message = wait(f1, "message");
message = wait(f1, "message");
e1.source.postMessage("inc", e1.origin);
e1.source.postMessage("print", e1.origin);
const e3 = yield message;
assert.deepEqual(e3.data, {n: 2}, "state changed in window#1");
let message = wait(f1, "message");
message = wait(f1, "message");
e2.source.postMessage("print", e2.origin);
yield message;
assert.deepEqual(e2.data, {n:1}, "window#2 didn't received inc message");
@ -246,7 +247,6 @@ exports["test direct messaging"] = function* (assert) {
t1.destroy();
yield wait(t1, "detach");
};
require("sdk/test").run(exports);

View File

@ -299,6 +299,7 @@ exports['test button global state updated'] = function(assert) {
}
exports['test button global state set and get with state method'] = function(assert) {
let state;
let loader = Loader(module);
let { ToggleButton } = loader.require('sdk/ui');
@ -309,7 +310,7 @@ exports['test button global state set and get with state method'] = function(ass
});
// read the button's state
let state = button.state(button);
state = button.state(button);
assert.equal(state.label, 'my button',
'label is correct');
@ -379,6 +380,7 @@ exports['test button global state updated on multiple windows'] = function(asser
};
exports['test button window state'] = function(assert, done) {
let state;
let loader = Loader(module);
let { ToggleButton } = loader.require('sdk/ui');
let { browserWindows } = loader.require('sdk/windows');
@ -412,7 +414,7 @@ exports['test button window state'] = function(assert, done) {
assert.equal(button.disabled, false,
'global disabled unchanged');
let state = button.state(mainWindow);
state = button.state(mainWindow);
assert.equal(state.label, 'my button',
'previous window label unchanged');
@ -421,7 +423,7 @@ exports['test button window state'] = function(assert, done) {
assert.equal(state.disabled, false,
'previous window disabled unchanged');
let state = button.state(activeWindow);
state = button.state(activeWindow);
assert.equal(state.label, 'New label',
'active window label updated');
@ -450,7 +452,7 @@ exports['test button window state'] = function(assert, done) {
// check the nodes properties
let node = nodes[0];
let state = button.state(mainWindow);
state = button.state(mainWindow);
assert.equal(node.getAttribute('label'), state.label,
'node label is correct');
@ -462,8 +464,8 @@ exports['test button window state'] = function(assert, done) {
assert.equal(node.hasAttribute('disabled'), state.disabled,
'disabled is correct');
let node = nodes[1];
let state = button.state(activeWindow);
node = nodes[1];
state = button.state(activeWindow);
assert.equal(node.getAttribute('label'), state.label,
'node label is correct');
@ -525,6 +527,8 @@ exports['test button tab state'] = function(assert, done) {
// check the states
Cu.schedulePreciseGC(() => {
let state;
assert.equal(button.label, 'my button',
'global label unchanged');
assert.equal(button.icon, './icon.png',
@ -532,7 +536,7 @@ exports['test button tab state'] = function(assert, done) {
assert.equal(button.disabled, false,
'global disabled unchanged');
let state = button.state(mainTab);
state = button.state(mainTab);
assert.equal(state.label, 'Tab label',
'previous tab label updated');
@ -541,7 +545,7 @@ exports['test button tab state'] = function(assert, done) {
assert.equal(state.disabled, false,
'previous tab disabled unchanged');
let state = button.state(tab);
state = button.state(tab);
assert.equal(state.label, 'Window label',
'active tab inherited from window state');
@ -571,7 +575,7 @@ exports['test button tab state'] = function(assert, done) {
// check the node properties
let state = button.state(tabs.activeTab);
state = button.state(tabs.activeTab);
assert.equal(node.getAttribute('label'), state.label,
'node label is correct');
@ -684,7 +688,7 @@ exports['test button icon set'] = function(assert) {
assert.equal(node.getAttribute('image'), data.url(button.icon[size].substr(2)),
'the icon is set properly in navbar');
let size = 32 * devicePixelRatio;
size = 32 * devicePixelRatio;
CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_PANEL);

View File

@ -25,11 +25,11 @@ exports["test makeFilters no method filter"] = (assert) => {
testFiles.forEach(f => assert.ok(fileFilter(f), "using filter 'i' on filename " + f + " works"));
testMethods.forEach(m => assert.ok(testFilter(m), "using filter 'i' on method name " + m + " works"));
let { fileFilter, testFilter } = makeFilters({ filter: "i:" });
({ fileFilter, testFilter }) = makeFilters({ filter: "i:" });
testFiles.forEach(f => assert.ok(fileFilter(f), "using filter 'i:' on filename " + f + " works"));
testMethods.forEach(m => assert.ok(testFilter(m), "using filter 'i:' on method name " + m + " works"));
let { fileFilter, testFilter } = makeFilters({ filter: "z:" });
({ fileFilter, testFilter }) = makeFilters({ filter: "z:" });
testFiles.forEach(f => assert.ok(!fileFilter(f), "using filter 'z:' on filename " + f + " dnw"));
testMethods.forEach(m => assert.ok(testFilter(m), "using filter 'z:' on method name " + m + " works"));
}
@ -39,7 +39,7 @@ exports["test makeFilters no file filter"] = (assert) => {
testFiles.forEach(f => assert.ok(fileFilter(f), "using filter ':i' on filename " + f + " works"));
testMethods.forEach(m => assert.ok(testFilter(m), "using filter ':i' on method name " + m + " works"));
let { fileFilter, testFilter } = makeFilters({ filter: ":z" });
({ fileFilter, testFilter }) = makeFilters({ filter: ":z" });
testFiles.forEach(f => assert.ok(fileFilter(f), "using filter ':z' on filename " + f + " works"));
testMethods.forEach(m => assert.ok(!testFilter(m), "using filter ':z' on method name " + m + " dnw"));
}
@ -49,7 +49,7 @@ exports["test makeFilters both filters"] = (assert) => {
testFiles.forEach(f => assert.ok(fileFilter(f), "using filter 'i:i' on filename " + f + " works"));
testMethods.forEach(m => assert.ok(testFilter(m), "using filter 'i:i' on method name " + m + " works"));
let { fileFilter, testFilter } = makeFilters({ filter: "z:z" });
({ fileFilter, testFilter }) = makeFilters({ filter: "z:z" });
testFiles.forEach(f => assert.ok(!fileFilter(f), "using filter 'z:z' on filename " + f + " dnw"));
testMethods.forEach(m => assert.ok(!testFilter(m), "using filter 'z:z' on method name " + m + " dnw"));
}

View File

@ -92,8 +92,8 @@ exports.testConstructor = function(assert, done) {
// Test automatic widget destroy on unload
let { loader } = LoaderWithHookedConsole(module);
let widgetsFromLoader = loader.require("sdk/widget");
let widgetStartCount = widgetCount();
let w = widgetsFromLoader.Widget({ id: "destroy-on-unload", label: "foo", content: "bar" });
widgetStartCount = widgetCount();
w = widgetsFromLoader.Widget({ id: "destroy-on-unload", label: "foo", content: "bar" });
assert.equal(widgetCount(), widgetStartCount + 1, "widget has been correctly added");
loader.unload();
assert.equal(widgetCount(), widgetStartCount, "widget has been destroyed on module unload");
@ -162,8 +162,8 @@ exports.testConstructor = function(assert, done) {
// Test position restore on create/destroy/create
// Create 3 ordered widgets
let w1 = widgets.Widget({id: "position-first", label:"first", content: "bar"});
let w2 = widgets.Widget({id: "position-second", label:"second", content: "bar"});
w1 = widgets.Widget({id: "position-first", label:"first", content: "bar"});
w2 = widgets.Widget({id: "position-second", label:"second", content: "bar"});
let w3 = widgets.Widget({id: "position-third", label:"third", content: "bar"});
// Remove the middle widget
assert.equal(widgetNode(1).getAttribute("label"), "second", "second widget is the second widget inserted");

View File

@ -1,152 +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 windowUtils = require('sdk/deprecated/window-utils');
const { isWindowPBSupported, isGlobalPBSupported } = require('sdk/private-browsing/utils');
const { getFrames, getWindowTitle, onFocus, isWindowPrivate, windows, isBrowser } = require('sdk/window/utils');
const { open, close, focus } = require('sdk/window/helpers');
const { isPrivate } = require('sdk/private-browsing');
const { pb } = require('./private-browsing/helper');
const { fromIterator: toArray } = require('sdk/util/array');
function makeEmptyBrowserWindow(options) {
options = options || {};
return open('chrome://browser/content/browser.xul', {
features: {
chrome: true,
private: !!options.private,
toolbar: true
}
});
}
exports.testShowPanelAndWidgetOnPrivateWindow = function(assert, done) {
var myPrivateWindow;
var finished = false;
var privateWindow;
var privateWindowClosed = false;
var { Panel } = require('sdk/panel');
var { Widget } = require('sdk/widget');
pb.once('start', function() {
assert.pass('private browsing mode started');
// make a new private window
makeEmptyBrowserWindow().then(function(window) {
myPrivateWindow = window;
let wt = windowUtils.WindowTracker({
onTrack: function(window) {
if (!isBrowser(window) || window !== myPrivateWindow) return;
assert.ok(isWindowPrivate(window), 'window is private onTrack!');
let panel = Panel({
onShow: function() {
assert.ok(this.isShowing, 'the panel is showing on the private window');
let count = 0;
let widget = Widget({
id: "testShowPanelAndWidgetOnPrivateWindow-id",
label: "My Hello Widget",
content: "Hello!",
onAttach: function(mod) {
count++;
if (count == 2) {
panel.destroy();
widget.destroy();
close(window);
}
}
});
}
}).show(null, window.gBrowser);
},
onUntrack: function(window) {
if (window === myPrivateWindow) {
wt.unload();
pb.once('stop', function() {
assert.pass('private browsing mode end');
done();
});
pb.deactivate();
}
}
});
assert.equal(isWindowPrivate(window), true, 'the opened window is private');
assert.equal(isPrivate(window), true, 'the opened window is private');
assert.ok(getFrames(window).length > 1, 'there are frames for private window');
assert.equal(getWindowTitle(window), window.document.title,
'getWindowTitle works');
});
});
pb.activate();
};
exports.testWindowTrackerDoesNotIgnorePrivateWindows = function(assert, done) {
var myPrivateWindow;
var count = 0;
let wt = windowUtils.WindowTracker({
onTrack: function(window) {
if (!isBrowser(window) || !isWindowPrivate(window)) return;
assert.ok(isWindowPrivate(window), 'window is private onTrack!');
if (++count == 1)
close(window);
},
onUntrack: function(window) {
if (count == 1 && isWindowPrivate(window)) {
wt.unload();
pb.once('stop', function() {
assert.pass('private browsing mode end');
done();
});
pb.deactivate();
}
}
});
pb.once('start', function() {
assert.pass('private browsing mode started');
makeEmptyBrowserWindow();
});
pb.activate();
}
exports.testWindowIteratorDoesNotIgnorePrivateWindows = function(assert, done) {
pb.once('start', function() {
// make a new private window
makeEmptyBrowserWindow().then(function(window) {
assert.ok(isWindowPrivate(window), "window is private");
assert.equal(isPrivate(window), true, 'the opened window is private');
assert.ok(toArray(windowUtils.windowIterator()).indexOf(window) > -1,
"window is in windowIterator()");
assert.ok(windows(null, { includePrivate: true }).indexOf(window) > -1,
"window is in windows()");
close(window).then(function() {
pb.once('stop', function() {
done();
});
pb.deactivate();
});
});
});
pb.activate();
};
if (!isGlobalPBSupported) {
module.exports = {
"test Unsupported Test": function UnsupportedTest (assert) {
assert.pass(
"Skipping global private browsing tests");
}
}
}
require("test").run(exports);