mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-24 21:58:06 +00:00
Bug 865135 - Uplift Add-on SDK integration branch to Firefox.
This commit is contained in:
parent
b0b3b72fbd
commit
d05ec00bd9
1
addon-sdk/source/app-extension/bootstrap.js
vendored
1
addon-sdk/source/app-extension/bootstrap.js
vendored
@ -235,6 +235,7 @@ function startup(data, reasonCode) {
|
||||
stopOnError: options.stopOnError,
|
||||
verbose: options.verbose,
|
||||
parseable: options.parseable,
|
||||
checkMemory: options.check_memory,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -76,6 +76,7 @@ We'd like to thank our many Jetpack project contributors! They include:
|
||||
* Hrishikesh Kale
|
||||
* Wes Kocher
|
||||
* Lajos Koszti
|
||||
* Kusanagi Kouichi
|
||||
* [Vladimir Kukushkin](https://github.com/kukushechkin)
|
||||
|
||||
### L ###
|
||||
@ -129,6 +130,7 @@ We'd like to thank our many Jetpack project contributors! They include:
|
||||
* Dan Stevens
|
||||
* [J. Ryan Stinnett](https://github.com/jryans)
|
||||
* [Mihai Sucan](https://github.com/mihaisucan)
|
||||
* Sunny ([darkowlzz](https://github.com/darkowlzz))
|
||||
|
||||
### T ###
|
||||
|
||||
|
@ -94,26 +94,26 @@ Returns the value that is returned by `callee`.
|
||||
Returns the return value of `callee`.
|
||||
</api>
|
||||
|
||||
<api name="curry">
|
||||
<api name="partial">
|
||||
@function
|
||||
[Curries](http://en.wikipedia.org/wiki/Currying) the given function with the arguments given.
|
||||
Takes a function and bind values to one or more arguments, returning a new function of smaller arity.
|
||||
|
||||
let { curry } = require("sdk/lang/functional");
|
||||
let { partial } = require("sdk/lang/functional");
|
||||
let add = function add (x, y) { return x + y; }
|
||||
let addOne = curry(add, 1);
|
||||
let addOne = partial(add, 1);
|
||||
|
||||
addOne(5); // 6
|
||||
addOne(10); // 11
|
||||
curry(add, addOne(20))(2); // 23
|
||||
partial(add, addOne(20))(2); // 23
|
||||
|
||||
@param fn {function}
|
||||
Function to be curried.
|
||||
Function on which partial application is to be performed.
|
||||
|
||||
@param arguments... {mixed}
|
||||
Additional arguments
|
||||
|
||||
@returns {function}
|
||||
The curried function.
|
||||
The partial function.
|
||||
</api>
|
||||
|
||||
<api name="compose">
|
||||
|
346
addon-sdk/source/doc/module-source/sdk/lang/type.md
Normal file
346
addon-sdk/source/doc/module-source/sdk/lang/type.md
Normal file
@ -0,0 +1,346 @@
|
||||
<!-- 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/. -->
|
||||
|
||||
The `lang/type` module provides simple helper functions for working with type
|
||||
detection.
|
||||
|
||||
<api name="isUndefined">
|
||||
@function
|
||||
Returns `true` if `value` is [`undefined`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/undefined), `false` otherwise.
|
||||
|
||||
let { isUndefined } = require('sdk/lang/type');
|
||||
|
||||
var foo;
|
||||
isUndefined(foo); // true
|
||||
isUndefined(0); // false
|
||||
|
||||
@param value {mixed}
|
||||
The variable to check.
|
||||
|
||||
@returns {boolean}
|
||||
Boolean indicating if `value` is `undefined`.
|
||||
</api>
|
||||
|
||||
<api name="isNull">
|
||||
@function
|
||||
Returns `true` if `value` is [`null`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/null), `false` otherwise.
|
||||
|
||||
let { isNull } = require('sdk/lang/type');
|
||||
|
||||
isNull(null); // true
|
||||
isNull(false); // false
|
||||
|
||||
@param value {mixed}
|
||||
The variable to check.
|
||||
|
||||
@returns {boolean}
|
||||
Boolean indicating if `value` is `null`.
|
||||
</api>
|
||||
|
||||
<api name="isString">
|
||||
@function
|
||||
Returns `true` if `value` is a [`String`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String),
|
||||
`false` otherwise. Uses [`typeof`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/typeof)
|
||||
operator to check type, and will only properly detect string primitives:
|
||||
for example, a string created with `new String()` will always return false.
|
||||
|
||||
let { isString } = require('sdk/lang/type');
|
||||
|
||||
isString('my string'); // true
|
||||
isString(100); // false
|
||||
isString('100'); // true
|
||||
|
||||
@param value {mixed}
|
||||
The variable to check.
|
||||
|
||||
@returns {boolean}
|
||||
Boolean indicating if `value` is a `String`.
|
||||
</api>
|
||||
|
||||
<api name="isNumber">
|
||||
@function
|
||||
Returns `true` if `value` is a [`Number`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Number),
|
||||
`false` otherwise. Uses [`typeof`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/typeof)
|
||||
operator to check type, and will only properly detect number primitives:
|
||||
for example, a number created with `new Number()` will always return false.
|
||||
|
||||
let { isNumber } = require('sdk/lang/type');
|
||||
|
||||
isNumber(3.1415); // true
|
||||
isNumber(100); // true
|
||||
isNumber('100'); // false
|
||||
|
||||
@param value {mixed}
|
||||
The variable to check.
|
||||
|
||||
@returns {boolean}
|
||||
Boolean indicating if `value` is a `Number`.
|
||||
</api>
|
||||
|
||||
<api name="isRegExp">
|
||||
@function
|
||||
Returns `true` if `value` is a [`RegExp`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp), `false` otherwise.
|
||||
|
||||
let { isRegExp } = require('sdk/lang/type');
|
||||
|
||||
isRegExp(/[^\.]*\.js$/); // true
|
||||
isRegExp(new RegExp('substring')); // true
|
||||
isRegExp(1000); // false
|
||||
|
||||
@param value {mixed}
|
||||
The variable to check.
|
||||
|
||||
@returns {boolean}
|
||||
Boolean indicating if `value` is a `RegExp`.
|
||||
</api>
|
||||
|
||||
<api name="isDate">
|
||||
@function
|
||||
Returns `true` if `value` is a [`Date`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date), `false` otherwise.
|
||||
|
||||
let { isDate } = require('sdk/lang/type');
|
||||
|
||||
isDate(new Date()); // true
|
||||
isDate('3/1/2013'); // false
|
||||
|
||||
@param value {mixed}
|
||||
The variable to check.
|
||||
|
||||
@returns {boolean}
|
||||
Boolean indicating if `value` is a `Date`.
|
||||
</api>
|
||||
|
||||
<api name="isFunction">
|
||||
@function
|
||||
Returns `true` if `value` is a [`Function`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function), `false` otherwise.
|
||||
|
||||
let { isFunction } = require('sdk/lang/type');
|
||||
|
||||
let fn = function () {};
|
||||
isFunction(fn); // true;
|
||||
isFunction(otherFn); // true;
|
||||
isFunction(function () {}); // true;
|
||||
|
||||
function otherFn () {}
|
||||
|
||||
@param value {mixed}
|
||||
The variable to check.
|
||||
|
||||
@returns {boolean}
|
||||
Boolean indicating if `value` is a `Function`.
|
||||
</api>
|
||||
|
||||
<api name="isObject">
|
||||
@function
|
||||
Returns `true` if `value` is an [`Object`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object) and not null, `false` otherwise.
|
||||
|
||||
let { isObject } = require('sdk/lang/type');
|
||||
|
||||
isObject({}); // true
|
||||
isObject(new Class()); // true
|
||||
isObject(null); // false
|
||||
isObject(5); // false
|
||||
|
||||
function Class () {}
|
||||
|
||||
@param value {mixed}
|
||||
The variable to check.
|
||||
|
||||
@returns {boolean}
|
||||
Boolean indicating if `value` is an `Object`.
|
||||
</api>
|
||||
|
||||
<api name="isArray">
|
||||
@function
|
||||
Returns `true` if `value` is an [`Array`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array), `false` otherwise. Uses native
|
||||
[`Array.isArray`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/isArray).
|
||||
|
||||
let { isArray } = require('sdk/lang/type');
|
||||
|
||||
isArray([]); // true
|
||||
isArray({}); // false
|
||||
|
||||
@param value {mixed}
|
||||
The variable to check.
|
||||
|
||||
@returns {boolean}
|
||||
Boolean indicating if `value` is an `Array`.
|
||||
</api>
|
||||
|
||||
<api name="isArguments">
|
||||
@function
|
||||
Returns `true` if `value` is an array-like [`arguments`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments) object,
|
||||
`false` otherwise.
|
||||
|
||||
let { isArguments } = require('sdk/lang/type');
|
||||
|
||||
function run () {
|
||||
isArguments(arguments); // true
|
||||
isArguments([]); // false
|
||||
isArguments(Array.slice(arguments)); // false
|
||||
}
|
||||
run(1, 2, 3);
|
||||
|
||||
@param value {mixed}
|
||||
The variable to check.
|
||||
|
||||
@returns {boolean}
|
||||
Boolean indicating if `value` is an `arguments` object.
|
||||
</api>
|
||||
|
||||
<api name="isPrimitive">
|
||||
@function
|
||||
Returns `true` if `value` is a primitive value: that is, any of [`null`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/null), [`undefined`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/undefined), [`number`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/number),
|
||||
[`boolean`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/boolean), or [`string`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/string). Returns `false` if `value` is not a primitive value.
|
||||
|
||||
let { isPrimitive } = require('sdk/lang/type');
|
||||
|
||||
isPrimitive(3); // true
|
||||
isPrimitive('foo'); // true
|
||||
isPrimitive({}); // false
|
||||
|
||||
@param value {mixed}
|
||||
The variable to check.
|
||||
|
||||
@returns {boolean}
|
||||
Boolean indicating if `value` is a primitive.
|
||||
</api>
|
||||
|
||||
<api name="isFlat">
|
||||
@function
|
||||
Returns `true` if `value` is a direct descendant of `Object.prototype` or `null`.
|
||||
Similar to jQuery's [`isPlainObject`](http://api.jquery.com/jQuery.isPlainObject/).
|
||||
|
||||
let { isFlat } = require('sdk/lang/type');
|
||||
|
||||
isFlat({}); // true
|
||||
isFlat(new Type()); // false
|
||||
|
||||
function Type () {}
|
||||
|
||||
@param value {mixed}
|
||||
The variable to check.
|
||||
|
||||
@returns {boolean}
|
||||
Boolean indicating if `value` is a direct descendant of `Object.prototype` or `null`.
|
||||
</api>
|
||||
|
||||
<api name="isEmpty">
|
||||
@function
|
||||
Returns `true` if `value` is an [`Object`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object) with no properties and `false` otherwise.
|
||||
|
||||
let { isEmpty } = require('sdk/lang/type');
|
||||
|
||||
isEmpty({}); // true
|
||||
isEmpty({ init: false }); // false
|
||||
|
||||
@param value {object}
|
||||
The variable to check.
|
||||
|
||||
@returns {boolean}
|
||||
Boolean indicating if `value` is an `Object` with no properties.
|
||||
</api>
|
||||
|
||||
<api name="isJSON">
|
||||
@function
|
||||
Returns `true` if `value` is a string, number, boolean, null, array of JSON-serializable values, or an object whose property values are themselves JSON-serializable. Returns `false` otherwise.
|
||||
|
||||
let { isJSON } = require('sdk/lang/type');
|
||||
|
||||
isJSON({ value: 42 }); // true
|
||||
isJSON({ fn: function () {} ); // false
|
||||
|
||||
@param value {mixed}
|
||||
The variable to check.
|
||||
|
||||
@returns {boolean}
|
||||
Boolean indicating if `value` is an `Array`/flat `Object` containing only
|
||||
atomic values and other flat objects.
|
||||
</api>
|
||||
|
||||
<api name="instanceOf">
|
||||
@function
|
||||
Returns `true` if `value` is an instance of a given `Type`. This is similar to the [`instanceof`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/instanceof) operator.
|
||||
The difference is that the `Type` constructor can be from a scope that has
|
||||
a different top level object: for example, it could be from a different iframe,
|
||||
module or sandbox.
|
||||
|
||||
let { instanceOf } = require('sdk/lang/type');
|
||||
|
||||
instanceOf(new Class(), Class); // true
|
||||
function Class() {}
|
||||
|
||||
@param value {object}
|
||||
The variable to check.
|
||||
|
||||
@param Type {object}
|
||||
The constructor to compare to `value`
|
||||
|
||||
@returns {boolean}
|
||||
Boolean indicating if `value` is an instance of `Type`.
|
||||
</api>
|
||||
|
||||
<api name="source">
|
||||
@function
|
||||
Returns the textual representation of `value`, containing property descriptors and types
|
||||
of properties contained within the object.
|
||||
|
||||
let { source } = require('sdk/lang/type');
|
||||
|
||||
var obj = {
|
||||
name: undefined,
|
||||
twitter: '@horse_js',
|
||||
tweets: [
|
||||
{ id: 100, text: 'What happens to you if you break the monad laws?' },
|
||||
{ id: 101, text: 'JAVASCRIPT DUBSTEP GENERATOR' }
|
||||
]
|
||||
};
|
||||
|
||||
console.log(source(obj));
|
||||
// Prints the below
|
||||
/*
|
||||
{ // [object Object]
|
||||
// writable configurable enumerable
|
||||
name: undefined,
|
||||
// writable configurable enumerable
|
||||
twitter: "@horse_js",
|
||||
// writable configurable enumerable
|
||||
tweets: [
|
||||
{ // [object Object]
|
||||
// writable configurable enumerable
|
||||
id: 100,
|
||||
// writable configurable enumerable
|
||||
text: "What happens to you if you break the monad laws?",
|
||||
"__proto__": { // [object Object]
|
||||
|
||||
}
|
||||
},
|
||||
{ // [object Object]
|
||||
// writable configurable enumerable
|
||||
id: 101,
|
||||
// writable configurable enumerable
|
||||
text: "JAVASCRIPT DUBSTEP GENERATOR",
|
||||
"__proto__": { // [object Object]
|
||||
|
||||
}
|
||||
}
|
||||
],
|
||||
"__proto__": { // [object Object]
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@param value {mixed}
|
||||
The source object to create a textual representation of.
|
||||
|
||||
@param indent {string}
|
||||
Optional. `String` to be used as indentation in output. 4 spaces by default.
|
||||
|
||||
@param limit {number}
|
||||
Optional. Number of properties to display per object.
|
||||
|
||||
@returns {string}
|
||||
The textual representation of `value`.
|
||||
</api>
|
@ -192,6 +192,11 @@ registration.
|
||||
Tabs emit all the events described in the Events section. Listeners are
|
||||
passed the `Tab` object that triggered the event.
|
||||
|
||||
<api name="id">
|
||||
@property {string}
|
||||
The unique id for the tab. This property is read-only.
|
||||
</api>
|
||||
|
||||
<api name="title">
|
||||
@property {string}
|
||||
The title of the tab (usually the title of the page currently loaded in the tab)
|
||||
|
@ -17,4 +17,4 @@ const { isBrowser } = require("../window/utils");
|
||||
// implementation for `isBrowser`. Either way it's not really needed yet
|
||||
// neither window tracker provides this event.
|
||||
|
||||
exports.events = filter(function({target}) isBrowser(target), events);
|
||||
exports.events = filter(events, function({target}) isBrowser(target));
|
||||
|
@ -13,7 +13,7 @@ const self = require("../self");
|
||||
const traceback = require("./traceback")
|
||||
const prefs = require("../preferences/service");
|
||||
const { merge } = require("../util/object");
|
||||
const { curry } = require("../lang/functional");
|
||||
const { partial } = require("../lang/functional");
|
||||
|
||||
const LEVELS = {
|
||||
"all": Number.MIN_VALUE,
|
||||
@ -102,13 +102,13 @@ function PlainTextConsole(print) {
|
||||
}
|
||||
|
||||
merge(this, {
|
||||
log: curry(message, print, "info"),
|
||||
info: curry(message, print, "info"),
|
||||
warn: curry(message, print, "warn"),
|
||||
error: curry(message, print, "error"),
|
||||
debug: curry(message, print, "debug"),
|
||||
exception: curry(errorMessage, print),
|
||||
trace: curry(traceMessage, print),
|
||||
log: partial(message, print, "info"),
|
||||
info: partial(message, print, "info"),
|
||||
warn: partial(message, print, "warn"),
|
||||
error: partial(message, print, "error"),
|
||||
debug: partial(message, print, "debug"),
|
||||
exception: partial(errorMessage, print),
|
||||
trace: partial(traceMessage, print),
|
||||
|
||||
dir: function dir() {},
|
||||
group: function group() {},
|
||||
|
@ -19,8 +19,7 @@ function initialize(instance) {
|
||||
// Create an event handler that will dispose instance on unload.
|
||||
function handler(event) {
|
||||
if (event.subject.wrappedJSObject === unloadSubject) {
|
||||
dispose(instance);
|
||||
instance.dispose();
|
||||
instance.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,8 +65,10 @@ let Disposable = Class({
|
||||
destroy: function destroy() {
|
||||
// Destroying disposable removes unload handler so that attempt to dispose
|
||||
// won't be made at unload & delegates to dispose.
|
||||
dispose(this);
|
||||
this.dispose();
|
||||
if (disposables.has(this)) {
|
||||
dispose(this);
|
||||
this.dispose();
|
||||
}
|
||||
}
|
||||
});
|
||||
exports.Disposable = Disposable;
|
||||
|
@ -25,7 +25,7 @@ let refs = (function() {
|
||||
}
|
||||
})();
|
||||
|
||||
function transform(f, input) {
|
||||
function transform(input, f) {
|
||||
let output = {};
|
||||
|
||||
// Since event listeners don't prevent `input` to be GC-ed we wanna presrve
|
||||
@ -46,16 +46,16 @@ function transform(f, input) {
|
||||
// High order event transformation function that takes `input` event channel
|
||||
// and returns transformation containing only events on which `p` predicate
|
||||
// returns `true`.
|
||||
function filter(predicate, input) {
|
||||
return transform(function(data, next) {
|
||||
function filter(input, predicate) {
|
||||
return transform(input, function(data, next) {
|
||||
if (predicate(data)) next(data)
|
||||
}, input);
|
||||
});
|
||||
}
|
||||
exports.filter = filter;
|
||||
|
||||
// High order function that takes `input` and returns input of it's values
|
||||
// mapped via given `f` function.
|
||||
function map(f, input) transform(function(data, next) next(f(data)), input)
|
||||
function map(input, f) transform(input, function(data, next) next(f(data)))
|
||||
exports.map = map;
|
||||
|
||||
// High order function that takes `input` stream of streams and merges them
|
||||
@ -97,7 +97,7 @@ function merge(inputs) {
|
||||
}
|
||||
exports.merge = merge;
|
||||
|
||||
function expand(f, inputs) merge(map(f, inputs))
|
||||
function expand(inputs, f) merge(map(inputs, f))
|
||||
exports.expand = expand;
|
||||
|
||||
function pipe(from, to) on(from, "*", emit.bind(emit, to))
|
||||
|
@ -13,6 +13,7 @@ module.metadata = {
|
||||
};
|
||||
|
||||
const { setTimeout } = require("../timers");
|
||||
const { deprecateFunction } = require("../util/deprecate");
|
||||
|
||||
/**
|
||||
* Takes `lambda` function and returns a method. When returned method is
|
||||
@ -55,14 +56,15 @@ function invoke(callee, params, self) callee.apply(self, params);
|
||||
exports.invoke = invoke;
|
||||
|
||||
/**
|
||||
* Curries a function with the arguments given.
|
||||
* Takes a function and bind values to one or more arguments, returning a new
|
||||
* function of smaller arity.
|
||||
*
|
||||
* @param {Function} fn
|
||||
* The function to curry
|
||||
* The function to partial
|
||||
*
|
||||
* @returns The function curried
|
||||
* @returns The new function with binded values
|
||||
*/
|
||||
function curry(fn) {
|
||||
function partial(fn) {
|
||||
if (typeof fn !== "function")
|
||||
throw new TypeError(String(fn) + " is not a function");
|
||||
|
||||
@ -70,7 +72,12 @@ function curry(fn) {
|
||||
|
||||
return function() fn.apply(this, args.concat(Array.slice(arguments)));
|
||||
}
|
||||
exports.curry = curry;
|
||||
exports.partial = partial;
|
||||
|
||||
exports.curry = deprecateFunction(partial,
|
||||
'curry is deprecated, ' +
|
||||
'please use require("sdk/lang/functional").partial instead.'
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns the composition of a list of functions, where each function consumes
|
||||
|
@ -63,9 +63,15 @@ function incompatibility(module) {
|
||||
|
||||
let applications = Object.keys(engines);
|
||||
|
||||
applications.forEach(xulappModule.is);
|
||||
|
||||
let versionRange = engines[xulappModule.name];
|
||||
let versionRange;
|
||||
applications.forEach(function(name) {
|
||||
if (xulappModule.is(name)) {
|
||||
versionRange = engines[name];
|
||||
// Continue iteration. We want to ensure the module doesn't
|
||||
// contain a typo in the applications' name or some unknown
|
||||
// application - `is` function throws an exception in that case.
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof(versionRange) === "string") {
|
||||
if (xulappModule.satisfiesVersion(versionRange))
|
||||
|
@ -1,7 +1,6 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
module.metadata = {
|
||||
@ -64,7 +63,8 @@ var getRequestCount = exports.getRequestCount = function getRequestCount() {
|
||||
};
|
||||
|
||||
var XMLHttpRequest = exports.XMLHttpRequest = function XMLHttpRequest() {
|
||||
var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
let self = this;
|
||||
let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance(Ci.nsIXMLHttpRequest);
|
||||
// For the sake of simplicity, don't tie this request to any UI.
|
||||
req.mozBackgroundRequest = true;
|
||||
@ -73,31 +73,25 @@ var XMLHttpRequest = exports.XMLHttpRequest = function XMLHttpRequest() {
|
||||
|
||||
this._req = req;
|
||||
this._orsc = null;
|
||||
this._cleanup = this._cleanup.bind(this);
|
||||
|
||||
requests.push(this);
|
||||
|
||||
var self = this;
|
||||
|
||||
this._boundCleanup = function _boundCleanup() {
|
||||
self._cleanup();
|
||||
};
|
||||
|
||||
TERMINATE_EVENTS.forEach(
|
||||
function(name) {
|
||||
self._req.addEventListener(name, self._boundCleanup, false);
|
||||
});
|
||||
TERMINATE_EVENTS.forEach(function(name) {
|
||||
self._req.addEventListener(name, self._cleanup, false);
|
||||
});
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype = {
|
||||
_cleanup: function _cleanup() {
|
||||
this.onreadystatechange = null;
|
||||
var index = requests.indexOf(this);
|
||||
|
||||
let index = requests.indexOf(this);
|
||||
if (index != -1) {
|
||||
var self = this;
|
||||
TERMINATE_EVENTS.forEach(
|
||||
function(name) {
|
||||
self._req.removeEventListener(name, self._boundCleanup, false);
|
||||
});
|
||||
let self = this;
|
||||
TERMINATE_EVENTS.forEach(function(name) {
|
||||
self._req.removeEventListener(name, self._cleanup, false);
|
||||
});
|
||||
requests.splice(index, 1);
|
||||
}
|
||||
},
|
||||
@ -105,11 +99,11 @@ XMLHttpRequest.prototype = {
|
||||
this._req.abort();
|
||||
this._cleanup();
|
||||
},
|
||||
addEventListener: function addEventListener() {
|
||||
throw new Error("not implemented");
|
||||
addEventListener: function addEventListener(name, func) {
|
||||
this._req.addEventListener(name, func);
|
||||
},
|
||||
removeEventListener: function removeEventListener() {
|
||||
throw new Error("not implemented");
|
||||
removeEventListener: function removeEventListener(name, func) {
|
||||
this._req.removeEventListener(name, func);
|
||||
},
|
||||
set upload(newValue) {
|
||||
throw new Error("not implemented");
|
||||
@ -128,12 +122,15 @@ XMLHttpRequest.prototype = {
|
||||
this._req.onreadystatechange = function() {
|
||||
try {
|
||||
self._orsc.apply(self, arguments);
|
||||
} catch (e) {
|
||||
}
|
||||
catch (e) {
|
||||
console.exception(e);
|
||||
}
|
||||
};
|
||||
} else
|
||||
}
|
||||
else {
|
||||
this._req.onreadystatechange = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -32,9 +32,6 @@ const { filter, pipe } = require("./event/utils");
|
||||
const { getNodeView, getActiveView } = require("./view/core");
|
||||
const { isNil, isObject } = require("./lang/type");
|
||||
|
||||
if (isPrivateBrowsingSupported && isWindowPBSupported)
|
||||
throw Error('The panel module cannot be used with per-window private browsing at the moment, see Bug 816257');
|
||||
|
||||
let isArray = Array.isArray;
|
||||
let assetsURI = require("./self").data.url();
|
||||
|
||||
@ -251,24 +248,24 @@ const Panel = Class({
|
||||
exports.Panel = Panel;
|
||||
|
||||
// Filter panel events to only panels that are create by this module.
|
||||
let panelEvents = filter(function({target}) panelFor(target), events);
|
||||
let panelEvents = filter(events, function({target}) panelFor(target));
|
||||
|
||||
// Panel events emitted after panel has being shown.
|
||||
let shows = filter(function({type}) type === "sdk-panel-shown", panelEvents);
|
||||
let shows = filter(panelEvents, function({type}) type === "sdk-panel-shown");
|
||||
|
||||
// Panel events emitted after panel became hidden.
|
||||
let hides = filter(function({type}) type === "sdk-panel-hidden", panelEvents);
|
||||
let hides = filter(panelEvents, function({type}) type === "sdk-panel-hidden");
|
||||
|
||||
// Panel events emitted after content inside panel is ready. For different
|
||||
// panels ready may mean different state based on `contentScriptWhen` attribute.
|
||||
// Weather given event represents readyness is detected by `getAttachEventType`
|
||||
// helper function.
|
||||
let ready = filter(function({type, target})
|
||||
getAttachEventType(modelFor(panelFor(target))) === type, panelEvents);
|
||||
let ready = filter(panelEvents, function({type, target})
|
||||
getAttachEventType(modelFor(panelFor(target))) === type);
|
||||
|
||||
// Panel events emitted after content document in the panel has changed.
|
||||
let change = filter(function({type}) type === "sdk-panel-content-changed",
|
||||
panelEvents);
|
||||
let change = filter(panelEvents, function({type})
|
||||
type === "sdk-panel-content-changed");
|
||||
|
||||
// Forward panel show / hide events to panel's own event listeners.
|
||||
on(shows, "data", function({target}) emit(panelFor(target), "show"));
|
||||
|
@ -39,13 +39,13 @@ function tabEventsFor(window) {
|
||||
}
|
||||
|
||||
// Filter DOMContentLoaded events from all the browser events.
|
||||
let readyEvents = filter(function(e) e.type === "DOMContentLoaded", events);
|
||||
let readyEvents = filter(events, function(e) e.type === "DOMContentLoaded");
|
||||
// Map DOMContentLoaded events to it's target browser windows.
|
||||
let futureWindows = map(function(e) e.target, readyEvents);
|
||||
let futureWindows = map(readyEvents, function(e) e.target);
|
||||
// Expand all browsers that will become interactive to supported tab events
|
||||
// on these windows. Result will be a tab events from all tabs of all windows
|
||||
// that will become interactive.
|
||||
let eventsFromFuture = expand(tabEventsFor, futureWindows);
|
||||
let eventsFromFuture = expand(futureWindows, tabEventsFor);
|
||||
|
||||
// Above covers only windows that will become interactive in a future, but some
|
||||
// windows may already be interactive so we pick those and expand to supported
|
||||
|
@ -57,6 +57,9 @@ var results = {
|
||||
testRuns: []
|
||||
};
|
||||
|
||||
// A list of the compartments and windows loaded after startup
|
||||
var startLeaks;
|
||||
|
||||
// JSON serialization of last memory usage stats; we keep it stringified
|
||||
// so we don't actually change the memory usage stats (in terms of objects)
|
||||
// of the JSRuntime we're profiling.
|
||||
@ -162,9 +165,32 @@ function reportMemoryUsage() {
|
||||
|
||||
var gWeakrefInfo;
|
||||
|
||||
function showResults() {
|
||||
function checkMemory() {
|
||||
memory.gc();
|
||||
setTimeout(function () {
|
||||
memory.gc();
|
||||
setTimeout(function () {
|
||||
let leaks = getPotentialLeaks();
|
||||
let compartmentURLs = Object.keys(leaks.compartments).filter(function(url) {
|
||||
return !(url in startLeaks.compartments);
|
||||
});
|
||||
|
||||
let windowURLs = Object.keys(leaks.windows).filter(function(url) {
|
||||
return !(url in startLeaks.windows);
|
||||
});
|
||||
|
||||
for (let url of compartmentURLs)
|
||||
console.warn("LEAKED", leaks.compartments[url]);
|
||||
|
||||
for (let url of windowURLs)
|
||||
console.warn("LEAKED", leaks.windows[url]);
|
||||
|
||||
showResults();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function showResults() {
|
||||
if (gWeakrefInfo) {
|
||||
gWeakrefInfo.forEach(
|
||||
function(info) {
|
||||
@ -227,7 +253,7 @@ function cleanup() {
|
||||
console.exception(e);
|
||||
};
|
||||
|
||||
setTimeout(showResults, 1);
|
||||
setTimeout(require('@test/options').checkMemory ? checkMemory : showResults, 1);
|
||||
|
||||
// dump the coverobject
|
||||
if (Object.keys(coverObject).length){
|
||||
@ -245,6 +271,123 @@ function cleanup() {
|
||||
}
|
||||
}
|
||||
|
||||
function getPotentialLeaks() {
|
||||
memory.gc();
|
||||
|
||||
// Things we can assume are part of the platform and so aren't leaks
|
||||
let WHITELIST_BASE_URLS = [
|
||||
"chrome://",
|
||||
"resource:///",
|
||||
"resource://app/",
|
||||
"resource://gre/",
|
||||
"resource://gre-resources/",
|
||||
"resource://pdf.js/",
|
||||
"resource://pdf.js.components/",
|
||||
"resource://services-common/",
|
||||
"resource://services-crypto/",
|
||||
"resource://services-sync/"
|
||||
];
|
||||
|
||||
let ioService = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
let uri = ioService.newURI("chrome://global/content/", "UTF-8", null);
|
||||
let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].
|
||||
getService(Ci.nsIChromeRegistry);
|
||||
uri = chromeReg.convertChromeURL(uri);
|
||||
let spec = uri.spec;
|
||||
let pos = spec.indexOf("!/");
|
||||
WHITELIST_BASE_URLS.push(spec.substring(0, pos + 2));
|
||||
|
||||
let compartmentRegexp = new RegExp("^explicit/js-non-window/compartments/non-window-global/compartment\\((.+)\\)/");
|
||||
let compartmentDetails = new RegExp("^([^,]+)(?:, (.+?))?(?: \\(from: (.*)\\))?$");
|
||||
let windowRegexp = new RegExp("^explicit/window-objects/top\\((.*)\\)/active");
|
||||
let windowDetails = new RegExp("^(.*), id=.*$");
|
||||
|
||||
function isPossibleLeak(item) {
|
||||
if (!item.location)
|
||||
return false;
|
||||
|
||||
for (let whitelist of WHITELIST_BASE_URLS) {
|
||||
if (item.location.substring(0, whitelist.length) == whitelist)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
let compartments = {};
|
||||
let windows = {};
|
||||
function logReporter(process, path, kind, units, amount, description) {
|
||||
let matches = compartmentRegexp.exec(path);
|
||||
if (matches) {
|
||||
if (matches[1] in compartments)
|
||||
return;
|
||||
|
||||
let details = compartmentDetails.exec(matches[1]);
|
||||
if (!details) {
|
||||
console.error("Unable to parse compartment detail " + matches[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
let item = {
|
||||
path: matches[1],
|
||||
principal: details[1],
|
||||
location: details[2] ? details[2].replace("\\", "/", "g") : undefined,
|
||||
source: details[3] ? details[3].split(" -> ").reverse() : undefined,
|
||||
toString: function() this.location
|
||||
};
|
||||
|
||||
if (!isPossibleLeak(item))
|
||||
return;
|
||||
|
||||
compartments[matches[1]] = item;
|
||||
return;
|
||||
}
|
||||
|
||||
matches = windowRegexp.exec(path);
|
||||
if (matches) {
|
||||
if (matches[1] in windows)
|
||||
return;
|
||||
|
||||
let details = windowDetails.exec(matches[1]);
|
||||
if (!details) {
|
||||
console.error("Unable to parse window detail " + matches[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
let item = {
|
||||
path: matches[1],
|
||||
location: details[1].replace("\\", "/", "g"),
|
||||
source: [details[1].replace("\\", "/", "g")],
|
||||
toString: function() this.location
|
||||
};
|
||||
|
||||
if (!isPossibleLeak(item))
|
||||
return;
|
||||
|
||||
windows[matches[1]] = item;
|
||||
}
|
||||
}
|
||||
|
||||
let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
|
||||
getService(Ci.nsIMemoryReporterManager);
|
||||
|
||||
let enm = mgr.enumerateReporters();
|
||||
while (enm.hasMoreElements()) {
|
||||
let reporter = enm.getNext().QueryInterface(Ci.nsIMemoryReporter);
|
||||
logReporter(reporter.process, reporter.path, reporter.kind, reporter.units,
|
||||
reporter.amount, reporter.description);
|
||||
}
|
||||
|
||||
let enm = mgr.enumerateMultiReporters();
|
||||
while (enm.hasMoreElements()) {
|
||||
let mr = enm.getNext().QueryInterface(Ci.nsIMemoryMultiReporter);
|
||||
mr.collectReports(logReporter, null);
|
||||
}
|
||||
|
||||
return { compartments: compartments, windows: windows };
|
||||
}
|
||||
|
||||
function nextIteration(tests) {
|
||||
if (tests) {
|
||||
results.passed += tests.passed;
|
||||
@ -440,6 +583,12 @@ var runTests = exports.runTests = function runTests(options) {
|
||||
global: {} // useful for storing things like coverage testing.
|
||||
});
|
||||
|
||||
// Load these before getting initial leak stats as they will still be in
|
||||
// memory when we check later
|
||||
require("../deprecated/unit-test");
|
||||
require("../deprecated/unit-test-finder");
|
||||
startLeaks = getPotentialLeaks();
|
||||
|
||||
nextIteration();
|
||||
} catch (e) {
|
||||
let frames = fromException(e).reverse().reduce(function(frames, frame) {
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
const { Loader, resolveURI, Require,
|
||||
unload, override, descriptor } = require('../loader/cuddlefish');
|
||||
const { ensure } = require('../system/unload');
|
||||
const addonWindow = require('../addon/window');
|
||||
const { PlainTextConsole } = require("sdk/console/plain-text");
|
||||
|
||||
@ -19,7 +20,7 @@ function CustomLoader(module, globals, packaging) {
|
||||
});
|
||||
|
||||
let loader = Loader(options);
|
||||
return Object.create(loader, descriptor({
|
||||
let wrapper = Object.create(loader, descriptor({
|
||||
require: Require(loader, module),
|
||||
sandbox: function(id) {
|
||||
let requirement = loader.resolve(id, module.id);
|
||||
@ -30,6 +31,8 @@ function CustomLoader(module, globals, packaging) {
|
||||
unload(loader, reason);
|
||||
}
|
||||
}));
|
||||
ensure(wrapper);
|
||||
return wrapper;
|
||||
};
|
||||
exports.Loader = CustomLoader;
|
||||
|
||||
|
@ -228,6 +228,12 @@ parser_groups = (
|
||||
metavar=None,
|
||||
default=False,
|
||||
cmds=['sdocs'])),
|
||||
(("", "--check-memory",), dict(dest="check_memory",
|
||||
help="attempts to detect leaked compartments after a test run",
|
||||
action="store_true",
|
||||
default=False,
|
||||
cmds=['test', 'testpkgs', 'testaddons',
|
||||
'testall'])),
|
||||
]
|
||||
),
|
||||
|
||||
@ -660,7 +666,7 @@ def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None,
|
||||
# a Mozilla application (which includes running tests).
|
||||
|
||||
use_main = False
|
||||
inherited_options = ['verbose', 'enable_e10s', 'parseable']
|
||||
inherited_options = ['verbose', 'enable_e10s', 'parseable', 'check_memory']
|
||||
enforce_timeouts = False
|
||||
|
||||
if command == "xpi":
|
||||
|
@ -1,16 +1,83 @@
|
||||
'use strict';
|
||||
|
||||
const { isWindowPBSupported } = require('sdk/private-browsing/utils');
|
||||
const { open, focus, close } = require('sdk/window/helpers');
|
||||
const { isPrivate } = require('sdk/private-browsing');
|
||||
const { defer } = require('sdk/core/promise');
|
||||
|
||||
if (isWindowPBSupported) {
|
||||
exports.testRequirePanel = function (assert) {
|
||||
try {
|
||||
require('panel');
|
||||
const BROWSER = 'chrome://browser/content/browser.xul';
|
||||
|
||||
exports.testRequirePanel = function(assert) {
|
||||
require('panel');
|
||||
assert.ok('the panel module should not throw an error');
|
||||
};
|
||||
|
||||
exports.testShowPanelInPrivateWindow = function(assert, done) {
|
||||
let panel = require('sdk/panel').Panel({
|
||||
contentURL: "data:text/html;charset=utf-8,"
|
||||
});
|
||||
|
||||
testShowPanel(assert, panel).
|
||||
then(makeEmptyPrivateBrowserWindow).
|
||||
then(focus).
|
||||
then(function(window) {
|
||||
assert.equal(isPrivate(window), true, 'opened window is private');
|
||||
assert.pass('private window was focused');
|
||||
return window;
|
||||
}).
|
||||
then(function(window) {
|
||||
let { promise, resolve } = defer();
|
||||
|
||||
assert.ok(!panel.isShowing, 'the panel is not showing [1]');
|
||||
|
||||
panel.once('show', function() {
|
||||
assert.ok(panel.isShowing, 'the panel is showing');
|
||||
|
||||
panel.once('hide', function() {
|
||||
assert.ok(!panel.isShowing, 'the panel is not showing [2]');
|
||||
|
||||
resolve(window);
|
||||
});
|
||||
|
||||
panel.hide();
|
||||
});
|
||||
|
||||
panel.show();
|
||||
|
||||
return promise;
|
||||
}).
|
||||
then(close).
|
||||
then(done, assert.fail.bind(assert));
|
||||
};
|
||||
|
||||
|
||||
function makeEmptyPrivateBrowserWindow(options) {
|
||||
options = options || {};
|
||||
return open(BROWSER, {
|
||||
features: {
|
||||
chrome: true,
|
||||
toolbar: true,
|
||||
private: true
|
||||
}
|
||||
catch(e) {
|
||||
assert.ok(e.message.match(/Bug 816257/), 'Bug 816257 is mentioned');
|
||||
return;
|
||||
}
|
||||
assert.fail('the panel module should throw an error');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testShowPanel(assert, panel) {
|
||||
let { promise, resolve } = defer();
|
||||
|
||||
assert.ok(!panel.isShowing, 'the panel is not showing [1]');
|
||||
|
||||
panel.once('show', function() {
|
||||
assert.ok(panel.isShowing, 'the panel is showing');
|
||||
|
||||
panel.once('hide', function() {
|
||||
assert.ok(!panel.isShowing, 'the panel is not showing [2]');
|
||||
|
||||
resolve(null);
|
||||
});
|
||||
|
||||
panel.hide();
|
||||
})
|
||||
panel.show();
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ const { loader } = LoaderWithHookedConsole(module);
|
||||
const pb = loader.require('sdk/private-browsing');
|
||||
const pbUtils = loader.require('sdk/private-browsing/utils');
|
||||
const xulApp = require("sdk/system/xul-app");
|
||||
const { openDialog, getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
const { open: openWindow, getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
const { openTab, getTabContentWindow, getActiveTab, setTabURL, closeTab } = require('sdk/tabs/utils');
|
||||
const promise = require("sdk/core/promise");
|
||||
const windowHelpers = require('sdk/window/helpers');
|
||||
@ -58,6 +58,7 @@ exports.openWebpage = function openWebpage(url, enablePrivate) {
|
||||
let rawTab = openTab(chromeWindow, url, {
|
||||
isPrivate: enablePrivate
|
||||
});
|
||||
|
||||
return {
|
||||
ready: promise.resolve(getTabContentWindow(rawTab)),
|
||||
close: function () {
|
||||
@ -68,8 +69,10 @@ exports.openWebpage = function openWebpage(url, enablePrivate) {
|
||||
};
|
||||
}
|
||||
else {
|
||||
let win = openDialog({
|
||||
private: enablePrivate
|
||||
let win = openWindow(null, {
|
||||
features: {
|
||||
private: enablePrivate
|
||||
}
|
||||
});
|
||||
let deferred = promise.defer();
|
||||
|
||||
@ -77,7 +80,8 @@ exports.openWebpage = function openWebpage(url, enablePrivate) {
|
||||
// that the window is really ready
|
||||
events.on("browser-delayed-startup-finished", function onReady({subject}) {
|
||||
if (subject == win) {
|
||||
events.off("browser-delayed-startup-finished", onReady, true);
|
||||
events.off("browser-delayed-startup-finished", onReady);
|
||||
deferred.resolve(win);
|
||||
|
||||
let rawTab = getActiveTab(win);
|
||||
setTabURL(rawTab, url);
|
||||
|
@ -192,33 +192,6 @@ exports.testTabLocation = function(test) {
|
||||
});
|
||||
};
|
||||
|
||||
// TEST: tab.reload()
|
||||
exports.testTabReload = function(test) {
|
||||
test.waitUntilDone();
|
||||
|
||||
let url = "data:text/html;charset=utf-8,<!doctype%20html><title></title>";
|
||||
|
||||
tabs.open({
|
||||
url: url,
|
||||
onReady: function onReady(tab) {
|
||||
tab.removeListener('ready', onReady);
|
||||
|
||||
tab.once(
|
||||
'ready',
|
||||
function onReload() {
|
||||
test.pass("the tab was loaded again");
|
||||
test.assertEqual(tab.url, url, "the tab has the same URL");
|
||||
|
||||
// end test
|
||||
tab.close(function() test.done());
|
||||
}
|
||||
);
|
||||
|
||||
tab.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// TEST: tab.move()
|
||||
exports.testTabMove = function(test) {
|
||||
test.waitUntilDone();
|
||||
|
@ -300,39 +300,6 @@ exports.testTabClose = function(test) {
|
||||
});
|
||||
};
|
||||
|
||||
// TEST: tab.reload()
|
||||
exports.testTabReload = function(test) {
|
||||
test.waitUntilDone();
|
||||
openBrowserWindow(function(window, browser) {
|
||||
let tabs = require("sdk/tabs");
|
||||
let url = "data:text/html;charset=utf-8,<!doctype%20html><title></title>";
|
||||
|
||||
tabs.open({ url: url, onReady: function onReady(tab) {
|
||||
tab.removeListener("ready", onReady);
|
||||
|
||||
browser.addEventListener(
|
||||
"load",
|
||||
function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
|
||||
browser.addEventListener(
|
||||
"load",
|
||||
function onReload() {
|
||||
browser.removeEventListener("load", onReload, true);
|
||||
test.pass("the tab was loaded again");
|
||||
test.assertEqual(tab.url, url, "the tab has the same URL");
|
||||
closeBrowserWindow(window, function() test.done());
|
||||
},
|
||||
true
|
||||
);
|
||||
tab.reload();
|
||||
},
|
||||
true
|
||||
);
|
||||
}});
|
||||
});
|
||||
};
|
||||
|
||||
// TEST: tab.move()
|
||||
exports.testTabMove = function(test) {
|
||||
test.waitUntilDone();
|
||||
|
@ -9,6 +9,7 @@ let { Cc, Ci } = require("chrome");
|
||||
|
||||
const { Loader } = require('sdk/test/loader');
|
||||
const timer = require("sdk/timers");
|
||||
const { merge } = require("sdk/util/object");
|
||||
|
||||
// These should match the same constants in the module.
|
||||
const ITEM_CLASS = "addon-context-menu-item";
|
||||
@ -1944,6 +1945,7 @@ exports.testParentMenu = function (test) {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// Existing context menu modifications should apply to new windows.
|
||||
exports.testNewWindow = function (test) {
|
||||
test = new TestHelper(test);
|
||||
@ -1981,6 +1983,73 @@ exports.testNewWindowMultipleModules = function (test) {
|
||||
};
|
||||
|
||||
|
||||
// Existing context menu modifications should not apply to new private windows.
|
||||
exports.testNewPrivateWindow = function (test) {
|
||||
test = new TestHelper(test);
|
||||
let loader = test.newLoader();
|
||||
|
||||
let item = new loader.cm.Item({ label: "item" });
|
||||
|
||||
test.showMenu(null, function (popup) {
|
||||
test.checkMenu([item], [], []);
|
||||
popup.hidePopup();
|
||||
|
||||
test.withNewPrivateWindow(function () {
|
||||
test.showMenu(null, function (popup) {
|
||||
test.checkMenu([], [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// Existing context menu modifications should apply to new private windows when
|
||||
// private browsing support is enabled.
|
||||
exports.testNewPrivateEnabledWindow = function (test) {
|
||||
test = new TestHelper(test);
|
||||
let loader = test.newPrivateLoader();
|
||||
|
||||
let item = new loader.cm.Item({ label: "item" });
|
||||
|
||||
test.showMenu(null, function (popup) {
|
||||
test.checkMenu([item], [], []);
|
||||
popup.hidePopup();
|
||||
|
||||
test.withNewPrivateWindow(function () {
|
||||
test.showMenu(null, function (popup) {
|
||||
test.checkMenu([item], [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// Existing context menu modifications should apply to new private windows when
|
||||
// private browsing support is enabled unless unloaded.
|
||||
exports.testNewPrivateEnabledWindowUnloaded = function (test) {
|
||||
test = new TestHelper(test);
|
||||
let loader = test.newPrivateLoader();
|
||||
|
||||
let item = new loader.cm.Item({ label: "item" });
|
||||
|
||||
test.showMenu(null, function (popup) {
|
||||
test.checkMenu([item], [], []);
|
||||
popup.hidePopup();
|
||||
|
||||
loader.unload();
|
||||
|
||||
test.withNewPrivateWindow(function () {
|
||||
test.showMenu(null, function (popup) {
|
||||
test.checkMenu([], [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// Items in the context menu should be sorted according to locale.
|
||||
exports.testSorting = function (test) {
|
||||
test = new TestHelper(test);
|
||||
@ -3339,6 +3408,37 @@ TestHelper.prototype = {
|
||||
return wrapper;
|
||||
},
|
||||
|
||||
// As above but the loader has private-browsing support enabled.
|
||||
newPrivateLoader: function() {
|
||||
let base = require("@loader/options");
|
||||
|
||||
// Clone current loader's options adding the private-browsing permission
|
||||
let options = merge({}, base, {
|
||||
metadata: merge({}, base.metadata || {}, {
|
||||
permissions: merge({}, base.metadata.permissions || {}, {
|
||||
'private-browsing': true
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
const self = this;
|
||||
let loader = Loader(module, null, options);
|
||||
let wrapper = {
|
||||
loader: loader,
|
||||
cm: loader.require("sdk/context-menu"),
|
||||
globalScope: loader.sandbox("sdk/context-menu"),
|
||||
unload: function () {
|
||||
loader.unload();
|
||||
let idx = self.loaders.indexOf(wrapper);
|
||||
if (idx < 0)
|
||||
throw new Error("Test error: tried to unload nonexistent loader");
|
||||
self.loaders.splice(idx, 1);
|
||||
}
|
||||
};
|
||||
this.loaders.push(wrapper);
|
||||
return wrapper;
|
||||
},
|
||||
|
||||
// Returns true if the count crosses the overflow threshold.
|
||||
shouldOverflow: function (count) {
|
||||
return count >
|
||||
@ -3405,6 +3505,15 @@ TestHelper.prototype = {
|
||||
this.browserWindow = win;
|
||||
},
|
||||
|
||||
// Opens a new private browser window. The window will be closed
|
||||
// automatically when done() is called.
|
||||
withNewPrivateWindow: function (onloadCallback) {
|
||||
let win = this.browserWindow.OpenBrowserWindow({private: true});
|
||||
this.delayedEventListener(win, "load", onloadCallback, true);
|
||||
this.oldBrowserWindow = this.browserWindow;
|
||||
this.browserWindow = win;
|
||||
},
|
||||
|
||||
// Opens a new tab with our test page in the current window. The tab will
|
||||
// be closed automatically when done() is called.
|
||||
withTestDoc: function (onloadCallback) {
|
||||
|
@ -188,4 +188,38 @@ exports["test disposables that throw"] = function(assert) {
|
||||
assert.equal(disposals, 0, "no disposal if constructor threw");
|
||||
}
|
||||
|
||||
exports["test multiple destroy"] = function(assert) {
|
||||
let loader = Loader(module);
|
||||
let { Disposable } = loader.require("sdk/core/disposable");
|
||||
|
||||
let disposals = 0
|
||||
|
||||
let Foo = Class({
|
||||
extends: Disposable,
|
||||
dispose: function dispose() {
|
||||
disposals = disposals + 1
|
||||
}
|
||||
})
|
||||
|
||||
let foo1 = Foo();
|
||||
let foo2 = Foo();
|
||||
let foo3 = Foo();
|
||||
|
||||
assert.equal(disposals, 0, "no disposals yet");
|
||||
|
||||
foo1.destroy();
|
||||
assert.equal(disposals, 1, "disposed properly");
|
||||
foo1.destroy();
|
||||
assert.equal(disposals, 1, "didn't attempt to dispose twice");
|
||||
|
||||
foo2.destroy();
|
||||
assert.equal(disposals, 2, "other instances still dispose fine");
|
||||
foo2.destroy();
|
||||
assert.equal(disposals, 2, "but not twice");
|
||||
|
||||
loader.unload();
|
||||
|
||||
assert.equal(disposals, 3, "unload only disposed the remaining instance");
|
||||
}
|
||||
|
||||
require('test').run(exports);
|
||||
|
@ -13,7 +13,7 @@ function inc(x) x + 1
|
||||
|
||||
exports["test filter events"] = function(assert) {
|
||||
let input = {};
|
||||
let evens = filter(isEven, input);
|
||||
let evens = filter(input, isEven);
|
||||
let actual = [];
|
||||
on(evens, "data", function(e) actual.push(e));
|
||||
|
||||
@ -23,28 +23,28 @@ exports["test filter events"] = function(assert) {
|
||||
};
|
||||
|
||||
exports["test filter emits"] = $.emits(function(input, assert) {
|
||||
let output = filter(isEven, input);
|
||||
let output = filter(input, isEven);
|
||||
assert(output, [1, 2, 3, 4, 5], [2, 4], "this is `output` & evens passed");
|
||||
});;
|
||||
|
||||
exports["test filter reg once"] = $.registerOnce(function(input, assert) {
|
||||
assert(filter(isEven, input), [1, 2, 3, 4, 5, 6], [2, 4, 6],
|
||||
assert(filter(input, isEven), [1, 2, 3, 4, 5, 6], [2, 4, 6],
|
||||
"listener can be registered only once");
|
||||
});
|
||||
|
||||
exports["test filter ignores new"] = $.ignoreNew(function(input, assert) {
|
||||
assert(filter(isEven, input), [1, 2, 3], [2],
|
||||
assert(filter(input, isEven), [1, 2, 3], [2],
|
||||
"new listener is ignored")
|
||||
});
|
||||
|
||||
exports["test filter is FIFO"] = $.FIFO(function(input, assert) {
|
||||
assert(filter(isEven, input), [1, 2, 3, 4], [2, 4],
|
||||
assert(filter(input, isEven), [1, 2, 3, 4], [2, 4],
|
||||
"listeners are invoked in fifo order")
|
||||
});
|
||||
|
||||
exports["test map events"] = function(assert) {
|
||||
let input = {};
|
||||
let incs = map(inc, input);
|
||||
let incs = map(input, inc);
|
||||
let actual = [];
|
||||
on(incs, "data", function(e) actual.push(e));
|
||||
|
||||
@ -54,22 +54,22 @@ exports["test map events"] = function(assert) {
|
||||
};
|
||||
|
||||
exports["test map emits"] = $.emits(function(input, assert) {
|
||||
let output = map(inc, input);
|
||||
let output = map(input, inc);
|
||||
assert(output, [1, 2, 3], [2, 3, 4], "this is `output` & evens passed");
|
||||
});;
|
||||
|
||||
exports["test map reg once"] = $.registerOnce(function(input, assert) {
|
||||
assert(map(inc, input), [1, 2, 3], [2, 3, 4],
|
||||
assert(map(input, inc), [1, 2, 3], [2, 3, 4],
|
||||
"listener can be registered only once");
|
||||
});
|
||||
|
||||
exports["test map ignores new"] = $.ignoreNew(function(input, assert) {
|
||||
assert(map(inc, input), [1], [2],
|
||||
assert(map(input, inc), [1], [2],
|
||||
"new listener is ignored")
|
||||
});
|
||||
|
||||
exports["test map is FIFO"] = $.FIFO(function(input, assert) {
|
||||
assert(map(inc, input), [1, 2, 3, 4], [2, 3, 4, 5],
|
||||
assert(map(input, inc), [1, 2, 3, 4], [2, 3, 4, 5],
|
||||
"listeners are invoked in fifo order")
|
||||
});
|
||||
|
||||
@ -115,28 +115,28 @@ exports["test merge array[stream]"] = function(assert) {
|
||||
};
|
||||
|
||||
exports["test merge emits"] = $.emits(function(input, assert) {
|
||||
let evens = filter(isEven, input)
|
||||
let evens = filter(input, isEven)
|
||||
let output = merge([evens, input]);
|
||||
assert(output, [1, 2, 3], [1, 2, 2, 3], "this is `output` & evens passed");
|
||||
});
|
||||
|
||||
|
||||
exports["test merge reg once"] = $.registerOnce(function(input, assert) {
|
||||
let evens = filter(isEven, input)
|
||||
let evens = filter(input, isEven)
|
||||
let output = merge([input, evens]);
|
||||
assert(output, [1, 2, 3, 4], [1, 2, 2, 3, 4, 4],
|
||||
"listener can be registered only once");
|
||||
});
|
||||
|
||||
exports["test merge ignores new"] = $.ignoreNew(function(input, assert) {
|
||||
let evens = filter(isEven, input)
|
||||
let evens = filter(input, isEven)
|
||||
let output = merge([input, evens])
|
||||
assert(output, [1], [1],
|
||||
"new listener is ignored")
|
||||
});
|
||||
|
||||
exports["test marge is FIFO"] = $.FIFO(function(input, assert) {
|
||||
let evens = filter(isEven, input)
|
||||
let evens = filter(input, isEven)
|
||||
let output = merge([input, evens])
|
||||
|
||||
assert(output, [1, 2, 3, 4], [1, 2, 2, 3, 4, 4],
|
||||
@ -148,7 +148,7 @@ exports["test expand"] = function(assert) {
|
||||
let inputs = {};
|
||||
let actual = [];
|
||||
|
||||
on(expand(function($) $(), inputs), "data", function($) actual.push($))
|
||||
on(expand(inputs, function($) $()), "data", function($) actual.push($))
|
||||
|
||||
emit(inputs, "data", function() a);
|
||||
emit(a, "data", "a1");
|
||||
|
@ -2,9 +2,11 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
const { setTimeout } = require('sdk/timers');
|
||||
const utils = require('sdk/lang/functional');
|
||||
const { invoke, defer, curry, compose, memoize, once, delay, wrap } = utils;
|
||||
const { invoke, defer, partial, compose, memoize, once, delay, wrap } = utils;
|
||||
const { LoaderWithHookedConsole } = require('sdk/test/loader');
|
||||
|
||||
exports['test forwardApply'] = function(assert) {
|
||||
function sum(b, c) this.a + b + c
|
||||
@ -29,17 +31,33 @@ exports['test deferred function'] = function(assert, done) {
|
||||
nextTurn = true;
|
||||
};
|
||||
|
||||
exports['test partial function'] = function(assert) {
|
||||
function sum(b, c) this.a + b + c;
|
||||
|
||||
let foo = { a : 5 };
|
||||
|
||||
foo.sum7 = partial(sum, 7);
|
||||
foo.sum8and4 = partial(sum, 8, 4);
|
||||
|
||||
assert.equal(foo.sum7(2), 14, 'partial one arguments works');
|
||||
|
||||
assert.equal(foo.sum8and4(), 17, 'partial both arguments works');
|
||||
};
|
||||
|
||||
exports['test curry function'] = function(assert) {
|
||||
let { loader, messages } = LoaderWithHookedConsole(module);
|
||||
let { curry } = loader.require('sdk/lang/functional');
|
||||
|
||||
function sum(b, c) this.a + b + c;
|
||||
|
||||
let foo = { a : 5 };
|
||||
|
||||
foo.sum7 = curry(sum, 7);
|
||||
foo.sum8and4 = curry(sum, 8, 4);
|
||||
|
||||
assert.equal(foo.sum7(2), 14, 'curry one arguments works');
|
||||
assert.equal(messages.length, 1, "only one error is dispatched");
|
||||
assert.ok(messages[0].msg.indexOf('curry is deprecated') > -1);
|
||||
|
||||
assert.equal(foo.sum8and4(), 17, 'curry both arguments works');
|
||||
loader.unload();
|
||||
};
|
||||
|
||||
exports['test compose'] = function(assert) {
|
||||
|
@ -1058,6 +1058,8 @@ exports.testEvents = function(test) {
|
||||
|
||||
exports["test page-mod on private tab"] = function (test) {
|
||||
test.waitUntilDone();
|
||||
let fail = test.fail.bind(test);
|
||||
|
||||
let privateUri = "data:text/html;charset=utf-8," +
|
||||
"<iframe src=\"data:text/html;charset=utf-8,frame\" />";
|
||||
let nonPrivateUri = "data:text/html;charset=utf-8,non-private";
|
||||
@ -1072,17 +1074,24 @@ exports["test page-mod on private tab"] = function (test) {
|
||||
nonPrivateUri,
|
||||
"page-mod should only attach to the non-private tab");
|
||||
}
|
||||
|
||||
test.assert(!isPrivate(worker),
|
||||
"The worker is really non-private");
|
||||
test.assert(!isPrivate(worker.tab),
|
||||
"The document is really non-private");
|
||||
pageMod.destroy();
|
||||
page1.close().then(page2.close).then(test.done.bind(test));
|
||||
|
||||
page1.close().
|
||||
then(page2.close).
|
||||
then(test.done.bind(test), fail);
|
||||
}
|
||||
});
|
||||
|
||||
let page1 = openWebpage(privateUri, true);
|
||||
let page2 = openWebpage(nonPrivateUri, false);
|
||||
let page1, page2;
|
||||
page1 = openWebpage(privateUri, true);
|
||||
page1.ready.then(function() {
|
||||
page2 = openWebpage(nonPrivateUri, false);
|
||||
}, fail);
|
||||
}
|
||||
|
||||
exports["test page-mod on private tab in global pb"] = function (test) {
|
||||
|
@ -120,9 +120,11 @@ exports["test Document Reload"] = function(assert, done) {
|
||||
|
||||
let content =
|
||||
"<script>" +
|
||||
"setTimeout(function () {" +
|
||||
" window.location = 'about:blank';" +
|
||||
"}, 250);" +
|
||||
"window.onload = function() {" +
|
||||
" setTimeout(function () {" +
|
||||
" window.location = 'about:blank';" +
|
||||
" }, 0);" +
|
||||
"}" +
|
||||
"</script>";
|
||||
let messageCount = 0;
|
||||
let panel = Panel({
|
||||
@ -132,7 +134,7 @@ exports["test Document Reload"] = function(assert, done) {
|
||||
onMessage: function (message) {
|
||||
messageCount++;
|
||||
if (messageCount == 1) {
|
||||
assert.ok(/data:text\/html/.test(message), "First document had a content script");
|
||||
assert.ok(/data:text\/html/.test(message), "First document had a content script " + message);
|
||||
}
|
||||
else if (messageCount == 2) {
|
||||
assert.equal(message, "about:blank", "Second document too");
|
||||
@ -141,6 +143,7 @@ exports["test Document Reload"] = function(assert, done) {
|
||||
}
|
||||
}
|
||||
});
|
||||
assert.pass('Panel was created');
|
||||
};
|
||||
|
||||
exports["test Parent Resize Hack"] = function(assert, done) {
|
||||
|
@ -381,3 +381,30 @@ exports.testImmediateClosing = function (test) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// TEST: tab.reload()
|
||||
exports.testTabReload = function(test) {
|
||||
test.waitUntilDone();
|
||||
|
||||
let url = "data:text/html;charset=utf-8,<!doctype%20html><title></title>";
|
||||
|
||||
tabs.open({
|
||||
url: url,
|
||||
onReady: function onReady(tab) {
|
||||
tab.removeListener('ready', onReady);
|
||||
|
||||
tab.once(
|
||||
'ready',
|
||||
function onReload() {
|
||||
test.pass("the tab was loaded again");
|
||||
test.assertEqual(tab.url, url, "the tab has the same URL");
|
||||
|
||||
// end test
|
||||
tab.close(function() test.done());
|
||||
}
|
||||
);
|
||||
|
||||
tab.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -208,30 +208,20 @@ exports['test window watcher unregs 4 loading wins'] = function(assert, done) {
|
||||
}
|
||||
|
||||
exports['test window watcher without untracker'] = function(assert, done) {
|
||||
var myWindow;
|
||||
var finished = false;
|
||||
|
||||
var delegate = {
|
||||
let myWindow;
|
||||
let wt = new windowUtils.WindowTracker({
|
||||
onTrack: function(window) {
|
||||
if (window == myWindow) {
|
||||
assert.pass("onTrack() called with our test window");
|
||||
timer.setTimeout(function() {
|
||||
myWindow.close();
|
||||
|
||||
if (!finished) {
|
||||
finished = true;
|
||||
myWindow = null;
|
||||
wt.unload();
|
||||
done();
|
||||
} else {
|
||||
assert.fail("onTrack() called multiple times.");
|
||||
}
|
||||
}, 1);
|
||||
close(myWindow).then(function() {
|
||||
wt.unload();
|
||||
done();
|
||||
}, assert.fail);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var wt = new windowUtils.WindowTracker(delegate);
|
||||
myWindow = makeEmptyWindow();
|
||||
};
|
||||
|
||||
|
@ -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'
|
||||
|
||||
var xhr = require("sdk/net/xhr");
|
||||
var timer = require("sdk/timers");
|
||||
var { Loader } = require("sdk/test/loader");
|
||||
var xulApp = require("sdk/system/xul-app");
|
||||
const xhr = require('sdk/net/xhr');
|
||||
const { Loader } = require('sdk/test/loader');
|
||||
const xulApp = require('sdk/system/xul-app');
|
||||
|
||||
// TODO: rewrite test below
|
||||
/* Test is intentionally disabled until platform bug 707256 is fixed.
|
||||
exports.testAbortedXhr = function(test) {
|
||||
var req = new xhr.XMLHttpRequest();
|
||||
@ -16,67 +17,76 @@ exports.testAbortedXhr = function(test) {
|
||||
};
|
||||
*/
|
||||
|
||||
exports.testLocalXhr = function(test) {
|
||||
exports.testLocalXhr = function(assert, done) {
|
||||
var req = new xhr.XMLHttpRequest();
|
||||
req.overrideMimeType("text/plain");
|
||||
req.open("GET", module.uri);
|
||||
let ready = false;
|
||||
|
||||
req.overrideMimeType('text/plain');
|
||||
req.open('GET', module.uri);
|
||||
req.onreadystatechange = function() {
|
||||
if (req.readyState == 4 && (req.status == 0 || req.status == 200)) {
|
||||
test.assertMatches(req.responseText,
|
||||
/onreadystatechange/,
|
||||
"XMLHttpRequest should get local files");
|
||||
timer.setTimeout(
|
||||
function() { test.assertEqual(xhr.getRequestCount(), 0);
|
||||
test.done(); },
|
||||
0
|
||||
);
|
||||
ready = true;
|
||||
assert.ok(req.responseText.match(/onreadystatechange/i),
|
||||
'XMLHttpRequest should get local files');
|
||||
}
|
||||
};
|
||||
req.addEventListener('load', function onload() {
|
||||
req.removeEventListener('load', onload);
|
||||
assert.pass('addEventListener for load event worked');
|
||||
assert.ok(ready, 'onreadystatechange listener worked');
|
||||
assert.equal(xhr.getRequestCount(), 0, 'request count is 0');
|
||||
done();
|
||||
});
|
||||
req.send(null);
|
||||
test.assertEqual(xhr.getRequestCount(), 1);
|
||||
test.waitUntilDone(4000);
|
||||
|
||||
assert.equal(xhr.getRequestCount(), 1, 'request count is 1');
|
||||
};
|
||||
|
||||
exports.testUnload = function(test) {
|
||||
exports.testUnload = function(assert) {
|
||||
var loader = Loader(module);
|
||||
var sbxhr = loader.require("sdk/net/xhr");
|
||||
var sbxhr = loader.require('sdk/net/xhr');
|
||||
var req = new sbxhr.XMLHttpRequest();
|
||||
req.overrideMimeType("text/plain");
|
||||
|
||||
req.overrideMimeType('text/plain');
|
||||
req.open("GET", module.uri);
|
||||
req.send(null);
|
||||
test.assertEqual(sbxhr.getRequestCount(), 1);
|
||||
|
||||
assert.equal(sbxhr.getRequestCount(), 1, 'request count is 1');
|
||||
loader.unload();
|
||||
test.assertEqual(sbxhr.getRequestCount(), 0);
|
||||
assert.equal(sbxhr.getRequestCount(), 0, 'request count is 0');
|
||||
};
|
||||
|
||||
exports.testResponseHeaders = function(test) {
|
||||
exports.testResponseHeaders = function(assert, done) {
|
||||
var req = new xhr.XMLHttpRequest();
|
||||
req.overrideMimeType("text/plain");
|
||||
req.open("GET", module.uri);
|
||||
|
||||
req.overrideMimeType('text/plain');
|
||||
req.open('GET', module.uri);
|
||||
req.onreadystatechange = function() {
|
||||
if (req.readyState == 4 && (req.status == 0 || req.status == 200)) {
|
||||
var headers = req.getAllResponseHeaders();
|
||||
if (xulApp.versionInRange(xulApp.platformVersion, "13.0a1", "*")) {
|
||||
if (xulApp.satisfiesVersion(xulApp.platformVersion, '>=13.0a1')) {
|
||||
headers = headers.split("\r\n");
|
||||
if(headers.length == 1) {
|
||||
if (headers.length == 1) {
|
||||
headers = headers[0].split("\n");
|
||||
}
|
||||
for(let i in headers) {
|
||||
if(headers[i] && headers[i].search("Content-Type") >= 0) {
|
||||
test.assertEqual(headers[i], "Content-Type: text/plain",
|
||||
"XHR's headers are valid");
|
||||
for (let i in headers) {
|
||||
if (headers[i] && headers[i].search('Content-Type') >= 0) {
|
||||
assert.equal(headers[i], 'Content-Type: text/plain',
|
||||
'XHR\'s headers are valid');
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.assert(headers === null || headers === "",
|
||||
"XHR's headers are empty");
|
||||
assert.ok(headers === null || headers === '',
|
||||
'XHR\'s headers are empty');
|
||||
}
|
||||
test.done();
|
||||
|
||||
done();
|
||||
}
|
||||
};
|
||||
req.send(null);
|
||||
test.assertEqual(xhr.getRequestCount(), 1);
|
||||
test.waitUntilDone(4000);
|
||||
|
||||
assert.equal(xhr.getRequestCount(), 1, 'request count is 1');
|
||||
}
|
||||
|
||||
require('test').run(exports);
|
||||
|
@ -296,15 +296,6 @@ exports.testTrackWindows = function(test) {
|
||||
"activate 2", "global activate 2"
|
||||
];
|
||||
|
||||
function shutdown(window) {
|
||||
if (this.length === 1) {
|
||||
test.assertEqual(actions.join(), expects.join(),
|
||||
"correct activate and deactivate sequence")
|
||||
|
||||
test.done();
|
||||
}
|
||||
}
|
||||
|
||||
function openWindow() {
|
||||
windows.push(browserWindows.open({
|
||||
url: "data:text/html;charset=utf-8,<i>testTrackWindows</i>",
|
||||
@ -312,18 +303,28 @@ exports.testTrackWindows = function(test) {
|
||||
onActivate: function(window) {
|
||||
let index = windows.indexOf(window);
|
||||
|
||||
test.assertEqual(actions.join(), expects.slice(0, index*4).join(), expects[index*4]);
|
||||
actions.push("activate " + index);
|
||||
|
||||
if (windows.length < 3)
|
||||
if (windows.length < 3) {
|
||||
openWindow()
|
||||
else
|
||||
for each (let win in windows)
|
||||
win.close(shutdown)
|
||||
}
|
||||
else {
|
||||
let count = windows.length;
|
||||
for each (let win in windows) {
|
||||
win.close(function() {
|
||||
if (--count == 0) {
|
||||
test.done();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onDeactivate: function(window) {
|
||||
let index = windows.indexOf(window);
|
||||
|
||||
test.assertEqual(actions.join(), expects.slice(0, index*4 + 2).join(), expects[index*4 + 2]);
|
||||
actions.push("deactivate " + index)
|
||||
}
|
||||
}));
|
||||
@ -334,6 +335,8 @@ exports.testTrackWindows = function(test) {
|
||||
// only concerned with windows opened for this test
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
test.assertEqual(actions.join(), expects.slice(0, index*4 + 1).join(), expects[index*4 + 1]);
|
||||
actions.push("global activate " + index)
|
||||
})
|
||||
|
||||
@ -342,6 +345,8 @@ exports.testTrackWindows = function(test) {
|
||||
// only concerned with windows opened for this test
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
test.assertEqual(actions.join(), expects.slice(0, index*4 + 3).join(), expects[index*4 + 3]);
|
||||
actions.push("global deactivate " + index)
|
||||
})
|
||||
|
||||
@ -361,9 +366,7 @@ exports.testWindowOpenPrivateDefault = function(test) {
|
||||
test.assertEqual(tab.url, 'about:mozilla', 'opened correct tab');
|
||||
test.assertEqual(isPrivate(tab), false, 'tab is not private');
|
||||
|
||||
window.close(function() {
|
||||
test.done();
|
||||
});
|
||||
window.close(test.done.bind(test));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user