Bug 849009 - Uplift Add-on SDK changeset 645b0ca71ccd41bb1fc69d97d22c456b03452e89

This commit is contained in:
Wes Kocher 2013-03-07 15:09:34 -08:00
parent e15cbdb2ca
commit fb22710bae
75 changed files with 1154 additions and 687 deletions

View File

@ -151,6 +151,11 @@ function startup(data, reasonCode) {
if (path) path += '/';
let fileURI = branch.getCharPref(name);
// On mobile, file URI has to end with a `/` otherwise, setSubstitution
// takes the parent folder instead.
if (fileURI[fileURI.length-1] !== '/')
fileURI += '/';
// Maps the given file:// URI to a resource:// in order to avoid various
// failure that happens with file:// URI and be close to production env
let resourcesURI = ioService.newURI(fileURI, null, null);

0
addon-sdk/source/bin/cfx Normal file → Executable file
View File

View File

View File

@ -1,9 +1,11 @@
var count = 0
var count = 0;
setTimeout(function() {
window.addEventListener("message", function(msg) {
if (++count > 1) self.postMessage(msg.data);
if (++count > 1) {
self.postMessage(msg.data);
}
else msg.source.postMessage(msg.data, '*');
});

View File

@ -6,6 +6,8 @@
We'd like to thank our many Jetpack project contributors! They include:
### A ###
* Adamantium
* Ehsan Akhgari
* arky
@ -14,6 +16,8 @@ We'd like to thank our many Jetpack project contributors! They include:
<!--end-->
### B ###
* [Romain B](https://github.com/Niamor)
* [Louis-Rémi Babé](https://github.com/louisremi)
* Will Bamberg
@ -25,6 +29,8 @@ We'd like to thank our many Jetpack project contributors! They include:
<!--end-->
### C ###
* [Shane Caraveo](https://github.com/mixedpuppy)
* [Matěj Cepl](https://github.com/mcepl)
* Marc Chevrier
@ -33,6 +39,8 @@ We'd like to thank our many Jetpack project contributors! They include:
<!--end-->
### D ###
* dexter
* Christopher Dorn
* Connor Dunn
@ -40,11 +48,15 @@ We'd like to thank our many Jetpack project contributors! They include:
<!--end-->
### F ###
* [Matteo Ferretti (ZER0)](https://github.com/ZER0)
* fuzzykiller
<!--end-->
### G ###
* [Marcio Galli](https://github.com/taboca)
* [Ben Gillbanks](http://www.iconfinder.com/browse/iconset/circular_icons/)
* Felipe Gomes
@ -55,6 +67,8 @@ We'd like to thank our many Jetpack project contributors! They include:
<!--end-->
### H ###
* Mark Hammond
* Mark A. Hershberger
* Lloyd Hilaiel
@ -62,25 +76,36 @@ We'd like to thank our many Jetpack project contributors! They include:
<!--end-->
### I ###
* Shun Ikejima
<!--end-->
### J ###
* Eric H. Jung
<!--end-->
### K ###
* Hrishikesh Kale
* Wes Kocher
* Lajos Koszti
* [Vladimir Kukushkin](https://github.com/kukushechkin)
<!--end-->
### L ###
* Edward Lee
* Gregg Lind
<!--end-->
### M ###
* [Nils Maier](https://github.com/nmaier)
* Gervase Markham
* Dave Mason
@ -90,6 +115,8 @@ We'd like to thank our many Jetpack project contributors! They include:
<!--end-->
### N ###
* Siavash Askari Nasr
* Joe R. Nassimian ([placidrage](https://github.com/placidrage))
* Dương H. Nguyễn
@ -97,22 +124,31 @@ We'd like to thank our many Jetpack project contributors! They include:
<!--end-->
### O ###
* [ongaeshi](https://github.com/ongaeshi)
* Paul OShannessy
* Les Orchard
<!--end-->
### P ###
* Robert Pankowecki
* Alexandre Poirot
* [Jamie Phelps](https://github.com/ongaeshi)
* [Alexandre Poirot](https://github.com/ochameau)
* Nickolay Ponomarev
<!--end-->
### R ###
* Aza Raskin
<!--end-->
### S ###
* Till Schneidereit
* Justin Scott
* Ayan Shah
@ -125,6 +161,8 @@ We'd like to thank our many Jetpack project contributors! They include:
<!--end-->
### T ###
* taku0
* Clint Talbert
* Tim Taubert
@ -134,6 +172,8 @@ We'd like to thank our many Jetpack project contributors! They include:
<!--end-->
### V ###
* Peter Van der Beken
* Sander van Veen
* Atul Varma
@ -142,6 +182,8 @@ We'd like to thank our many Jetpack project contributors! They include:
<!--end-->
### W ###
* Brian Warner
* [Henri Wiechers](https://github.com/hwiechers)
* Drew Willcoxon
@ -150,5 +192,7 @@ We'd like to thank our many Jetpack project contributors! They include:
<!--end-->
### Z ###
* Piotr Zalewa
* Brett Zamir

View File

@ -242,6 +242,7 @@ Finally, the "text-entry.html" file defines the `<textarea>` element:
&lt;html&gt;
&lt;head&gt;
&lt;meta charset="utf-8"&gt;
&lt;style type="text/css" media="all"&gt;
textarea {
margin: 10px;

View File

@ -10,6 +10,9 @@
The `preferences/service` module provides access to the
application-wide preferences service singleton.
To define preferences for your own add-on and expose them to the user in
the [Add-on Manager](https://developer.mozilla.org/en-US/docs/Addons/Add-on_Manager),
you can use the [simple-prefs](modules/sdk/simple-prefs.html) module.
<api name="set">
@function

View File

@ -181,7 +181,7 @@ if the document cannot be processed by `JSON.parse`.
</api>
<api name="status">
@property {string}
@property {integer}
The HTTP response status code (e.g. *200*).
</api>

View File

@ -355,3 +355,17 @@ for more details.
The listener function that processes the event.
</api>
## Using the Preferences Service to Access Simple Prefs ##
If you ever need to access your simple-prefs with the `preferences/service` module,
you can do so using the extended preference name. To get this
just prepend `"extensions." + require("sdk/self").id + "."` to the preference name `"somePreference"`.
For example, if you had a simple-pref named `"somePreference"` then you could
get its value like so:
require('sdk/preferences/service').get(['extensions', require('sdk/self').id, 'somePreference'].join('.'))
This would give you the same value as:
require('sdk/simple-prefs').prefs['somePreference']

View File

@ -182,6 +182,13 @@ tabs in this window, not all tabs in all windows. This property is read-only.
<api name="isPrivateBrowsing">
@property {boolean}
Returns `true` if the window is in private browsing mode, and `false` otherwise.
<div class="warning">
This property is deprecated.
From version 1.14, please consider using following code instead:<br/>
<code>require("private-browsing").isPrivate(browserWindow)</code>
</div>
</api>
<api name="activate">

0
addon-sdk/source/examples/library-detector/README.md Normal file → Executable file
View File

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 386 B

After

Width:  |  Height:  |  Size: 386 B

View File

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

View File

0
addon-sdk/source/examples/library-detector/lib/main.js Normal file → Executable file
View File

View File

View File

@ -1,5 +1,5 @@
/* vim:set ts=2 sw=2 sts=2 expandtab */
/*jshint asi: true undef: true es5: true node: true browser: true devel: true
/*jshint undef: true es5: true node: true browser: true devel: true
forin: true latedef: false */
/*global define: true, Cu: true, __URI__: true */
;(function(id, factory) { // Module boilerplate :(
@ -7,8 +7,15 @@
define(factory);
} else if (typeof(require) === 'function') { // CommonJS
factory.call(this, require, exports, module);
} else if (~String(this).indexOf('BackstagePass')) { // JSM
} else if (String(this).indexOf('BackstagePass') >= 0) { // JSM
this[factory.name] = {};
try {
this.console = this['Components'].utils
.import('resource://gre/modules/devtools/Console.jsm', {}).console;
}
catch (ex) {
// Avoid failures on different toolkit configurations.
}
factory(function require(uri) {
var imports = {};
this['Components'].utils.import(uri, imports);
@ -16,12 +23,12 @@
}, this[factory.name], { uri: __URI__, id: id });
this.EXPORTED_SYMBOLS = [factory.name];
} else { // Browser or alike
var globals = this
var globals = this;
factory(function require(id) {
return globals[id];
}, (globals[id] = {}), { uri: document.location.href + '#' + id, id: id });
}
}).call(this, 'loader', function Promise(require, exports, module) {
}).call(this, 'promise/core', function Promise(require, exports, module) {
'use strict';
@ -29,157 +36,211 @@ module.metadata = {
"stability": "unstable"
};
function resolution(value) {
/**
Returns non-standard compliant (`then` does not returns a promise) promise
that resolves to a given `value`. Used just internally only.
**/
return { then: function then(resolve) { resolve(value) } }
/**
* Internal utility: Wraps given `value` into simplified promise, successfully
* fulfilled to a given `value`. Note the result is not a complete promise
* implementation, as its method `then` does not returns anything.
*/
function fulfilled(value) {
return { then: function then(fulfill) { fulfill(value); } };
}
function rejection(reason) {
/**
Returns non-standard compliant promise (`then` does not returns a promise)
that rejects with a given `reason`. This is used internally only.
**/
return { then: function then(resolve, reject) { reject(reason) } }
/**
* Internal utility: Wraps given input into simplified promise, pre-rejected
* with a given `reason`. Note the result is not a complete promise
* implementation, as its method `then` does not returns anything.
*/
function rejected(reason) {
return { then: function then(fulfill, reject) { reject(reason); } };
}
/**
* Internal utility: Decorates given `f` function, so that on exception promise
* rejected with thrown error is returned.
*/
function attempt(f) {
/**
Returns wrapper function that delegates to `f`. If `f` throws then captures
error and returns promise that rejects with a thrown error. Otherwise returns
return value. (Internal utility)
**/
return function effort(options) {
try { return f(options) }
catch(error) { return rejection(error) }
}
}
function isPromise(value) {
/**
Returns true if given `value` is promise. Value is assumed to be promise if
it implements `then` method.
**/
return value && typeof(value.then) === 'function'
}
function defer(prototype) {
/**
Returns object containing following properties:
- `promise` Eventual value representation implementing CommonJS [Promises/A]
(http://wiki.commonjs.org/wiki/Promises/A) API.
- `resolve` Single shot function that resolves returned `promise` with a given
`value` argument.
- `reject` Single shot function that rejects returned `promise` with a given
`reason` argument.
Given `prototype` argument is used as a prototype of the returned `promise`
allowing one to implement additional API. If prototype is not passed then
it falls back to `Object.prototype`.
## Examples
// Simple usage.
var deferred = defer()
deferred.promise.then(console.log, console.error)
deferred.resolve(value)
// Advanced usage
var prototype = {
get: function get(name) {
return this.then(function(value) {
return value[name];
})
return function effort(input) {
try {
return f(input);
}
}
catch(error) {
if (exports._reportErrors && typeof(console) === 'object') {
console.error(error)
}
return rejected(error)
}
};
}
/**
* Internal utility: Returns `true` if given `value` is a promise. Value is
* assumed to be a promise if it implements method `then`.
*/
function isPromise(value) {
return value && typeof(value.then) === 'function';
}
/**
* Creates deferred object containing fresh promise & methods to either resolve
* or reject it. The result is an object with the following properties:
* - `promise` Eventual value representation implementing CommonJS [Promises/A]
* (http://wiki.commonjs.org/wiki/Promises/A) API.
* - `resolve` Single shot function that resolves enclosed `promise` with a
* given `value`.
* - `reject` Single shot function that rejects enclosed `promise` with a given
* `reason`.
*
* An optional `prototype` argument is used as a prototype of the returned
* `promise` allowing one to implement additional API. If prototype is not
* passed then it falls back to `Object.prototype`.
*
* ## Example
*
* function fetchURI(uri, type) {
* var deferred = defer();
* var request = new XMLHttpRequest();
* request.open("GET", uri, true);
* request.responseType = type;
* request.onload = function onload() {
* deferred.resolve(request.response);
* }
* request.onerror = function(event) {
* deferred.reject(event);
* }
* request.send();
*
* return deferred.promise;
* }
*/
function defer(prototype) {
// Define FIFO queue of observer pairs. Once promise is resolved & all queued
// observers are forwarded to `result` and variable is set to `null`.
var observers = [];
// Promise `result`, which will be assigned a resolution value once promise
// is resolved. Note that result will always be assigned promise (or alike)
// object to take care of propagation through promise chains. If result is
// `null` promise is not resolved yet.
var result = null;
var foo = defer(prototype)
deferred.promise.get('name').then(console.log)
deferred.resolve({ name: 'Foo' })
//=> 'Foo'
*/
var pending = [], result
prototype = (prototype || prototype === null) ? prototype : Object.prototype
// Create an object implementing promise API.
var promise = Object.create(prototype, {
then: { value: function then(resolve, reject) {
// create a new deferred using a same `prototype`.
var deferred = defer(prototype)
// If `resolve / reject` callbacks are not provided.
resolve = resolve ? attempt(resolve) : resolution
reject = reject ? attempt(reject) : rejection
then: { value: function then(onFulfill, onError) {
var deferred = defer(prototype);
// Create a listeners for a enclosed promise resolution / rejection that
// delegate to an actual callbacks and resolve / reject returned promise.
function resolved(value) { deferred.resolve(resolve(value)) }
function rejected(reason) { deferred.resolve(reject(reason)) }
// Decorate `onFulfill` / `onError` handlers with `attempt`, that
// way if wrapped handler throws exception decorator will catch and
// return promise rejected with it, which will cause rejection of
// `deferred.promise`. If handler is missing, substitute it with an
// utility function that takes one argument and returns promise
// fulfilled / rejected with it. This takes care of propagation
// through the rest of the promise chain.
onFulfill = onFulfill ? attempt(onFulfill) : fulfilled;
onError = onError ? attempt(onError) : rejected;
// If promise is pending register listeners. Otherwise forward them to
// resulting resolution.
if (pending) pending.push([ resolved, rejected ])
else result.then(resolved, rejected)
// Create a pair of observers that invoke given handlers & propagate
// results to `deferred.promise`.
function resolveDeferred(value) { deferred.resolve(onFulfill(value)); }
function rejectDeferred(reason) { deferred.resolve(onError(reason)); }
return deferred.promise
// If enclosed promise (`this.promise`) observers queue is still alive
// enqueue a new observer pair into it. Note that this does not
// necessary means that promise is pending, it may already be resolved,
// but we still have to queue observers to guarantee an order of
// propagation.
if (observers) {
observers.push({ resolve: resolveDeferred, reject: rejectDeferred });
}
// Otherwise just forward observer pair right to a `result` promise.
else {
result.then(resolveDeferred, rejectDeferred);
}
return deferred.promise;
}}
})
var deferred = {
promise: promise,
/**
* Resolves associated `promise` to a given `value`, unless it's already
* resolved or rejected. Note that resolved promise is not necessary a
* successfully fulfilled. Promise may be resolved with a promise `value`
* in which case `value` promise's fulfillment / rejection will propagate
* up to a promise resolved with `value`.
*/
resolve: function resolve(value) {
/**
Resolves associated `promise` to a given `value`, unless it's already
resolved or rejected.
**/
if (pending) {
// store resolution `value` as a promise (`value` itself may be a
// promise), so that all subsequent listeners can be forwarded to it,
// which either resolves immediately or forwards if `value` is
// a promise.
result = isPromise(value) ? value : resolution(value)
// forward all pending observers.
while (pending.length) result.then.apply(result, pending.shift())
// mark promise as resolved.
pending = null
if (!result) {
// Store resolution `value` in a `result` as a promise, so that all
// the subsequent handlers can be simply forwarded to it. Since
// `result` will be a promise all the value / error propagation will
// be uniformly taken care of.
result = isPromise(value) ? value : fulfilled(value);
// Forward already registered observers to a `result` promise in the
// order they were registered. Note that we intentionally dequeue
// observer at a time until queue is exhausted. This makes sure that
// handlers registered as side effect of observer forwarding are
// queued instead of being invoked immediately, guaranteeing FIFO
// order.
while (observers.length) {
var observer = observers.shift();
result.then(observer.resolve, observer.reject);
}
// Once `observers` queue is exhausted we `null`-ify it, so that
// new handlers are forwarded straight to the `result`.
observers = null;
}
},
/**
* Rejects associated `promise` with a given `reason`, unless it's already
* resolved / rejected. This is just a (better performing) convenience
* shortcut for `deferred.resolve(reject(reason))`.
*/
reject: function reject(reason) {
/**
Rejects associated `promise` with a given `reason`, unless it's already
resolved / rejected.
**/
deferred.resolve(rejection(reason))
// Note that if promise is resolved that does not necessary means that it
// is successfully fulfilled. Resolution value may be a promise in which
// case its result propagates. In other words if promise `a` is resolved
// with promise `b`, `a` is either fulfilled or rejected depending
// on weather `b` is fulfilled or rejected. Here `deferred.promise` is
// resolved with a promise pre-rejected with a given `reason`, there for
// `deferred.promise` is rejected with a given `reason`. This may feel
// little awkward first, but doing it this way greatly simplifies
// propagation through promise chains.
deferred.resolve(rejected(reason));
}
}
};
return deferred
return deferred;
}
exports.defer = defer
exports.defer = defer;
/**
* Returns a promise resolved to a given `value`. Optionally a second
* `prototype` argument may be provided to be used as a prototype for the
* returned promise.
*/
function resolve(value, prototype) {
/**
Returns a promise resolved to a given `value`. Optionally second `prototype`
arguments my be provided to be used as a prototype for a returned promise.
**/
var deferred = defer(prototype)
deferred.resolve(value)
return deferred.promise
var deferred = defer(prototype);
deferred.resolve(value);
return deferred.promise;
}
exports.resolve = resolve
exports.resolve = resolve;
/**
* Returns a promise rejected with a given `reason`. Optionally a second
* `prototype` argument may be provided to be used as a prototype for the
* returned promise.
*/
function reject(reason, prototype) {
/**
Returns a promise that is rejected with a given `reason`. Optionally second
`prototype` arguments my be provided to be used as a prototype for a returned
promise.
**/
var deferred = defer(prototype)
deferred.reject(reason)
return deferred.promise
var deferred = defer(prototype);
deferred.reject(reason);
return deferred.promise;
}
exports.reject = reject
exports.reject = reject;
var promised = (function() {
// Note: Define shortcuts and utility functions here in order to avoid
@ -226,6 +287,6 @@ var promised = (function() {
}
}
})()
exports.promised = promised
exports.promised = promised;
})
});

View File

@ -12,15 +12,20 @@ const { EventEmitter } = require('../deprecated/events');
const { Trait } = require('../deprecated/traits');
const { when } = require('../system/unload');
const { getInnerId, getOuterId, windows, isDocumentLoaded, isBrowser,
getMostRecentBrowserWindow } = require('../window/utils');
getMostRecentBrowserWindow, getMostRecentWindow } = require('../window/utils');
const errors = require('../deprecated/errors');
const { deprecateFunction } = require('../util/deprecate');
const { ignoreWindow } = require('sdk/private-browsing/utils');
const { isPrivateBrowsingSupported } = require('../self');
const windowWatcher = Cc['@mozilla.org/embedcomp/window-watcher;1'].
getService(Ci.nsIWindowWatcher);
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 });
/**
* An iterator for XUL windows currently in the application.
*
@ -31,7 +36,7 @@ function windowIterator() {
// Bug 752631: We only pass already loaded window in order to avoid
// breaking XUL windows DOM. DOM is broken when some JS code try
// to access DOM during "uninitialized" state of the related document.
let list = windows().filter(isDocumentLoaded);
let list = getWindows().filter(isDocumentLoaded);
for (let i = 0, l = list.length; i < l; i++) {
yield list[i];
}
@ -60,7 +65,7 @@ function WindowTracker(delegate) {
this._delegate = delegate;
this._loadingWindows = [];
for each (let window in windows())
for each (let window in getWindows())
this._regWindow(window);
windowWatcher.registerNotification(this);
@ -71,6 +76,10 @@ function WindowTracker(delegate) {
WindowTracker.prototype = {
_regLoadingWindow: function _regLoadingWindow(window) {
// Bug 834961: ignore private windows when they are not supported
if (ignoreWindow(window))
return;
this._loadingWindows.push(window);
window.addEventListener('load', this, true);
},
@ -85,6 +94,10 @@ WindowTracker.prototype = {
},
_regWindow: function _regWindow(window) {
// Bug 834961: ignore private windows when they are not supported
if (ignoreWindow(window))
return;
if (window.document.readyState == 'complete') {
this._unregLoadingWindow(window);
this._delegate.onTrack(window);
@ -103,7 +116,7 @@ WindowTracker.prototype = {
unload: function unload() {
windowWatcher.unregisterNotification(this);
for each (let window in windows())
for each (let window in getWindows())
this._unregWindow(window);
},
@ -117,6 +130,9 @@ WindowTracker.prototype = {
observe: errors.catchAndLog(function observe(subject, topic, data) {
var window = subject.QueryInterface(Ci.nsIDOMWindow);
// ignore private windows if they are not supported
if (ignoreWindow(window))
return;
if (topic == 'domwindowopened')
this._regWindow(window);
else
@ -159,12 +175,12 @@ Object.defineProperties(exports, {
activeWindow: {
enumerable: true,
get: function() {
return Cc['@mozilla.org/appshell/window-mediator;1']
.getService(Ci.nsIWindowMediator)
.getMostRecentWindow(null);
return getMostRecentWindow(null);
},
set: function(window) {
try { window.focus(); } catch (e) { }
try {
window.focus();
} catch (e) {}
}
},
activeBrowserWindow: {

View File

@ -7,7 +7,8 @@ module.metadata = {
"stability": "stable"
};
const { setMode, getMode, on: onStateChange, isWindowPrivate } = require('./private-browsing/utils');
const { setMode, getMode, on: onStateChange } = require('./private-browsing/utils');
const { isWindowPrivate } = require('./window/utils');
const { emit, on, once, off } = require('./event/core');
const { when: unload } = require('./system/unload');
const { deprecateUsage, deprecateFunction, deprecateEvent } = require('./util/deprecate');
@ -38,15 +39,24 @@ exports.removeListener = deprecateEvents(function removeListener(type, listener)
});
exports.isPrivate = function(thing) {
// if thing is defined, and we can find a window for it
// then check if the window is private
if (!!thing) {
// if the thing is a window, and the window is private
// then return true
if (isWindowPrivate(thing)) {
return true;
}
// can we find an associated window?
let window = getOwnerWindow(thing);
if (window)
return isWindowPrivate(window);
}
// if we get here, and global private browsing
// is available, and it is true, then return
// true otherwise false is returned here
return getMode();
};

View File

@ -11,11 +11,11 @@ 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 { getWindowLoadingContext, windows } = require('../window/utils');
const { WindowTracker } = require("../deprecated/window-utils");
const events = require('../system/events');
const { deprecateFunction } = require('../util/deprecate');
const { isOneOf, is, satisfiesVersion, version } = require('../system/xul-app');
const { isWindowPrivate } = require('../window/utils');
const { isPrivateBrowsingSupported } = require('../self');
let deferredEmit = defer(emit);
let pbService;
@ -33,7 +33,8 @@ if (isOneOf(['Firefox', 'Fennec'])) {
// 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) */ }
}
catch(e) { /* Private Browsing Service has been removed (Bug 818800) */ }
try {
PrivateBrowsingUtils = Cu.import('resource://gre/modules/PrivateBrowsingUtils.jsm', {}).PrivateBrowsingUtils;
@ -41,27 +42,6 @@ if (isOneOf(['Firefox', 'Fennec'])) {
catch(e) { /* if this file DNE then an error will be thrown */ }
}
function isWindowPrivate(win) {
if (!PrivateBrowsingUtils || !win)
return false;
// if the pbService is undefined, the PrivateBrowsingUtils.jsm is available,
// and the app is Firefox, then assume per-window private browsing is
// enabled.
if (win instanceof Ci.nsIDOMWindow) {
return PrivateBrowsingUtils.isWindowPrivate(win);
}
// Sometimes the input is not a nsIDOMWindow.. but it is still a winodw.
try {
return !!win.docShell.QueryInterface(Ci.nsILoadContext).usePrivateBrowsing;
}
catch (e) {}
return false;
}
exports.isWindowPrivate = isWindowPrivate;
// checks that global private browsing is implemented
let isGlobalPBSupported = exports.isGlobalPBSupported = !!pbService && is('Firefox');
@ -72,6 +52,11 @@ let isWindowPBSupported = exports.isWindowPBSupported =
// checks that per-tab private browsing is implemented
let isTabPBSupported = exports.isTabPBSupported =
!pbService && !!PrivateBrowsingUtils && is('Fennec') && satisfiesVersion(version, '>=20.0*');
function ignoreWindow(window) {
return !isPrivateBrowsingSupported && isWindowPrivate(window);
}
exports.ignoreWindow = ignoreWindow;
function onChange() {
// Emit event with in next turn of event loop.

View File

@ -13,6 +13,7 @@ function getOwnerWindow(thing) {
try {
// check for and return associated window
let fn = (privateNS(thing.prototype) || privateNS(thing) || {}).getOwnerWindow;
if (fn)
return fn.apply(fn, [thing].concat(arguments));
}

View File

@ -39,18 +39,20 @@ var ids = exports.ids = {
Thunderbird: "{3550f703-e582-4d05-9a08-453d09bdfdc6}"
};
var is = exports.is = function is(name) {
function is(name) {
if (!(name in ids))
throw new Error("Unkown Mozilla Application: " + name);
return ID == ids[name];
};
exports.is = is;
var isOneOf = exports.isOneOf = function isOneOf(names) {
function isOneOf(names) {
for (var i = 0; i < names.length; i++)
if (is(names[i]))
return true;
return false;
};
exports.isOneOf = isOneOf;
/**
* Use this to check whether the given version (e.g. xulApp.platformVersion)

View File

@ -11,7 +11,10 @@ function Options(options) {
return validateOptions(options, {
url: { is: ["string"] },
inBackground: { is: ["undefined", "boolean"] },
inBackground: {
map: function(v) !!v,
is: ["undefined", "boolean"]
},
isPinned: { is: ["undefined", "boolean"] },
isPrivate: { is: ["undefined", "boolean"] },
onOpen: { is: ["undefined", "function"] },

View File

@ -3,8 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { getTabForContentWindow } = require('./utils');
module.metadata = {
'stability': 'unstable'
};
// NOTE: This file should only export Tab instances
const { getTabForContentWindow, getTabForBrowser: getRawTabForBrowser } = require('./utils');
const { Tab } = require('./tab');
const { rawTabNS } = require('./namespace');
function getTabForWindow(win) {
let tab = getTabForContentWindow(win);
@ -12,6 +21,21 @@ function getTabForWindow(win) {
if (!tab)
return null;
return Tab({ tab: tab });
return getTabForRawTab(tab) || Tab({ tab: tab });
}
exports.getTabForWindow = getTabForWindow;
// only works on fennec atm
function getTabForRawTab(rawTab) {
let tab = rawTabNS(rawTab).tab;
if (tab) {
return tab;
}
return null;
}
exports.getTabForRawTab = getTabForRawTab;
function getTabForBrowser(browser) {
return getTabForRawTab(getRawTabForBrowser(browser));
}
exports.getTabForBrowser = getTabForBrowser;

View File

@ -7,3 +7,4 @@ let { ns } = require('../core/namespace');
exports.tabsNS = ns();
exports.tabNS = ns();
exports.rawTabNS = ns();

View File

@ -5,27 +5,40 @@
const { Cc, Ci } = require('chrome');
const { Class } = require('../core/heritage');
const { tabNS } = require('./namespace');
const { tabNS, rawTabNS } = require('./namespace');
const { EventTarget } = require('../event/target');
const { activateTab, getTabTitle, setTabTitle, closeTab, getTabURL, getContentWindowForTab,
getTabForBrowser,
setTabURL, getOwnerWindow, getTabContentType, getTabId } = require('./utils');
const { emit } = require('../event/core');
const { getOwnerWindow: getPBOwnerWindow } = require('../private-browsing/window/utils');
const { when: unload } = require('../system/unload');
const { EVENTS } = require('./events');
const ERR_FENNEC_MSG = 'This method is not yet supported by Fennec';
const Tab = Class({
extends: EventTarget,
initialize: function initialize(options) {
options = options.tab ? options : { tab: options };
let tab = options.tab;
EventTarget.prototype.initialize.call(this, options);
let tabInternals = tabNS(this);
rawTabNS(tab).tab = this;
tabInternals.window = options.window || getOwnerWindow(options.tab);
tabInternals.tab = options.tab;
let window = tabInternals.window = options.window || getOwnerWindow(tab);
tabInternals.tab = tab;
// TabReady
let onReady = tabInternals.onReady = onTabReady.bind(this);
tab.browser.addEventListener(EVENTS.ready.dom, onReady, false);
// TabClose
let onClose = tabInternals.onClose = onTabClose.bind(this);
window.BrowserApp.deck.addEventListener(EVENTS.close.dom, onClose, false);
unload(cleanupTab.bind(null, this));
},
/**
@ -145,6 +158,41 @@ const Tab = Class({
});
exports.Tab = Tab;
function cleanupTab(tab) {
let tabInternals = tabNS(tab);
if (!tabInternals.tab)
return;
if (tabInternals.tab.browser) {
tabInternals.tab.browser.removeEventListener(EVENTS.ready.dom, tabInternals.onReady, false);
}
tabInternals.onReady = null;
tabInternals.window.BrowserApp.deck.removeEventListener(EVENTS.close.dom, tabInternals.onClose, false);
tabInternals.onClose = null;
rawTabNS(tabInternals.tab).tab = null;
tabInternals.tab = null;
tabInternals.window = null;
}
function onTabReady(event) {
let win = event.target.defaultView;
// ignore frames
if (win === win.top) {
emit(this, 'ready', this);
}
}
// TabClose
function onTabClose(event) {
let rawTab = getTabForBrowser(event.target);
if (tabNS(this).tab !== rawTab)
return;
emit(this, EVENTS.close.name, this);
cleanupTab(this);
};
getPBOwnerWindow.define(Tab, function(tab) {
return getContentWindowForTab(tabNS(tab).tab);
});

View File

@ -11,9 +11,9 @@ module.metadata = {
}
};
if (require('../system/xul-app').is('Firefox')) {
module.exports = require('./tab-firefox');
}
else if (require('../system/xul-app').is('Fennec')) {
if (require('../system/xul-app').name == 'Fennec') {
module.exports = require('./tab-fennec');
}
else {
module.exports = require('./tab-firefox');
}

View File

@ -22,8 +22,7 @@ Object.defineProperties(tabs, {
});
return undefined;
}
// Open in active window if new window was not required..
// Open in active window if new window was not required.
let activeWindow = windows.activeWindow;
let privateState = !!options.isPrivate;
@ -35,7 +34,7 @@ Object.defineProperties(tabs, {
// find a window in the state that we need
let window = getWindow(privateState);
if (window) {
window.tabs.open(options);
window.tabs.open(options);
}
// open a window in the state that we need
else {
@ -52,9 +51,9 @@ Object.defineProperties(tabs, {
function getWindow(privateState) {
for each (let window in windows) {
if (privateState === isPrivate(window)) {
return window;
}
if (privateState === isPrivate(window)) {
return window;
}
}
return null;
}

View File

@ -11,9 +11,9 @@ module.metadata = {
}
};
if (require('../system/xul-app').is('Firefox')) {
module.exports = require('./tabs-firefox');
}
else if (require('../system/xul-app').is('Fennec')) {
if (require('../system/xul-app').name == 'Fennec') {
module.exports = require('../windows/tabs-fennec').tabs;
}
else {
module.exports = require('./tabs-firefox');
}

View File

@ -8,9 +8,17 @@ module.metadata = {
'stability': 'unstable'
};
// NOTE: This file should only deal with xul/native tabs
const { Ci } = require('chrome');
const { defer } = require("../lang/functional");
const { windows, isBrowser } = require('../window/utils');
const { Ci } = require('chrome');
const { isPrivateBrowsingSupported } = require('../self');
// Bug 834961: ignore private windows when they are not supported
function getWindows() windows(null, { includePrivate: isPrivateBrowsingSupported });
function activateTab(tab, window) {
let gBrowser = getTabBrowserForTab(tab);
@ -48,7 +56,7 @@ exports.getTabContainer = getTabContainer;
*/
function getTabs(window) {
if (arguments.length === 0) {
return windows().filter(isBrowser).reduce(function(tabs, window) {
return getWindows().filter(isBrowser).reduce(function(tabs, window) {
return tabs.concat(getTabs(window))
}, []);
}
@ -63,7 +71,7 @@ function getTabs(window) {
exports.getTabs = getTabs;
function getActiveTab(window) {
return window.gBrowser.selectedTab;
return getSelectedTab(window);
}
exports.getActiveTab = getActiveTab;
@ -79,7 +87,7 @@ exports.getOwnerWindow = getOwnerWindow;
// fennec
function getWindowHoldingTab(rawTab) {
for each (let window in windows()) {
for each (let window in getWindows()) {
// this function may be called when not using fennec,
// but BrowserApp is only defined on Fennec
if (!window.BrowserApp)
@ -105,10 +113,13 @@ function openTab(window, url, options) {
isPrivate: options.isPrivate || false
});
}
let tab = window.gBrowser.addTab(url);
if (!options.inBackground)
activateTab(tab);
return tab;
// firefox
let newTab = window.gBrowser.addTab(url);
if (!options.inBackground) {
activateTab(newTab);
}
return newTab;
};
exports.openTab = openTab;
@ -195,6 +206,7 @@ function getAllTabContentWindows() {
}
exports.getAllTabContentWindows = getAllTabContentWindows;
// gets the tab containing the provided window
function getTabForContentWindow(window) {
// Retrieve the topmost frame container. It can be either <xul:browser>,
// <xul:iframe/> or <html:iframe/>. But in our case, it should be xul:browser.
@ -202,9 +214,12 @@ function getTabForContentWindow(window) {
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.chromeEventHandler;
// Is null for toplevel documents
if (!browser)
if (!browser) {
return false;
}
// Retrieve the owner window, should be browser.xul one
let chromeWindow = browser.ownerDocument.defaultView;
@ -221,15 +236,29 @@ function getTabForContentWindow(window) {
return chromeWindow.gBrowser.tabs[i];
return null;
}
// Fennec
else if ('BrowserApp' in chromeWindow) {
// Looks like we are on Firefox Mobile
return chromeWindow.BrowserApp.getTabForWindow(window)
return getTabForWindow(window);
}
return null;
}
exports.getTabForContentWindow = getTabForContentWindow;
// used on fennec
function getTabForWindow(window) {
for each (let { BrowserApp } in getWindows()) {
if (!BrowserApp)
continue;
for each (let tab in BrowserApp.tabs) {
if (tab.browser.contentWindow == window.top)
return tab;
}
}
return null;
}
function getTabURL(tab) {
if (tab.browser) // fennec
return String(tab.browser.currentURI.spec);
@ -262,3 +291,20 @@ function getSelectedTab(window) {
return null;
}
exports.getSelectedTab = getSelectedTab;
function getTabForBrowser(browser) {
for each (let window in getWindows()) {
// this function may be called when not using fennec
if (!window.BrowserApp)
continue;
for each (let tab in window.BrowserApp.tabs) {
if (tab.browser === browser)
return tab;
}
}
return null;
}
exports.getTabForBrowser = getTabForBrowser;

View File

@ -69,14 +69,17 @@ Assert.prototype = {
return;
}
let message = e.message;
if ('operator' in e) {
message += [
" -",
source(e.expected),
e.operator,
source(e.actual)
].join(" ");
try {
if ('operator' in e) {
message += [
" -",
source(e.expected),
e.operator,
source(e.actual)
].join(" ");
}
}
catch(e) {}
this._log.fail(message);
},
pass: function pass(message) {

View File

@ -6,8 +6,9 @@
const { Loader, resolveURI, Require,
unload, override, descriptor } = require('../loader/cuddlefish');
const { PlainTextConsole } = require("sdk/console/plain-text");
exports.Loader = function(module, globals, packaging) {
function CustomLoader(module, globals, packaging) {
let options = packaging || require("@loader/options");
options = override(options, {
globals: override(require('../system/globals'), globals || {})
@ -26,3 +27,45 @@ exports.Loader = function(module, globals, packaging) {
}
}));
};
exports.Loader = CustomLoader;
// Creates a custom loader instance whose console module is hooked in order
// to avoid printing messages to the console, and instead, expose them in the
// returned `messages` array attribute
exports.LoaderWithHookedConsole = function (module, callback) {
let messages = [];
function hook(msg) {
messages.push({type: this, msg: msg});
if (callback)
callback(this, msg);
}
return {
loader: CustomLoader(module, {
console: {
log: hook.bind("log"),
info: hook.bind("info"),
warn: hook.bind("warn"),
error: hook.bind("error"),
debug: hook.bind("debug"),
exception: hook.bind("exception")
}
}),
messages: messages
};
}
// Same than LoaderWithHookedConsole with lower level, instead we get what is
// actually printed to the command line console
exports.LoaderWithHookedConsole2 = function (module, callback) {
let messages = [];
return {
loader: CustomLoader(module, {
console: new PlainTextConsole(function (msg) {
messages.push(msg);
if (callback)
callback(msg);
})
}),
messages: messages
};
}

View File

@ -87,3 +87,11 @@ exports.flatten = function flatten(array){
}
return flat;
};
function fromIterator(iterator) {
let array = [];
for each (let item in iterator)
array.push(item);
return array;
}
exports.fromIterator = fromIterator;

View File

@ -9,9 +9,10 @@ const { on, off, once } = require('../event/core');
const { method } = require('../lang/functional');
const { getWindowTitle } = require('./utils');
const unload = require('../system/unload');
const { getMode } = require('../private-browsing/utils');
const { isWindowPrivate } = require('../private-browsing/utils');
const { EventTarget } = require('../event/target');
const { getOwnerWindow: getPBOwnerWindow } = require('../private-browsing/window/utils');
const { deprecateUsage } = require('../util/deprecate');
const ERR_FENNEC_MSG = 'This method is not yet supported by Fennec, consider using require("tabs") instead';
@ -37,7 +38,13 @@ const BrowserWindow = Class({
on: method(on),
removeListener: method(off),
once: method(once),
get isPrivateBrowsing() getMode(windowNS(this).window),
get isPrivateBrowsing() {
deprecateUsage('`browserWindow.isPrivateBrowsing` is deprecated, please ' +
'consider using ' +
'`require("private-browsing").isPrivate(browserWindow)` ' +
'instead.');
return isWindowPrivate(windowNS(this).window);
}
});
exports.BrowserWindow = BrowserWindow;

View File

@ -9,12 +9,13 @@ module.metadata = {
const { Cc, Ci } = require('chrome');
const array = require('../util/array');
const observers = require('../deprecated/observer-service');
const { defer } = require('sdk/core/promise');
const windowWatcher = Cc['@mozilla.org/embedcomp/window-watcher;1'].
getService(Ci.nsIWindowWatcher);
const appShellService = Cc['@mozilla.org/appshell/appShellService;1'].
getService(Ci.nsIAppShellService);
const observers = require('../deprecated/observer-service');
const WM = Cc['@mozilla.org/appshell/window-mediator;1'].
getService(Ci.nsIWindowMediator);
@ -23,11 +24,41 @@ const BROWSER = 'navigator:browser',
NAME = '_blank',
FEATURES = 'chrome,all,dialog=no';
function isWindowPrivate(win) {
if (!win)
return false;
// if the pbService is undefined, the PrivateBrowsingUtils.jsm is available,
// and the app is Firefox, then assume per-window private browsing is
// enabled.
try {
return win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsILoadContext)
.usePrivateBrowsing;
}
catch(e) {}
// Sometimes the input is not a nsIDOMWindow.. but it is still a winodw.
try {
return !!win.docShell.QueryInterface(Ci.nsILoadContext).usePrivateBrowsing;
}
catch (e) {}
return false;
}
exports.isWindowPrivate = isWindowPrivate;
function getMostRecentBrowserWindow() {
return WM.getMostRecentWindow(BROWSER);
return getMostRecentWindow(BROWSER);
}
exports.getMostRecentBrowserWindow = getMostRecentBrowserWindow;
function getMostRecentWindow(type) {
return WM.getMostRecentWindow(type);
}
exports.getMostRecentWindow = getMostRecentWindow;
/**
* Returns the ID of the window's current inner window.
*/
@ -107,6 +138,11 @@ exports.backgroundify = backgroundify;
function serializeFeatures(options) {
return Object.keys(options).reduce(function(result, name) {
let value = options[name];
// the chrome and private features are special
if ((name == 'private' || name == 'chrome'))
return result + ((value === true) ? ',' + name : '');
return result + ',' + name + '=' +
(value === true ? 'yes' : value === false ? 'no' : value);
}, '').substr(1);
@ -121,19 +157,55 @@ function serializeFeatures(options) {
* @params {String} options.name
* Optional name that is assigned to the window.
* @params {Object} options.features
* Map of key, values like: `{ width: 10, height: 15, chrome: true }`.
* Map of key, values like: `{ width: 10, height: 15, chrome: true, private: true }`.
*/
function open(uri, options) {
options = options || {};
return windowWatcher.
let newWindow = windowWatcher.
openWindow(options.parent || null,
uri,
options.name || null,
serializeFeatures(options.features || {}),
options.args || null);
return newWindow;
}
exports.open = open;
function onFocus(window) {
let deferred = defer();
if (isFocused(window)) {
deferred.resolve(window);
}
else {
window.addEventListener("focus", function focusListener() {
window.removeEventListener("focus", focusListener, true);
deferred.resolve(window);
}, true);
}
return deferred.promise;
}
exports.onFocus = onFocus;
function isFocused(window) {
const FM = Cc["@mozilla.org/focus-manager;1"].
getService(Ci.nsIFocusManager);
let childTargetWindow = {};
FM.getFocusedElementForWindow(window, true, childTargetWindow);
childTargetWindow = childTargetWindow.value;
let focusedChildWindow = {};
if (FM.activeWindow) {
FM.getFocusedElementForWindow(FM.activeWindow, true, focusedChildWindow);
focusedChildWindow = focusedChildWindow.value;
}
return (focusedChildWindow === childTargetWindow);
}
/**
* Opens a top level window and returns it's `nsIDOMWindow` representation.
* Same as `open` but with more features
@ -149,8 +221,13 @@ function openDialog(options) {
features = features.split(',').concat('private').join(',');
}
let browser = WM.getMostRecentWindow(BROWSER);
return browser.openDialog.apply(
let browser = getMostRecentBrowserWindow();
// if there is no browser then do nothing
if (!browser)
return undefined;
let newWindow = browser.openDialog.apply(
browser,
array.flatten([
options.url || URI_BROWSER,
@ -159,6 +236,8 @@ function openDialog(options) {
options.args || null
])
);
return newWindow;
}
exports.openDialog = openDialog;
@ -166,12 +245,17 @@ exports.openDialog = openDialog;
* Returns an array of all currently opened windows.
* Note that these windows may still be loading.
*/
function windows() {
function windows(type, options) {
options = options || {};
let list = [];
let winEnum = windowWatcher.getWindowEnumerator();
let winEnum = WM.getEnumerator(type);
while (winEnum.hasMoreElements()) {
let window = winEnum.getNext().QueryInterface(Ci.nsIDOMWindow);
list.push(window);
// Only add non-private windows when pb permission isn't set,
// unless an option forces the addition of them.
if (options.includePrivate || !isWindowPrivate(window)) {
list.push(window);
}
}
return list;
}
@ -189,7 +273,11 @@ function isDocumentLoaded(window) {
exports.isDocumentLoaded = isDocumentLoaded;
function isBrowser(window) {
return window.document.documentElement.getAttribute("windowtype") === BROWSER;
try {
return window.document.documentElement.getAttribute("windowtype") === BROWSER;
}
catch (e) {}
return false;
};
exports.isBrowser = isBrowser;

View File

@ -11,9 +11,9 @@ module.metadata = {
}
};
if (require('./system/xul-app').is('Firefox')) {
module.exports = require('./windows/firefox');
}
else if (require('./system/xul-app').is('Fennec')) {
if (require('./system/xul-app').is('Fennec')) {
module.exports = require('./windows/fennec');
}
else {
module.exports = require('./windows/firefox');
}

View File

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

View File

@ -10,7 +10,7 @@ const { Cc, Ci, Cr } = require('chrome'),
{ WindowTabs, WindowTabTracker } = require('./tabs-firefox'),
{ WindowDom } = require('./dom'),
{ WindowLoader } = require('./loader'),
{ isBrowser, getWindowDocShell } = require('../window/utils'),
{ isBrowser, getWindowDocShell, windows: windowIterator } = require('../window/utils'),
{ Options } = require('../tabs/common'),
apiUtils = require('../deprecated/api-utils'),
unload = require('../system/unload'),
@ -21,6 +21,7 @@ const { Cc, Ci, Cr } = require('chrome'),
{ getOwnerWindow } = require('../private-browsing/window/utils'),
viewNS = require('../core/namespace').ns(),
{ isPrivateBrowsingSupported } = require('../self');
const { ignoreWindow } = require('sdk/private-browsing/utils');
/**
* Window trait composes safe wrappers for browser window that are E10S
@ -207,6 +208,9 @@ const browserWindows = Trait.resolve({ toString: null }).compose(
*/
get activeWindow() {
let window = windowUtils.activeBrowserWindow;
// Bug 834961: ignore private windows when they are not supported
if (ignoreWindow(window))
window = windowIterator()[0];
return window ? BrowserWindow({window: window}) : null;
},
open: function open(options) {
@ -231,6 +235,7 @@ const browserWindows = Trait.resolve({ toString: null }).compose(
this._add(window);
this._emit('open', window);
},
/**
* Internal listener which is called whenever window gets closed.
* Cleans up references and removes wrapper from this list.

View File

@ -8,8 +8,9 @@ const { Tab } = require('../tabs/tab');
const { browserWindows } = require('./fennec');
const { windowNS } = require('../window/namespace');
const { tabsNS, tabNS } = require('../tabs/namespace');
const { openTab, getTabs, getSelectedTab } = require('../tabs/utils');
const { openTab, getTabs, getSelectedTab, getTabForBrowser: getRawTabForBrowser } = require('../tabs/utils');
const { Options } = require('../tabs/common');
const { getTabForBrowser, getTabForRawTab } = require('../tabs/helpers');
const { on, once, off, emit } = require('../event/core');
const { method } = require('../lang/functional');
const { EVENTS } = require('../tabs/events');
@ -41,9 +42,6 @@ const Tabs = Class({
// TabSelect
window.BrowserApp.deck.addEventListener(EVENTS.activate.dom, onTabSelect, false);
// TabClose
window.BrowserApp.deck.addEventListener(EVENTS.close.dom, onTabClose, false);
},
get activeTab() {
return getTabForRawTab(getSelectedTab(tabsNS(this).window));
@ -92,7 +90,6 @@ function tabsUnloader(event, window) {
return;
window.BrowserApp.deck.removeEventListener(EVENTS.open.dom, onTabOpen, false);
window.BrowserApp.deck.removeEventListener(EVENTS.activate.dom, onTabSelect, false);
window.BrowserApp.deck.removeEventListener(EVENTS.close.dom, onTabClose, false);
}
// unload handler
@ -112,20 +109,6 @@ function removeTab(tab) {
return tab;
}
function getTabForBrowser(browser) {
return getTabForRawTab(getRawTabForBrowser(browser));
}
function getRawTabForBrowser(browser) {
let tabs = mainWindow.BrowserApp.tabs;
for (let i = 0; i < tabs.length; i++) {
let tab = tabs[i];
if (tab.browser === browser)
return tab
}
return null;
}
// TabOpen
function onTabOpen(event) {
let browser = event.target;
@ -140,19 +123,13 @@ function onTabOpen(event) {
tabNS(tab).opened = true;
// TabReady
let onReady = tabNS(tab).onReady = onTabReady.bind(tab);
browser.addEventListener(EVENTS.ready.dom, onReady, false);
tab.on('ready', function() emit(gTabs, 'ready', tab));
tab.once('close', onTabClose);
emit(tab, 'open', tab);
emit(gTabs, 'open', tab);
};
function onTabReady() {
emit(this, 'ready', this);
emit(gTabs, 'ready', this);
}
// TabSelect
function onTabSelect(event) {
// Set value whenever new tab becomes active.
@ -168,28 +145,7 @@ function onTabSelect(event) {
};
// TabClose
function onTabClose(event) {
let tab = getTabForBrowser(event.target);
function onTabClose(tab) {
removeTab(tab);
emit(gTabs, 'close', tab);
emit(tab, 'close', tab);
emit(gTabs, EVENTS.close.name, tab);
};
function getTabForRawTab(rawTab) {
for each (let tab in gTabs) {
if (tabNS(tab).tab === rawTab)
return tab;
}
return null;
}
unload(function() {
for each (let tab in gTabs) {
let tabInternals = tabNS(tab);
tabInternals.tab.browser.removeEventListener(EVENTS.ready.dom, tabInternals.onReady, false);
tabInternals.onReady = null;
tabInternals.tab = null;
tabInternals.window = null;
}
});

View File

@ -16,7 +16,7 @@ const { getOwnerWindow, getActiveTab, getTabs,
openTab } = require("../tabs/utils");
const { Options } = require("../tabs/common");
const { observer: tabsObserver } = require("../tabs/observer");
const { isWindowPrivate } = require("../private-browsing/utils");
const { ignoreWindow, isWindowPrivate } = require("../private-browsing/utils");
const TAB_BROWSER = "tabbrowser";
@ -91,7 +91,9 @@ const WindowTabTracker = Trait.compose({
tabsObserver.removeListener("deactivate", this._onTabDeactivate);
},
_onTabEvent: function _onTabEvent(type, tab) {
if (this._window === getOwnerWindow(tab)) {
// Accept only tabs for the watched window, and ignore private tabs
// if addon doesn't have private permission
if (this._window === getOwnerWindow(tab) && !ignoreWindow(this._window)) {
let options = this._tabOptions.shift() || {};
options.tab = tab;
options.window = this._public;

View File

@ -825,8 +825,8 @@ def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None,
if target_cfg.get('preferences'):
harness_options['preferences'] = target_cfg.get('preferences')
harness_options['manifest'] = \
manifest.get_harness_options_manifest(options.bundle_sdk)
# Do not add entries for SDK modules
harness_options['manifest'] = manifest.get_harness_options_manifest(False)
# Gives an hint to tell if sdk modules are bundled or not
harness_options['is-sdk-bundled'] = options.bundle_sdk
@ -912,6 +912,7 @@ def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None,
binary=options.binary,
profiledir=options.profiledir,
verbose=options.verbose,
parseable=options.parseable,
enforce_timeouts=enforce_timeouts,
logfile=options.logfile,
addons=options.addons,

View File

View File

0
addon-sdk/source/python-lib/cuddlefish/docs/webdocs.py Normal file → Executable file
View File

View File

@ -269,8 +269,7 @@ class ManifestBuilder:
yield absname
for me in self.get_module_entries():
# Do not add manifest entries for system modules,
# so that we won't ship SDK files.
# Only ship SDK files if we are told to do so
if me.packageName != "addon-sdk" or bundle_sdk_modules:
yield me.js_filename
@ -281,8 +280,9 @@ class ManifestBuilder:
manifest = {}
for me in self.get_module_entries():
path = me.get_path()
# Do not add manifest entries for system modules,
# so that we won't ship SDK files.
# Do not add manifest entries for system modules.
# Doesn't prevent from shipping modules.
# Shipping modules is decided in `get_used_files`.
if me.packageName != "addon-sdk" or bundle_sdk_modules:
manifest[path] = me.get_entry_for_manifest()
return manifest
@ -474,18 +474,6 @@ class ManifestBuilder:
# non-relative import. Might be a short name (requiring a search
# through "library" packages), or a fully-qualified one.
# Search for a module in new layout.
# First normalize require argument in order to easily find a mapping
normalized = reqname
if normalized.endswith(".js"):
normalized = normalized[:-len(".js")]
if normalized.startswith("addon-kit/"):
normalized = normalized[len("addon-kit/"):]
if normalized.startswith("api-utils/"):
normalized = normalized[len("api-utils/"):]
if normalized in NEW_LAYOUT_MAPPING:
reqname = NEW_LAYOUT_MAPPING[normalized]
if "/" in reqname:
# 2: PKG/MOD: find PKG, look inside for MOD
bits = reqname.split("/")
@ -507,9 +495,32 @@ class ManifestBuilder:
# their own package first, then the list of packages defined by their
# .dependencies list
from_pkg = from_module.package.name
return self._search_packages_for_module(from_pkg,
lookfor_sections, reqname,
looked_in)
mi = self._search_packages_for_module(from_pkg,
lookfor_sections, reqname,
looked_in)
if mi:
return mi
# Only after we look for module in the addon itself, search for a module
# in new layout.
# First normalize require argument in order to easily find a mapping
normalized = reqname
if normalized.endswith(".js"):
normalized = normalized[:-len(".js")]
if normalized.startswith("addon-kit/"):
normalized = normalized[len("addon-kit/"):]
if normalized.startswith("api-utils/"):
normalized = normalized[len("api-utils/"):]
if normalized in NEW_LAYOUT_MAPPING:
# get the new absolute path for this module
reqname = NEW_LAYOUT_MAPPING[normalized]
from_pkg = from_module.package.name
return self._search_packages_for_module(from_pkg,
lookfor_sections, reqname,
looked_in)
else:
# We weren't able to find this module, really.
return None
def _handle_module(self, mi):
if not mi:
@ -659,12 +670,13 @@ def scan_requirements_with_grep(fn, lines):
iscomment = True
if iscomment:
continue
mo = re.search(REQUIRE_RE, clause)
mo = re.finditer(REQUIRE_RE, clause)
if mo:
modname = mo.group(1)
requires[modname] = {}
if modname not in first_location:
first_location[modname] = lineno0+1
for mod in mo:
modname = mod.group(1)
requires[modname] = {}
if modname not in first_location:
first_location[modname] = lineno0 + 1
# define() can happen across multiple lines, so join everyone up.
wholeshebang = "\n".join(lines)

0
addon-sdk/source/python-lib/cuddlefish/preflight.py Normal file → Executable file
View File

View File

@ -10,6 +10,7 @@ import atexit
import shlex
import subprocess
import re
import shutil
import mozrunner
from cuddlefish.prefs import DEFAULT_COMMON_PREFS
@ -22,6 +23,9 @@ CLEANUP_ADB = re.compile(r'^(I|E)/(stdout|stderr|GeckoConsole)\s*\(\s*\d+\):\s*(
# Used to filter only messages send by `console` module
FILTER_ONLY_CONSOLE_FROM_ADB = re.compile(r'^I/(stdout|stderr)\s*\(\s*\d+\):\s*((info|warning|error|debug): .*)$')
# Used to detect the currently running test
PARSEABLE_TEST_NAME = re.compile(r'TEST-START \| ([^\n]+)\n')
# Maximum time we'll wait for tests to finish, in seconds.
# The purpose of this timeout is to recover from infinite loops. It should be
# longer than the amount of time any test run takes, including those on slow
@ -123,13 +127,13 @@ class FennecRunner(mozrunner.Runner):
self.__real_binary = mozrunner.Runner.find_binary(self)
return self.__real_binary
FENNEC_REMOTE_PATH = '/mnt/sdcard/jetpack-profile'
class RemoteFennecRunner(mozrunner.Runner):
profile_class = FennecProfile
names = ['fennec']
_REMOTE_PATH = '/mnt/sdcard/jetpack-profile'
_INTENT_PREFIX = 'org.mozilla.'
_adb_path = None
@ -198,13 +202,13 @@ class RemoteFennecRunner(mozrunner.Runner):
print "Pushing the addon to your device"
# Create a clean empty profile on the sd card
subprocess.call([self._adb_path, "shell", "rm -r " + self._REMOTE_PATH])
subprocess.call([self._adb_path, "shell", "mkdir " + self._REMOTE_PATH])
subprocess.call([self._adb_path, "shell", "rm -r " + FENNEC_REMOTE_PATH])
subprocess.call([self._adb_path, "shell", "mkdir " + FENNEC_REMOTE_PATH])
# Push the profile folder created by mozrunner to the device
# (we can't simply use `adb push` as it doesn't copy empty folders)
localDir = self.profile.profile
remoteDir = self._REMOTE_PATH
remoteDir = FENNEC_REMOTE_PATH
for root, dirs, files in os.walk(localDir, followlinks='true'):
relRoot = os.path.relpath(root, localDir)
# Note about os.path usage below:
@ -236,7 +240,7 @@ class RemoteFennecRunner(mozrunner.Runner):
"am start " +
"-a android.activity.MAIN " +
"-n " + self._intent_name + "/" + self._intent_name + ".App " +
"--es args \"-profile " + self._REMOTE_PATH + "\""
"--es args \"-profile " + FENNEC_REMOTE_PATH + "\""
]
def start(self):
@ -374,9 +378,33 @@ class XulrunnerAppRunner(mozrunner.Runner):
self.names = runner.names
return self.__real_binary
def set_overloaded_modules(env_root, app_type, addon_id, preferences, overloads):
# win32 file scheme needs 3 slashes
desktop_file_scheme = "file://"
if not env_root.startswith("/"):
desktop_file_scheme = desktop_file_scheme + "/"
pref_prefix = "extensions.modules." + addon_id + ".path"
# Set preferences that will map require prefix to a given path
for name, path in overloads.items():
if len(name) == 0:
prefName = pref_prefix
else:
prefName = pref_prefix + "." + name
if app_type == "fennec-on-device":
# For testing on device, we have to copy overloaded files from fs
# to the device and use device path instead of local fs path.
# Actual copy of files if done after the call to Profile constructor
preferences[prefName] = "file://" + \
FENNEC_REMOTE_PATH + "/overloads/" + name
else:
preferences[prefName] = desktop_file_scheme + \
path.replace("\\", "/") + "/"
def run_app(harness_root_dir, manifest_rdf, harness_options,
app_type, binary=None, profiledir=None, verbose=False,
enforce_timeouts=False,
parseable=False, enforce_timeouts=False,
logfile=None, addons=None, args=None, extra_environment={},
norun=None,
used_files=None, enable_mobile=False,
@ -396,22 +424,6 @@ def run_app(harness_root_dir, manifest_rdf, harness_options,
cmdargs = []
preferences = dict(DEFAULT_COMMON_PREFS)
# Overload global commonjs path with lib/ folders
file_scheme = "file://"
# win32 file scheme needs 3 slashes
if not env_root.startswith("/"):
file_scheme = file_scheme + "/"
addon_id = harness_options["jetpackID"]
pref_prefix = "extensions.modules." + addon_id + ".path"
if overload_modules:
preferences[pref_prefix] = file_scheme + \
os.path.join(env_root, "lib").replace("\\", "/") + "/"
# Overload tests/ mapping with test/ folder, only when running test
if is_running_tests:
preferences[pref_prefix + ".tests"] = file_scheme + \
os.path.join(env_root, "test").replace("\\", "/") + "/"
# For now, only allow running on Mobile with --force-mobile argument
if app_type in ["fennec", "fennec-on-device"] and not enable_mobile:
print """
@ -533,6 +545,18 @@ def run_app(harness_root_dir, manifest_rdf, harness_options,
addon_dir = os.path.join(mydir, "mobile-utils")
addons.append(addon_dir)
# Overload addon-specific commonjs modules path with lib/ folder
overloads = dict()
if overload_modules:
overloads[""] = os.path.join(env_root, "lib")
# Overload tests/ mapping with test/ folder, only when running test
if is_running_tests:
overloads["tests"] = os.path.join(env_root, "test")
set_overloaded_modules(env_root, app_type, harness_options["jetpackID"], \
preferences, overloads)
# the XPI file is copied into the profile here
profile = profile_class(addons=addons,
profile=profiledir,
@ -541,6 +565,17 @@ def run_app(harness_root_dir, manifest_rdf, harness_options,
# Delete the temporary xpi file
os.remove(xpi_path)
# Copy overloaded files registered in set_overloaded_modules
# For testing on device, we have to copy overloaded files from fs
# to the device and use device path instead of local fs path.
# (has to be done after the call to profile_class() which eventualy creates
# profile folder)
if app_type == "fennec-on-device":
profile_path = profile.profile
for name, path in overloads.items():
shutil.copytree(path, \
os.path.join(profile_path, "overloads", name))
runner = runner_class(profile=profile,
binary=binary,
env=env,
@ -672,6 +707,14 @@ def run_app(harness_root_dir, manifest_rdf, harness_options,
done = False
result = None
test_name = "unknown"
def Timeout(message, test_name, parseable):
if parseable:
sys.stderr.write("TEST-UNEXPECTED-FAIL | %s | %s\n" % (test_name, message))
sys.stderr.flush()
return Exception(message)
try:
while not done:
time.sleep(0.05)
@ -682,6 +725,10 @@ def run_app(harness_root_dir, manifest_rdf, harness_options,
last_output_time = time.time()
sys.stderr.write(new_chars)
sys.stderr.flush()
if is_running_tests and parseable:
match = PARSEABLE_TEST_NAME.search(new_chars)
if match:
test_name = match.group(1)
if os.path.exists(resultfile):
result = open(resultfile).read()
if result:
@ -692,11 +739,11 @@ def run_app(harness_root_dir, manifest_rdf, harness_options,
sys.stderr.write("'"+result+"'\n")
if enforce_timeouts:
if time.time() - last_output_time > OUTPUT_TIMEOUT:
raise Exception("Test output exceeded timeout (%ds)." %
OUTPUT_TIMEOUT)
raise Timeout("Test output exceeded timeout (%ds)." %
OUTPUT_TIMEOUT, test_name, parseable)
if time.time() - starttime > RUN_TIMEOUT:
raise Exception("Test run exceeded timeout (%ds)." %
RUN_TIMEOUT)
raise Timeout("Test run exceeded timeout (%ds)." %
RUN_TIMEOUT, test_name, parseable)
except:
runner.stop()
raise

View File

@ -4,7 +4,7 @@
#Template used by test-main.js
TEST_MAIN_JS = '''\
var main = require("main");
var main = require("./main");
exports["test main"] = function(assert) {
assert.pass("Unit test running!");
@ -15,7 +15,7 @@ exports["test main async"] = function(assert, done) {
done();
};
require("test").run(exports);
require("sdk/test").run(exports);
'''
#Template used by package.json

View File

View File

@ -11,6 +11,7 @@ const { isPrivate } = require('sdk/private-browsing');
const { getOwnerWindow } = require('sdk/private-browsing/window/utils');
const { is } = require('sdk/system/xul-app');
const { isWindowPBSupported, isTabPBSupported } = require('sdk/private-browsing/utils');
const { merge } = require('sdk/util/object');
const TAB_URL = 'data:text/html;charset=utf-8,TEST-TAB';
@ -39,13 +40,13 @@ exports.testGetOwnerWindow = function(assert, done) {
else {
if (isWindowPBSupported) {
assert.notStrictEqual(chromeWindow,
getOwnerWindow(tab),
'associated window is not the same for window and window\'s tab');
getOwnerWindow(tab),
'associated window is not the same for window and window\'s tab');
}
else {
assert.strictEqual(chromeWindow,
getOwnerWindow(tab),
'associated window is the same for window and window\'s tab');
getOwnerWindow(tab),
'associated window is the same for window and window\'s tab');
}
}
@ -163,4 +164,7 @@ if (!is('Fennec')) {
}
}
merge(module.exports, require('./windows'));
merge(module.exports, require('./tabs'));
require('sdk/test/runner').runTestsFromModule(module);

View File

@ -8,6 +8,7 @@ const {Cc,Ci} = require("chrome");
const timer = require("sdk/timers");
const xulApp = require("sdk/system/xul-app");
const { Loader } = require("sdk/test/loader");
const { openTab, getBrowserForTab, closeTab } = require("sdk/tabs/utils");
/**
* A helper function that creates a PageMod, then opens the specified URL
@ -40,10 +41,10 @@ exports.testPageMod = function testPageMod(test, testURL, pageModOptions,
var pageMods = [new pageMod.PageMod(opts) for each(opts in pageModOptions)];
var tabBrowser = browserWindow.gBrowser;
var newTab = tabBrowser.addTab(testURL);
tabBrowser.selectedTab = newTab;
var b = tabBrowser.getBrowserForTab(newTab);
let newTab = openTab(browserWindow, testURL, {
inBackground: false
});
var b = getBrowserForTab(newTab);
function onPageLoad() {
b.removeEventListener("load", onPageLoad, true);
@ -56,7 +57,7 @@ exports.testPageMod = function testPageMod(test, testURL, pageModOptions,
function done() {
pageMods.forEach(function(mod) mod.destroy());
// XXX leaks reported if we don't close the tab?
tabBrowser.removeTab(newTab);
closeTab(newTab);
loader.unload();
test.done();
}

View File

@ -3,9 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
let { Cc, Ci } = require("chrome");
const timer = require("sdk/timers");
const { LoaderWithHookedConsole, pb, pbUtils, activate, deactivate } = require("./helper");
const { LoaderWithHookedConsole, deactivate, pb, pbUtils } = require("./helper");
const tabs = require("sdk/tabs");
exports["test activate private mode via handler"] = function(test) {
@ -176,7 +175,7 @@ exports.testAutomaticUnload = function(test) {
test.waitUntilDone();
// Create another private browsing instance and unload it
let { loader, errors } = LoaderWithHookedConsole();
let { loader, errors } = LoaderWithHookedConsole(module);
let pb2 = loader.require("sdk/private-browsing");
let called = false;
pb2.on("start", function onStart() {
@ -192,7 +191,10 @@ exports.testAutomaticUnload = function(test) {
test.assert(!called,
"First private browsing instance is destroyed and inactive");
// Must reset to normal mode, so that next test starts with it.
deactivate(function() test.done());
deactivate(function() {
test.assert(errors.length, 0, "should have been 1 deprecation error");
test.done();
});
}, 0);
});
@ -203,7 +205,7 @@ exports.testUnloadWhileActive = function(test) {
test.waitUntilDone();
let called = false;
let { loader, errors } = LoaderWithHookedConsole();
let { loader, errors } = LoaderWithHookedConsole(module);
let pb2 = loader.require("sdk/private-browsing");
let ul = loader.require("sdk/system/unload");
@ -223,7 +225,8 @@ exports.testUnloadWhileActive = function(test) {
test.fail("stop should not have been fired");
});
pb.once("stop", function() {
test.assert(!called, "stop was not called on unload")
test.assert(!called, "stop was not called on unload");
test.assert(errors.length, 2, "should have been 2 deprecation errors");
test.done();
});

View File

@ -3,32 +3,30 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
let { Cc,Ci } = require('chrome');
const unload = require("sdk/system/unload");
const { Loader } = require('sdk/test/loader');
const { windows: windowsIterator } = require("sdk/window/utils");
const windows = require("sdk/windows").browserWindows;
let { loader } = LoaderWithHookedConsole();
const { loader } = LoaderWithHookedConsole(module);
const pb = loader.require('sdk/private-browsing');
const pbUtils = loader.require('sdk/private-browsing/utils');
const { getOwnerWindow } = require('sdk/private-browsing/window/utils');
require('sdk/tabs/utils');
require('sdk/windows');
function LoaderWithHookedConsole() {
function LoaderWithHookedConsole(module) {
let globals = {};
let errors = [];
let loader = Loader(module, {
console: Object.create(console, {
error: { value: function(e) {
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
@ -44,8 +42,6 @@ function deactivate(callback) {
}
exports.deactivate = deactivate;
exports.loader = loader;
exports.pb = pb;
exports.pbUtils = pbUtils;
exports.getOwnerWindow = getOwnerWindow;
exports.LoaderWithHookedConsole = LoaderWithHookedConsole;

View File

@ -1,13 +1,13 @@
'use strict';
const { Ci } = require('chrome');
const { pb, pbUtils, loader: pbLoader, getOwnerWindow } = require('./helper');
const { openTab, closeTab } = require('sdk/tabs/utils');
const browserWindows = require('sdk/windows');
const { getOwnerWindow } = require('sdk/private-browsing/window/utils');
exports.testIsPrivateOnTab = function(test) {
const { openTab, closeTab } = pbLoader.require('sdk/tabs/utils');
let window = pbLoader.require('sdk/windows').browserWindows.activeWindow;
let chromeWindow = pbLoader.require('sdk/private-browsing/window/utils').getOwnerWindow(window);
let window = browserWindows.activeWindow;
let chromeWindow = getOwnerWindow(window);
test.assert(chromeWindow instanceof Ci.nsIDOMWindow, 'associated window is found');
test.assert(!pb.isPrivate(chromeWindow), 'the top level window is not private');

View File

@ -4,30 +4,53 @@
'use strict';
const { pb, pbUtils } = require('./helper');
const { openDialog } = require('sdk/window/utils');
const { openDialog, open } = require('sdk/window/utils');
const { promise, close } = require('sdk/window/helpers');
const { isPrivate } = require('sdk/private-browsing');
const { browserWindows: windows } = require('sdk/windows');
// 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
});
win.addEventListener('DOMContentLoaded', function onload() {
win.removeEventListener('DOMContentLoaded', onload, false);
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');
win.addEventListener("unload", function onunload() {
win.removeEventListener('unload', onload, false);
close(win).then(function() {
assert.equal(pb.isActive, false, 'PB mode is not active');
done();
}, false);
});
});
}
win.close();
}, false);
// test open() from window/utils with private feature
// test isActive state in pwpb case
// test isPrivate on ChromeWindow
exports.testPerWindowPrivateBrowsingGetter = function(assert, done) {
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();
});
});
}
exports.testIsPrivateOnWindowOn = function(assert, done) {

View File

@ -4,30 +4,20 @@
'use strict';
const { Cc, Ci } = require('chrome');
const { Loader } = require('sdk/test/loader');
const { Loader, LoaderWithHookedConsole } = require('sdk/test/loader');
const timer = require('sdk/timers');
const tabs = require('sdk/tabs');
const windows = require('sdk/windows');
const tabsLen = tabs.length;
const URL = 'data:text/html;charset=utf-8,<html><head><title>#title#</title></head></html>';
const ERR_MSG = 'Error: This method is not yet supported by Fennec';
function LoaderWithHookedConsole() {
let errors = [];
let loader = Loader(module, {
console: Object.create(console, {
error: { value: function(error) {
errors.push(error);
}}
})
});
return {
loader: loader,
errors: errors
}
}
// Fennec error message dispatched on all currently unimplement tab features,
// that match LoaderWithHookedConsole messages object pattern
const ERR_FENNEC_MSG = {
type: "error",
msg: "This method is not yet supported by Fennec"
};
// TEST: tab unloader
exports.testAutomaticDestroy = function(test) {
@ -109,7 +99,7 @@ exports.testAutomaticDestroy = function(test) {
// TEST: tab properties
exports.testTabProperties = function(test) {
test.waitUntilDone();
let { loader, errors } = LoaderWithHookedConsole();
let { loader, messages } = LoaderWithHookedConsole();
let tabs = loader.require('sdk/tabs');
let url = "data:text/html;charset=utf-8,<html><head><title>foo</title></head><body>foo</body></html>";
@ -121,7 +111,10 @@ exports.testTabProperties = function(test) {
test.assertEqual(tab.url, url, "URL of the new tab matches");
test.assert(tab.favicon, "favicon of the new tab is not empty");
// TODO: remove need for this test by implementing the favicon feature
test.assertEqual(errors.length, 1, "favicon logs an error for now");
// Poors man deepEqual with JSON.stringify...
test.assertEqual(JSON.stringify(messages),
JSON.stringify([ERR_FENNEC_MSG]),
"favicon logs an error for now");
test.assertEqual(tab.style, null, "style of the new tab matches");
test.assertEqual(tab.index, tabsLen, "index of the new tab matches");
test.assertNotEqual(tab.getThumbnail(), null, "thumbnail of the new tab matches");
@ -230,7 +223,7 @@ exports.testTabReload = function(test) {
exports.testTabMove = function(test) {
test.waitUntilDone();
let { loader, errors } = LoaderWithHookedConsole();
let { loader, messages } = LoaderWithHookedConsole();
let tabs = loader.require('sdk/tabs');
let url = "data:text/html;charset=utf-8,testTabMove";
@ -247,8 +240,9 @@ exports.testTabMove = function(test) {
test.assert(tab.index > tab1.index, "2nd tab has valid index");
tab.index = 0;
test.assertEqual(tab.index, i, "tab index after move matches");
test.assertEqual(errors.length, 1, "setting tab.index logs error");
test.assertEqual(JSON.stringify(messages),
JSON.stringify([ERR_FENNEC_MSG]),
"setting tab.index logs error");
// end test
tab1.close(function() tab.close(function() {
loader.unload();
@ -264,7 +258,7 @@ exports.testTabMove = function(test) {
exports.testTabsOpen_alt = function(test) {
test.waitUntilDone();
let { loader, errors } = LoaderWithHookedConsole();
let { loader, messages } = LoaderWithHookedConsole();
let tabs = loader.require('sdk/tabs');
let url = "data:text/html;charset=utf-8,default";
@ -274,7 +268,7 @@ exports.testTabsOpen_alt = function(test) {
test.assertEqual(tab.url, url, "URL of the new tab matches");
test.assertEqual(tabs.activeTab, tab, "URL of active tab in the current window matches");
test.assertEqual(tab.isPinned, false, "The new tab is not pinned");
test.assertEqual(errors.length, 1, "isPinned logs error");
test.assertEqual(messages.length, 1, "isPinned logs error");
// end test
tab.close(function() {
@ -289,7 +283,7 @@ exports.testTabsOpen_alt = function(test) {
exports.testOpenPinned_alt = function(test) {
test.waitUntilDone();
let { loader, errors } = LoaderWithHookedConsole();
let { loader, messages } = LoaderWithHookedConsole();
let tabs = loader.require('sdk/tabs');
let url = "about:blank";
@ -298,7 +292,11 @@ exports.testOpenPinned_alt = function(test) {
isPinned: true,
onOpen: function(tab) {
test.assertEqual(tab.isPinned, false, "The new tab is pinned");
test.assertEqual(errors.length, 2, "isPinned logs error");
// We get two error message: one for tabs.open's isPinned argument
// and another one for tab.isPinned
test.assertEqual(JSON.stringify(messages),
JSON.stringify([ERR_FENNEC_MSG, ERR_FENNEC_MSG]),
"isPinned logs error");
// end test
tab.close(function() {
@ -313,7 +311,7 @@ exports.testOpenPinned_alt = function(test) {
exports.testPinUnpin_alt = function(test) {
test.waitUntilDone();
let { loader, errors } = LoaderWithHookedConsole();
let { loader, messages } = LoaderWithHookedConsole();
let tabs = loader.require('sdk/tabs');
let url = "data:text/html;charset=utf-8,default";
@ -322,11 +320,18 @@ exports.testPinUnpin_alt = function(test) {
onOpen: function(tab) {
tab.pin();
test.assertEqual(tab.isPinned, false, "The tab was pinned correctly");
test.assertEqual(errors.length, 2, "tab.pin() logs error");
test.assertEqual(JSON.stringify(messages),
JSON.stringify([ERR_FENNEC_MSG, ERR_FENNEC_MSG]),
"tab.pin() logs error");
// Clear console messages for the following test
messages.length = 0;
tab.unpin();
test.assertEqual(tab.isPinned, false, "The tab was unpinned correctly");
test.assertEqual(errors.length, 4, "tab.unpin() logs error");
test.assertEqual(JSON.stringify(messages),
JSON.stringify([ERR_FENNEC_MSG, ERR_FENNEC_MSG]),
"tab.unpin() logs error");
// end test
tab.close(function() {

View File

@ -6,7 +6,7 @@
const { Cc, Ci } = require("chrome");
const { setTimeout } = require("sdk/timers");
const { Loader, Require, override } = require("sdk/test/loader");
const { LoaderWithHookedConsole } = require("sdk/test/loader");
const { Worker } = require("sdk/content/worker");
const DEFAULT_CONTENT_URL = "data:text/html;charset=utf-8,foo";
@ -348,24 +348,12 @@ exports["test:nothing is leaked to content script"] = WorkerTest(
exports["test:ensure console.xxx works in cs"] = WorkerTest(
DEFAULT_CONTENT_URL,
function(assert, browser, done) {
// Create a new module loader in order to be able to create a `console`
// module mockup:
let loader = Loader(module, {
console: {
log: hook.bind("log"),
info: hook.bind("info"),
warn: hook.bind("warn"),
error: hook.bind("error"),
debug: hook.bind("debug"),
exception: hook.bind("exception")
}
});
let { loader } = LoaderWithHookedConsole(module, onMessage);
// Intercept all console method calls
let calls = [];
function hook(msg) {
assert.equal(this, msg,
function onMessage(type, msg) {
assert.equal(type, msg,
"console.xxx(\"xxx\"), i.e. message is equal to the " +
"console method name we are calling");
calls.push(msg);
@ -657,22 +645,11 @@ exports["test:check worker API with page history"] = WorkerTest(
exports["test:global postMessage"] = WorkerTest(
DEFAULT_CONTENT_URL,
function(assert, browser, done) {
// Create a new module loader in order to be able to create a `console`
// module mockup:
let loader = Loader(module, {
console: {
log: hook.bind(null, "log"),
info: hook.bind(null, "info"),
warn: hook.bind(null, "warn"),
error: hook.bind(null, "error"),
debug: hook.bind(null, "debug"),
exception: hook.bind(null, "exception")
}
});
let { loader } = LoaderWithHookedConsole(module, onMessage);
// Intercept all console method calls
let seenMessages = 0;
function hook(type, message) {
function onMessage(type, message) {
seenMessages++;
assert.equal(type, "error", "Should be an error");
assert.equal(message, "DEPRECATED: The global `postMessage()` function in " +

View File

@ -3,27 +3,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const deprecate = require("sdk/util/deprecate");
var { Loader } = require("sdk/test/loader");
function LoaderWithHookedConsole() {
let errors = [];
let loader = Loader(module, {
console: Object.create(console, {
error: { value: function(error) {
errors.push(error);
}}
})
});
return {
loader: loader,
deprecate: loader.require("sdk/util/deprecate"),
errors: errors
}
}
const { LoaderWithHookedConsole } = require("sdk/test/loader");
exports["test Deprecate Usage"] = function testDeprecateUsage(assert) {
let { loader, deprecate, errors } = LoaderWithHookedConsole();
let { loader, messages } = LoaderWithHookedConsole(module);
let deprecate = loader.require("sdk/util/deprecate");
function functionIsDeprecated() {
deprecate.deprecateUsage("foo");
@ -31,9 +15,10 @@ exports["test Deprecate Usage"] = function testDeprecateUsage(assert) {
functionIsDeprecated();
assert.equal(errors.length, 1, "only one error is dispatched");
assert.equal(messages.length, 1, "only one error is dispatched");
assert.equal(messages[0].type, "error", "the console message is an error");
let msg = errors[0];
let msg = messages[0].msg;
assert.ok(msg.indexOf("foo") !== -1,
"message contains the given message");
@ -46,7 +31,8 @@ exports["test Deprecate Usage"] = function testDeprecateUsage(assert) {
}
exports["test Deprecate Function"] = function testDeprecateFunction(assert) {
let { loader, deprecate, errors } = LoaderWithHookedConsole();
let { loader, messages } = LoaderWithHookedConsole(module);
let deprecate = loader.require("sdk/util/deprecate");
let self = {};
let arg1 = "foo";
@ -63,10 +49,10 @@ exports["test Deprecate Function"] = function testDeprecateFunction(assert) {
deprecateFunction.call(self, arg1, arg2);
assert.equal(errors.length, 1,
"only one error is dispatched");
assert.equal(messages.length, 1, "only one error is dispatched");
assert.equal(messages[0].type, "error", "the console message is an error");
let msg = errors[0];
let msg = messages[0].msg;
assert.ok(msg.indexOf("bar") !== -1, "message contains the given message");
assert.ok(msg.indexOf("testDeprecateFunction") !== -1,
"message contains name of the caller function");
@ -77,7 +63,8 @@ exports["test Deprecate Function"] = function testDeprecateFunction(assert) {
}
exports.testDeprecateEvent = function(assert, done) {
let { loader, deprecate, errors } = LoaderWithHookedConsole();
let { loader, messages } = LoaderWithHookedConsole(module);
let deprecate = loader.require("sdk/util/deprecate");
let { on, emit } = loader.require('sdk/event/core');
let testObj = {};
@ -85,15 +72,16 @@ exports.testDeprecateEvent = function(assert, done) {
testObj.on('fire', function() {
testObj.on('water', function() {
assert.equal(errors.length, 1, "only one error is dispatched");
assert.equal(messages.length, 1, "only one error is dispatched");
loader.unload();
done();
})
assert.equal(errors.length, 1, "only one error is dispatched");
assert.equal(messages.length, 1, "only one error is dispatched");
emit(testObj, 'water');
});
assert.equal(errors.length, 1, "only one error is dispatched");
let msg = errors[0];
assert.equal(messages.length, 1, "only one error is dispatched");
assert.equal(messages[0].type, "error", "the console message is an error");
let msg = messages[0].msg;
assert.ok(msg.indexOf("BAD") !== -1, "message contains the given message");
assert.ok(msg.indexOf("deprecateEvent") !== -1,
"message contains name of the caller function");

View File

@ -5,7 +5,7 @@
'use strict';
const { on, once, off, emit, count, amass } = require('sdk/event/core');
const { Loader } = require('sdk/test/loader');
const { LoaderWithHookedConsole } = require("sdk/test/loader");
exports['test add a listener'] = function(assert) {
let events = [ { name: 'event#1' }, 'event#2' ];
@ -159,13 +159,8 @@ exports['test error handling'] = function(assert) {
exports['test unhandled errors'] = function(assert) {
let exceptions = [];
let loader = Loader(module, {
console: Object.create(console, {
exception: { value: function(e) {
exceptions.push(e);
}}
})
});
let { loader, messages } = LoaderWithHookedConsole(module);
let { emit, on } = loader.require('sdk/event/core');
let target = {};
let boom = Error('Boom!');
@ -174,12 +169,16 @@ exports['test unhandled errors'] = function(assert) {
on(target, 'message', function() { throw boom; });
emit(target, 'message');
assert.ok(~String(exceptions[0]).indexOf('Boom!'),
assert.equal(messages.length, 1, 'Got the first exception');
assert.equal(messages[0].type, 'exception', 'The console message is exception');
assert.ok(~String(messages[0].msg).indexOf('Boom!'),
'unhandled exception is logged');
on(target, 'error', function() { throw drax; });
emit(target, 'message');
assert.ok(~String(exceptions[1]).indexOf('Draax!'),
assert.equal(messages.length, 2, 'Got the second exception');
assert.equal(messages[1].type, 'exception', 'The console message is exception');
assert.ok(~String(messages[1].msg).indexOf('Draax!'),
'error in error handler is logged');
};

View File

@ -4,7 +4,7 @@
'use strict';
const { Loader } = require('sdk/test/loader');
const { LoaderWithHookedConsole } = require("sdk/test/loader");
// Exposing private methods as public in order to test
const EventEmitter = require('sdk/deprecated/events').EventEmitter.compose({
@ -256,11 +256,7 @@ exports["test:removing once"] = function(test) {
exports['test:emitLoop'] = function(test) {
// Override the console for this test so it doesn't log the exception to the
// test output
let loader = Loader(module, {
console: Object.create(console, {
exception: { value: function(e) { }}
})
});
let { loader } = LoaderWithHookedConsole(module);
let EventEmitter = loader.require('sdk/deprecated/events').EventEmitter.compose({
listeners: function(type) this._listeners(type),

View File

@ -4,16 +4,10 @@
const observers = require("sdk/deprecated/observer-service");
const { Cc, Ci } = require("chrome");
const { Loader } = require("sdk/test/loader");
const { PlainTextConsole } = require("sdk/console/plain-text");
const { LoaderWithHookedConsole2 } = require("sdk/test/loader");
exports.testUnloadAndErrorLogging = function(test) {
var prints = [];
var loader = Loader(module, {
console: new PlainTextConsole(function(_) {
prints.push(_);
})
});
let { loader, messages } = LoaderWithHookedConsole2(module);
var sbobsvc = loader.require("sdk/deprecated/observer-service");
var timesCalled = 0;
@ -28,10 +22,12 @@ exports.testUnloadAndErrorLogging = function(test) {
test.assertEqual(timesCalled, 1);
sbobsvc.add("narg", badCb);
observers.notify("narg", "yo yo");
var lines = prints[0].split("\n");
var lines = messages[0].split("\n");
test.assertEqual(lines[0], "error: " + require("sdk/self").name + ": An exception occurred.");
test.assertEqual(lines[0], "error: " + require("sdk/self").name + ": An exception occurred.");
test.assertEqual(lines[1], "Error: foo");
test.assertEqual(lines[2], module.uri + " 24");
// Keep in mind to update "18" to the line of "throw new Error("foo")"
test.assertEqual(lines[2], module.uri + " 18");
test.assertEqual(lines[3], "Traceback (most recent call last):");
loader.unload();

View File

@ -3,8 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var pageMod = require("sdk/page-mod");
var testPageMod = require("./pagemod-test-helpers").testPageMod;
const pageMod = require("sdk/page-mod");
const testPageMod = require("./pagemod-test-helpers").testPageMod;
const { Loader } = require('sdk/test/loader');
const tabs = require("sdk/tabs");
const timer = require("sdk/timers");
@ -12,6 +12,7 @@ const { Cc, Ci } = require("chrome");
const { open, getFrames, getMostRecentBrowserWindow } = require('sdk/window/utils');
const windowUtils = require('sdk/deprecated/window-utils');
const { getTabContentWindow, getActiveTab, openTab, closeTab } = require('sdk/tabs/utils');
const { is } = require('sdk/system/xul-app');
const { data } = require('sdk/self');
/* XXX This can be used to delay closing the test Firefox instance for interactive
@ -21,8 +22,10 @@ exports.delay = function(test) {
if (false) {
test.waitUntilDone(60000);
timer.setTimeout(function() {test.done();}, 4000);
} else
}
else {
test.pass();
}
}
function Isolate(worker) {
@ -384,11 +387,12 @@ exports.testRelatedTabNoOtherReqs = function(test) {
let loader = Loader(module);
let { PageMod } = loader.require("sdk/page-mod");
let pageMod = new PageMod({
include: "about:*",
include: "about:blank?testRelatedTabNoOtherReqs",
onAttach: function(worker) {
test.assert(!!worker.tab, "Worker.tab exists");
pageMod.destroy();
worker.tab.close(function() {
worker.destroy();
loader.unload();
test.done();
});
@ -396,7 +400,7 @@ exports.testRelatedTabNoOtherReqs = function(test) {
});
tabs.open({
url: "about:"
url: "about:blank?testRelatedTabNoOtherReqs"
});
};
@ -434,7 +438,7 @@ exports.testWorksWithExistingTabs = function(test) {
});
};
exports['test tab worker on message'] = function(test) {
exports.testTabWorkerOnMessage = function(test) {
test.waitUntilDone();
let { browserWindows } = require("sdk/windows");
@ -506,7 +510,7 @@ exports.testAutomaticDestroy = function(test) {
}
exports['test attachment to tabs only'] = function(test) {
exports.testAttachToTabsOnly = function(test) {
test.waitUntilDone();
let { PageMod } = require('sdk/page-mod');
@ -543,7 +547,13 @@ exports['test attachment to tabs only'] = function(test) {
element.addEventListener('DOMContentLoaded', function onload() {
element.removeEventListener('DOMContentLoaded', onload, false);
hiddenFrames.remove(hiddenFrame);
openToplevelWindow();
if (!is("Fennec")) {
openToplevelWindow();
}
else {
openBrowserIframe();
}
}, false);
element.setAttribute('src', 'data:text/html;charset=utf-8,foo');
}
@ -579,7 +589,7 @@ exports['test attachment to tabs only'] = function(test) {
function openTabWithIframes() {
console.info('Open iframes in a tab');
let subContent = '<iframe src="data:text/html;charset=utf-8,sub frame" />'
let content = '<iframe src="data:text/html,' +
let content = '<iframe src="data:text/html;charset=utf-8,' +
encodeURIComponent(subContent) + '" />';
require('sdk/tabs').open({
url: 'data:text/html;charset=utf-8,' + encodeURIComponent(content),
@ -825,8 +835,8 @@ exports.testPageModCssAutomaticDestroy = function(test) {
let browserWindow = windowUtils.activeBrowserWindow;
let win = getTabContentWindow(getActiveTab(browserWindow));
let div = win.document.querySelector("div"),
style = win.getComputedStyle(div);
let div = win.document.querySelector("div");
let style = win.getComputedStyle(div);
test.assertEqual(
style.width,
@ -995,14 +1005,16 @@ exports.testExistingOnFrames = function(test) {
exports.testIFramePostMessage = function(test) {
test.waitUntilDone();
let count = 0;
tabs.open({
url: data.url("test-iframe.html"),
onReady: function(tab) {
var worker = tab.attach({
contentScriptFile: data.url('test-iframe.js'),
contentScript: ' var iframePath = \'' + data.url('test-iframe-postmessage.html') + '\'',
contentScript: 'var iframePath = \'' + data.url('test-iframe-postmessage.html') + '\'',
onMessage: function(msg) {
test.assertEqual(++count, 1);
test.assertEqual(msg.first, 'a string');
test.assert(msg.second[1], "array");
test.assertEqual(typeof msg.third, 'object');
@ -1039,14 +1051,3 @@ exports.testEvents = function(test) {
}
);
};
if (require("sdk/system/xul-app").is("Fennec")) {
module.exports = {
"test Unsupported Test": function UnsupportedTest (test) {
test.pass(
"Skipping this test until Fennec support is implemented." +
"See bug 784224");
}
}
}

View File

@ -4,6 +4,7 @@
let { Cc, Ci } = require("chrome");
const { Loader } = require('sdk/test/loader');
const { LoaderWithHookedConsole } = require("sdk/test/loader");
const timer = require("sdk/timers");
const self = require('sdk/self');
@ -492,26 +493,21 @@ exports["test console.log in Panel"] = function(assert, done) {
console.log("' + text + '");\
}</script>';
let panel;
let loader = Loader(module, {
console: {
log: function (message) {
assert.equal(message, text, 'console.log() works');
panel.destroy();
done();
}
}
});
let { loader } = LoaderWithHookedConsole(module, onMessage);
let { Panel } = loader.require('sdk/panel');
panel = Panel({
let panel = Panel({
contentURL: 'data:text/html;charset=utf-8,' + encodeURIComponent(html)
});
panel.show();
function onMessage(type, message) {
assert.equal(type, 'log', 'console.log() works');
assert.equal(message, text, 'console.log() works');
panel.destroy();
done();
}
};
try {

View File

@ -4,24 +4,29 @@
'use strict';
const { Ci } = require('chrome');
const { pb, pbUtils, getOwnerWindow } = require('./private-browsing/helper');
const { merge } = require('sdk/util/object');
const windows = require('sdk/windows').browserWindows;
const tabs = require('sdk/tabs');
const winUtils = require('sdk/window/utils');
const { isWindowPrivate } = winUtils;
const { isPrivateBrowsingSupported } = require('sdk/self');
const { is } = require('sdk/system/xul-app');
const { isPrivate } = require('sdk/private-browsing');
const { getOwnerWindow } = require('sdk/private-browsing/window/utils');
const { LoaderWithHookedConsole } = require("sdk/test/loader");
const { getMode, isGlobalPBSupported,
isWindowPBSupported, isTabPBSupported } = require('sdk/private-browsing/utils');
const { pb } = require('./private-browsing/helper');
// is global pb is enabled?
if (pbUtils.isGlobalPBSupported) {
if (isGlobalPBSupported) {
merge(module.exports, require('./private-browsing/global'));
exports.testGlobalOnlyOnFirefox = function(test) {
test.assert(is("Firefox"), "isGlobalPBSupported is only true on Firefox");
}
}
else if (pbUtils.isWindowPBSupported) {
else if (isWindowPBSupported) {
merge(module.exports, require('./private-browsing/windows'));
exports.testPWOnlyOnFirefox = function(test) {
@ -29,7 +34,7 @@ else if (pbUtils.isWindowPBSupported) {
}
}
// only on Fennec
else if (pbUtils.isTabPBSupported) {
else if (isTabPBSupported) {
merge(module.exports, require('./private-browsing/tabs'));
exports.testPTOnlyOnFennec = function(test) {
@ -38,19 +43,26 @@ else if (pbUtils.isTabPBSupported) {
}
exports.testIsPrivateDefaults = function(test) {
test.assertEqual(pb.isPrivate(), false, 'undefined is not private');
test.assertEqual(pb.isPrivate('test'), false, 'strings are not private');
test.assertEqual(pb.isPrivate({}), false, 'random objects are not private');
test.assertEqual(pb.isPrivate(4), false, 'numbers are not private');
test.assertEqual(pb.isPrivate(/abc/), false, 'regex are not private');
test.assertEqual(pb.isPrivate(function() {}), false, 'functions are not private');
test.assertEqual(isPrivate(), false, 'undefined is not private');
test.assertEqual(isPrivate('test'), false, 'strings are not private');
test.assertEqual(isPrivate({}), false, 'random objects are not private');
test.assertEqual(isPrivate(4), false, 'numbers are not private');
test.assertEqual(isPrivate(/abc/), false, 'regex are not private');
test.assertEqual(isPrivate(function() {}), false, 'functions are not private');
};
exports.testWindowDefaults = function(test) {
test.assertEqual(windows.activeWindow.isPrivateBrowsing, false, 'window is not private browsing by default');
// Ensure that browserWindow still works while being deprecated
let { loader, messages } = LoaderWithHookedConsole(module);
let windows = loader.require("sdk/windows").browserWindows;
test.assertEqual(windows.activeWindow.isPrivateBrowsing, false,
'window is not private browsing by default');
test.assertMatches(messages[0].msg, /DEPRECATED.+isPrivateBrowsing/,
'isPrivateBrowsing is deprecated');
let chromeWin = winUtils.getMostRecentBrowserWindow();
test.assertEqual(pbUtils.getMode(chromeWin), false);
test.assertEqual(pbUtils.isWindowPrivate(chromeWin), false);
test.assertEqual(getMode(chromeWin), false);
test.assertEqual(isWindowPrivate(chromeWin), false);
}
// tests for the case where private browsing doesn't exist
@ -61,7 +73,7 @@ exports.testIsActiveDefault = function(test) {
exports.testIsPrivateBrowsingFalseDefault = function(test) {
test.assertEqual(isPrivateBrowsingSupported, false,
'usePrivateBrowsing property is false by default');
'isPrivateBrowsingSupported property is false by default');
};
exports.testGetOwnerWindow = function(test) {

View File

@ -6,8 +6,7 @@ const events = require("sdk/system/events");
const self = require("sdk/self");
const { Cc, Ci, Cu } = require("chrome");
const { setTimeout } = require("sdk/timers");
const { Loader } = require("sdk/test/loader");
const { PlainTextConsole } = require("sdk/console/plain-text");
const { LoaderWithHookedConsole2 } = require("sdk/test/loader");
const nsIObserverService = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
@ -36,12 +35,7 @@ exports["test basic"] = function(assert) {
}
exports["test error reporting"] = function(assert) {
let prints = [];
let loader = Loader(module, {
console: new PlainTextConsole(function(_) {
prints.push(_);
})
});
let { loader, messages } = LoaderWithHookedConsole2(module);
let events = loader.require("sdk/system/events");
function brokenHandler(subject, data) { throw new Error("foo"); };
@ -49,18 +43,18 @@ exports["test error reporting"] = function(assert) {
let lineNumber;
try { brokenHandler() } catch (error) { lineNumber = error.lineNumber }
let errorType = Date.now().toString(32);
events.on(errorType, brokenHandler);
events.emit(errorType, { data: "yo yo" });
assert.ok(prints[0].indexOf(self.name + ": An exception occurred.") >= 0,
assert.equal(messages.length, 1, "Got an exception");
let text = messages[0];
assert.ok(text.indexOf(self.name + ": An exception occurred.") >= 0,
"error is logged");
assert.ok(prints[0].indexOf("Error: foo") >= 0, "error message is logged");
assert.ok(prints[0].indexOf(module.uri) >= 0, "module uri is logged");
assert.ok(prints[0].indexOf(lineNumber) >= 0, "error line is logged");
assert.ok(text.indexOf("Error: foo") >= 0, "error message is logged");
assert.ok(text.indexOf(module.uri) >= 0, "module uri is logged");
assert.ok(text.indexOf(lineNumber) >= 0, "error line is logged");
events.off(errorType, brokenHandler);

View File

@ -7,7 +7,9 @@ const { Loader } = require('sdk/test/loader');
const { browserWindows } = require('sdk/windows');
const tabs = require('sdk/tabs');
const { isPrivate } = require('sdk/private-browsing');
const { isWindowPBSupported, isTabPBSupported } = require('sdk/private-browsing/utils');
const { openDialog } = require('sdk/window/utils');
const pbUtils = require('sdk/private-browsing/utils');
const { isWindowPrivate } = require('sdk/window/utils');
const URL = 'data:text/html;charset=utf-8,<html><head><title>#title#</title></head></html>';
@ -299,7 +301,7 @@ exports.testTabContentTypeAndReload = function(test) {
});
};
// test that it is possible to open a private tab
// test that it isn't possible to open a private tab without the private permission
exports.testTabOpenPrivate = function(test) {
test.waitUntilDone();
@ -309,7 +311,7 @@ exports.testTabOpenPrivate = function(test) {
isPrivate: true,
onReady: function(tab) {
test.assertEqual(tab.url, url, 'opened correct tab');
test.assertEqual(isPrivate(tab), false, 'private tabs arenot supported by default');
test.assertEqual(isPrivate(tab), false, 'private tabs are not supported by default');
tab.close(function() {
test.done();
@ -317,3 +319,36 @@ exports.testTabOpenPrivate = function(test) {
}
});
}
// We need permission flag in order to see private window's tabs
exports.testPrivateAreNotListed = function (test) {
test.waitUntilDone();
let originalTabCount = tabs.length;
let win = openDialog({
private: true
});
win.addEventListener("load", function onload() {
win.removeEventListener("load", onload);
// PWPB case
if (pbUtils.isWindowPBSupported) {
test.assert(isWindowPrivate(win), "window is private");
test.assertEqual(tabs.length, originalTabCount,
'New private window\'s tab isn\'t visible in tabs list');
}
else {
// Global case, openDialog didn't opened a private window/tab
test.assert(!isWindowPrivate(win), "window is private");
test.assertEqual(tabs.length, originalTabCount + 1,
'New non-private window\'s tab is visible in tabs list');
}
win.addEventListener("unload", function onunload() {
win.removeEventListener('unload', onunload);
test.done();
});
win.close();
});
}

View File

@ -5,17 +5,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var unload = require("sdk/system/unload");
var { Loader } = require("sdk/test/loader");
var { Loader, LoaderWithHookedConsole } = require("sdk/test/loader");
exports.testUnloading = function(test) {
var loader = Loader(module, {
console: Object.create(console, {
exception: { value: function(error) {
exceptions.push(error);
}}
})
});
var exceptions = [];
let { loader, messages } = LoaderWithHookedConsole(module);
var ul = loader.require("sdk/system/unload");
var unloadCalled = 0;
function unload() {
@ -32,8 +25,10 @@ exports.testUnloading = function(test) {
loader.unload();
test.assertEqual(unloadCalled, 2,
"Unloader functions are called on unload.");
test.assertEqual(exceptions.length, 1,
"One unload handler threw exception");
test.assertEqual(messages.length, 1,
"One unload handler threw exception 1/2");
test.assertEqual(messages[0].type, "exception",
"One unload handler threw exception 2/2");
};
exports.testEnsure = function(test) {

View File

@ -1,34 +1,34 @@
/* 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 windowUtils = require("sdk/deprecated/window-utils");
var timer = require("sdk/timers");
var { Cc, Ci } = require("chrome");
var { Loader, unload } = require("sdk/test/loader");
const windowUtils = require("sdk/deprecated/window-utils");
const timer = require("sdk/timers");
const { Cc, Ci } = require("chrome");
const { Loader } = require("sdk/test/loader");
const { open, getFrames, getWindowTitle, onFocus } = require('sdk/window/utils');
const { close } = require('sdk/window/helpers');
const { fromIterator: toArray } = require('sdk/util/array');
function toArray(iterator) {
let array = [];
for each (let item in iterator)
array.push(item);
return array;
}
const WM = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
function makeEmptyWindow() {
function makeEmptyWindow(options) {
options = options || {};
var xulNs = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
var blankXul = ('<?xml version="1.0"?>' +
'<?xml-stylesheet href="chrome://global/skin/" ' +
' type="text/css"?>' +
'<window xmlns="' + xulNs + '" windowtype="test:window">' +
'</window>');
var url = "data:application/vnd.mozilla.xul+xml;charset=utf-8," + escape(blankXul);
var features = ["chrome", "width=10", "height=10"];
var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Ci.nsIWindowWatcher);
return ww.openWindow(null, url, null, features.join(","), null);
return open("data:application/vnd.mozilla.xul+xml;charset=utf-8," + escape(blankXul), {
features: {
chrome: true,
width: 10,
height: 10
}
});
}
exports['test close on unload'] = function(assert) {
@ -83,7 +83,7 @@ exports['test close on unload'] = function(assert) {
"window not closed again on module unload.");
};
exports['test window watcher'] = function(assert, done) {
exports.testWindowTracker = function(assert, done) {
var myWindow;
var finished = false;
@ -91,21 +91,23 @@ exports['test window watcher'] = function(assert, done) {
onTrack: function(window) {
if (window == myWindow) {
assert.pass("onTrack() called with our test window");
timer.setTimeout(function() { myWindow.close(); }, 1);
timer.setTimeout(function() myWindow.close());
}
},
onUntrack: function(window) {
if (window == myWindow) {
assert.pass("onUntrack() called with our test window");
timer.setTimeout(function() {
if (!finished) {
finished = true;
myWindow = null;
wt.unload();
done();
} else
assert.fail("finishTest() called multiple times.");
}, 1);
if (!finished) {
finished = true;
myWindow = null;
wt.unload();
done();
}
else {
assert.fail("finishTest() called multiple times.");
}
});
}
}
};
@ -159,9 +161,7 @@ exports['test window watcher untracker'] = function(assert, done) {
exports['test window watcher unregs 4 loading wins'] = function(assert, done) {
var myWindow;
var finished = false;
let browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getMostRecentWindow("navigator:browser");
let browserWindow = WM.getMostRecentWindow("navigator:browser");
var counter = 0;
var delegate = {
@ -236,9 +236,8 @@ exports['test window watcher without untracker'] = function(assert, done) {
};
exports['test active window'] = function(assert, done) {
let browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getMostRecentWindow("navigator:browser");
let browserWindow = WM.getMostRecentWindow("navigator:browser");
let continueAfterFocus = function(window) onFocus(window).then(nextTest);
assert.equal(windowUtils.activeBrowserWindow, browserWindow,
"Browser window is the active browser window.");
@ -246,8 +245,7 @@ exports['test active window'] = function(assert, done) {
let testSteps = [
function() {
windowUtils.activeWindow = browserWindow;
continueAfterFocus(browserWindow);
continueAfterFocus(windowUtils.activeWindow = browserWindow);
},
function() {
assert.equal(windowUtils.activeWindow, browserWindow,
@ -267,49 +265,18 @@ exports['test active window'] = function(assert, done) {
function() {
assert.equal(windowUtils.activeBrowserWindow, browserWindow,
"Correct active browser window [4]");
browserWindow = null;
done();
}
];
let nextTest = function() {
let func = testSteps.shift();
if (func) {
func();
}
function nextTest() {
if (testSteps.length)
testSteps.shift()();
}
function continueAfterFocus(targetWindow) {
// Based on SimpleTest.waitForFocus
var fm = Cc["@mozilla.org/focus-manager;1"].
getService(Ci.nsIFocusManager);
var childTargetWindow = {};
fm.getFocusedElementForWindow(targetWindow, true, childTargetWindow);
childTargetWindow = childTargetWindow.value;
var focusedChildWindow = {};
if (fm.activeWindow) {
fm.getFocusedElementForWindow(fm.activeWindow, true, focusedChildWindow);
focusedChildWindow = focusedChildWindow.value;
}
var focused = (focusedChildWindow == childTargetWindow);
if (focused) {
nextTest();
} else {
childTargetWindow.addEventListener("focus", function focusListener() {
childTargetWindow.removeEventListener("focus", focusListener, true);
nextTest();
}, true);
}
}
nextTest();
};
exports['test windowIterator'] = function(assert, done) {
exports.testWindowIterator = function(assert, done) {
// make a new window
let window = makeEmptyWindow();
@ -327,17 +294,12 @@ exports['test windowIterator'] = function(assert, done) {
window.addEventListener("load", function onload() {
window.addEventListener("load", onload, false);
assert.ok(toArray(windowUtils.windowIterator()).indexOf(window) !== -1,
"window is now in windowIterator(false)");
"window is now in windowIterator()");
// Wait for the window unload before ending test
window.addEventListener("unload", function onunload() {
window.addEventListener("unload", onunload, false);
done();
}, false);
window.close();
close(window).then(done);
}, false);
}
};
if (require("sdk/system/xul-app").is("Fennec")) {
module.exports = {

View File

@ -1,12 +1,13 @@
/* 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 { Ci } = require('chrome');
const { open, backgroundify, windows,
getXULWindow, getBaseWindow } = require('sdk/window/utils');
const { open, backgroundify, windows, isBrowser,
getXULWindow, getBaseWindow, getMostRecentWindow,
getMostRecentBrowserWindow } = require('sdk/window/utils');
const { close } = require('sdk/window/helpers');
const windowUtils = require('sdk/deprecated/window-utils');
exports['test get nsIBaseWindow from nsIDomWindow'] = function(assert) {
@ -27,13 +28,15 @@ exports['test get nsIXULWindow from nsIDomWindow'] = function(assert) {
'base returns nsIXULWindow');
};
exports['test top window creation'] = function(assert) {
exports['test top window creation'] = function(assert, done) {
let window = open('data:text/html;charset=utf-8,Hello top window');
assert.ok(~windows().indexOf(window), 'window was opened');
window.close();
// Wait for the window unload before ending test
close(window).then(done);
};
exports['test new top window with options'] = function(assert) {
exports['test new top window with options'] = function(assert, done) {
let window = open('data:text/html;charset=utf-8,Hi custom top window', {
name: 'test',
features: { height: 100, width: 200, toolbar: true }
@ -43,10 +46,12 @@ exports['test new top window with options'] = function(assert) {
assert.equal(window.innerHeight, 100, 'height is set');
assert.equal(window.innerWidth, 200, 'height is set');
assert.equal(window.toolbar.visible, true, 'toolbar was set');
window.close();
// Wait for the window unload before ending test
close(window).then(done);
};
exports['test backgroundify'] = function(assert) {
exports.testBackgroundify = function(assert, done) {
let window = open('data:text/html;charset=utf-8,backgroundy');
assert.ok(~windows().indexOf(window),
'window is in the list of windows');
@ -54,7 +59,22 @@ exports['test backgroundify'] = function(assert) {
assert.equal(backgroundy, window, 'backgroundify returs give window back');
assert.ok(!~windows().indexOf(window),
'backgroundifyied window is in the list of windows');
window.close();
// Wait for the window unload before ending test
close(window).then(done);
};
exports.testIsBrowser = function(assert) {
// dummy window, bad type
assert.equal(isBrowser({ document: { documentElement: { getAttribute: function() {
return 'navigator:browserx';
}}}}), false, 'dummy object with correct stucture and bad type does not pass');
assert.ok(isBrowser(getMostRecentBrowserWindow()), 'active browser window is a browser window');
assert.ok(!isBrowser({}), 'non window is not a browser window');
assert.ok(!isBrowser({ document: {} }), 'non window is not a browser window');
assert.ok(!isBrowser({ document: { documentElement: {} } }), 'non window is not a browser window');
assert.ok(!isBrowser(), 'no argument is not a browser window');
};
require('test').run(exports);

View File

@ -6,12 +6,12 @@
const { Cc, Ci } = require('chrome');
const { setTimeout } = require('sdk/timers');
const { Loader } = require('sdk/test/loader');
const wm = Cc['@mozilla.org/appshell/window-mediator;1'].
getService(Ci.nsIWindowMediator);
const { onFocus, getMostRecentWindow, windows } = require('sdk/window/utils');
const { open, close, focus } = require('sdk/window/helpers');
const { browserWindows } = require("sdk/windows");
const tabs = require("sdk/tabs");
const { WindowTracker } = require("sdk/deprecated/window-utils");
const winUtils = require("sdk/deprecated/window-utils");
const { WindowTracker } = winUtils;
const { isPrivate } = require('sdk/private-browsing');
const { isWindowPBSupported } = require('sdk/private-browsing/utils');
@ -269,36 +269,11 @@ exports.testActiveWindow = function(test) {
});
function nextStep() {
if (testSteps.length > 0)
if (testSteps.length)
testSteps.shift()();
}
function continueAfterFocus(targetWindow) {
// Based on SimpleTest.waitForFocus
var fm = Cc["@mozilla.org/focus-manager;1"].
getService(Ci.nsIFocusManager);
var childTargetWindow = {};
fm.getFocusedElementForWindow(targetWindow, true, childTargetWindow);
childTargetWindow = childTargetWindow.value;
var focusedChildWindow = {};
if (fm.activeWindow) {
fm.getFocusedElementForWindow(fm.activeWindow, true, focusedChildWindow);
focusedChildWindow = focusedChildWindow.value;
}
var focused = (focusedChildWindow == childTargetWindow);
if (focused) {
setTimeout(nextStep, 0);
} else {
childTargetWindow.addEventListener("focus", function focusListener() {
childTargetWindow.removeEventListener("focus", focusListener, true);
setTimeout(nextStep, 0);
}, true);
}
}
let continueAfterFocus = function(w) onFocus(w).then(nextStep);
function finishTest() {
window3.close(function() {
@ -381,6 +356,8 @@ exports.testWindowOpenPrivateDefault = function(test) {
url: 'about:mozilla',
isPrivate: true,
onOpen: function(window) {
test.assertEqual();
let tab = window.tabs[0];
tab.once('ready', function() {
test.assertEqual(tab.url, 'about:mozilla', 'opened correct tab');
@ -393,3 +370,42 @@ exports.testWindowOpenPrivateDefault = function(test) {
}
});
}
// test that it is not possible to find a private window in
// windows module's iterator
exports.testWindowIteratorPrivateDefault = function(test) {
test.waitUntilDone();
test.assertEqual(browserWindows.length, 1, 'only one window open');
open('chrome://browser/content/browser.xul', {
features: {
private: true,
chrome: true
}
}).then(function(window) focus(window).then(function() {
// test that there is a private window opened
test.assertEqual(isPrivate(window), isWindowPBSupported, 'there is a private window open');
test.assertStrictEqual(window, winUtils.activeWindow);
test.assertStrictEqual(window, getMostRecentWindow());
test.assert(!isPrivate(browserWindows.activeWindow));
if (isWindowPBSupported) {
test.assertEqual(browserWindows.length, 1, 'only one window in browserWindows');
test.assertEqual(windows().length, 1, 'only one window in windows()');
}
else {
test.assertEqual(browserWindows.length, 2, 'two windows open');
test.assertEqual(windows().length, 2, 'two windows in windows()');
}
test.assertEqual(windows(null, { includePrivate: true }).length, 2);
for each(let window in browserWindows) {
// test that all windows in iterator are not private
test.assert(!isPrivate(window), 'no window in browserWindows is private');
}
close(window).then(test.done.bind(test));
}));
}