mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 947501 - Uplift Addon SDK to Firefox
This commit is contained in:
parent
f13e427458
commit
74b51a6914
@ -24,6 +24,7 @@ const { Worker } = require("./content/worker");
|
||||
const { EventTarget } = require("./event/target");
|
||||
const { emit } = require('./event/core');
|
||||
const { when } = require('./system/unload');
|
||||
const selection = require('./selection');
|
||||
|
||||
// All user items we add have this class.
|
||||
const ITEM_CLASS = "addon-context-menu-item";
|
||||
@ -204,6 +205,66 @@ let URLContext = Class({
|
||||
});
|
||||
exports.URLContext = URLContext;
|
||||
|
||||
// Matches when the user-supplied predicate returns true
|
||||
let PredicateContext = Class({
|
||||
extends: Context,
|
||||
|
||||
initialize: function initialize(predicate) {
|
||||
let options = validateOptions({ predicate: predicate }, {
|
||||
predicate: {
|
||||
is: ["function"],
|
||||
msg: "predicate must be a function."
|
||||
}
|
||||
});
|
||||
internal(this).predicate = options.predicate;
|
||||
},
|
||||
|
||||
isCurrent: function isCurrent(popupNode) {
|
||||
return internal(this).predicate(populateCallbackNodeData(popupNode));
|
||||
}
|
||||
});
|
||||
exports.PredicateContext = PredicateContext;
|
||||
|
||||
// List all editable types of inputs. Or is it better to have a list
|
||||
// of non-editable inputs?
|
||||
let editableInputs = {
|
||||
email: true,
|
||||
number: true,
|
||||
password: true,
|
||||
search: true,
|
||||
tel: true,
|
||||
text: true,
|
||||
textarea: true,
|
||||
url: true
|
||||
};
|
||||
|
||||
function populateCallbackNodeData(node) {
|
||||
let window = node.ownerDocument.defaultView;
|
||||
let data = {};
|
||||
|
||||
data.documentType = node.ownerDocument.contentType;
|
||||
|
||||
data.documentURL = node.ownerDocument.location.href;
|
||||
data.targetName = node.nodeName.toLowerCase();
|
||||
data.targetID = node.id || null ;
|
||||
|
||||
if ((data.targetName === 'input' && editableInputs[node.type]) ||
|
||||
data.targetName === 'textarea') {
|
||||
data.isEditable = !node.readOnly && !node.disabled;
|
||||
}
|
||||
else {
|
||||
data.isEditable = node.isContentEditable;
|
||||
}
|
||||
|
||||
data.selectionText = selection.text;
|
||||
|
||||
data.srcURL = node.src || null;
|
||||
data.linkURL = node.href || null;
|
||||
data.value = node.value || null;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function removeItemFromArray(array, item) {
|
||||
return array.filter(function(i) i !== item);
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ const suites = require('@test/options').allTestModules;
|
||||
const { Loader } = require("sdk/test/loader");
|
||||
const cuddlefish = require("sdk/loader/cuddlefish");
|
||||
|
||||
let loader = Loader(module);
|
||||
const NOT_TESTS = ['setup', 'teardown'];
|
||||
|
||||
var TestFinder = exports.TestFinder = function TestFinder(options) {
|
||||
@ -51,11 +52,10 @@ TestFinder.prototype = {
|
||||
} else
|
||||
filter = function() {return true};
|
||||
|
||||
suites.forEach(
|
||||
function(suite) {
|
||||
suites.forEach(function(suite) {
|
||||
// Load each test file as a main module in its own loader instance
|
||||
// `suite` is defined by cuddlefish/manifest.py:ManifestBuilder.build
|
||||
let loader = Loader(module);
|
||||
|
||||
let suiteModule;
|
||||
|
||||
try {
|
||||
|
@ -129,6 +129,12 @@ function isArguments(value) {
|
||||
}
|
||||
exports.isArguments = isArguments;
|
||||
|
||||
let isMap = value => Object.prototype.toString.call(value) === "[object Map]"
|
||||
exports.isMap = isMap;
|
||||
|
||||
let isSet = value => Object.prototype.toString.call(value) === "[object Set]"
|
||||
exports.isSet = isSet;
|
||||
|
||||
/**
|
||||
* Returns true if it is a primitive `value`. (null, undefined, number,
|
||||
* boolean, string)
|
||||
|
@ -315,14 +315,24 @@ function getElementWithSelection() {
|
||||
if (!element)
|
||||
return null;
|
||||
|
||||
let { value, selectionStart, selectionEnd } = element;
|
||||
try {
|
||||
// Accessing selectionStart and selectionEnd on e.g. a button
|
||||
// results in an exception thrown as per the HTML5 spec. See
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/multipage/association-of-controls-and-forms.html#textFieldSelection
|
||||
|
||||
let hasSelection = typeof value === "string" &&
|
||||
let { value, selectionStart, selectionEnd } = element;
|
||||
|
||||
let hasSelection = typeof value === "string" &&
|
||||
!isNaN(selectionStart) &&
|
||||
!isNaN(selectionEnd) &&
|
||||
selectionStart !== selectionEnd;
|
||||
|
||||
return hasSelection ? element : null;
|
||||
return hasSelection ? element : null;
|
||||
}
|
||||
catch (err) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
576
addon-sdk/source/lib/sdk/util/sequence.js
Normal file
576
addon-sdk/source/lib/sdk/util/sequence.js
Normal file
@ -0,0 +1,576 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
module.metadata = {
|
||||
"stability": "experimental"
|
||||
};
|
||||
|
||||
// Disclamer:
|
||||
// In this module we'll have some common argument / variable names
|
||||
// to hint their type or behavior.
|
||||
//
|
||||
// - `f` stands for "function" that is intended to be side effect
|
||||
// free.
|
||||
// - `p` stands for "predicate" that is function which returns logical
|
||||
// true or false and is intended to be side effect free.
|
||||
// - `x` / `y` single item of the sequence.
|
||||
// - `xs` / `ys` sequence of `x` / `y` items where `x` / `y` signifies
|
||||
// type of the items in sequence, so sequence is not of the same item.
|
||||
// - `_` used for argument(s) or variable(s) who's values are ignored.
|
||||
|
||||
const { complement, flip, identity } = require("../lang/functional");
|
||||
const { iteratorSymbol } = require("../util/iteration");
|
||||
const { isArray, isArguments, isMap, isSet,
|
||||
isString, isBoolean, isNumber } = require("../lang/type");
|
||||
|
||||
const Sequence = function Sequence(iterator) {
|
||||
if (iterator.isGenerator && iterator.isGenerator())
|
||||
this[iteratorSymbol] = iterator;
|
||||
else
|
||||
throw TypeError("Expected generator argument");
|
||||
};
|
||||
exports.Sequence = Sequence;
|
||||
|
||||
const polymorphic = dispatch => x =>
|
||||
x === null ? dispatch.null(null) :
|
||||
x === void(0) ? dispatch.void(void(0)) :
|
||||
isArray(x) ? (dispatch.array || dispatch.indexed)(x) :
|
||||
isString(x) ? (dispatch.string || dispatch.indexed)(x) :
|
||||
isArguments(x) ? (dispatch.arguments || dispatch.indexed)(x) :
|
||||
isMap(x) ? dispatch.map(x) :
|
||||
isSet(x) ? dispatch.set(x) :
|
||||
isNumber(x) ? dispatch.number(x) :
|
||||
isBoolean(x) ? dispatch.boolean(x) :
|
||||
dispatch.default(x);
|
||||
|
||||
const nogen = function*() {};
|
||||
const empty = () => new Sequence(nogen);
|
||||
exports.empty = empty;
|
||||
|
||||
const seq = polymorphic({
|
||||
null: empty,
|
||||
void: empty,
|
||||
array: identity,
|
||||
string: identity,
|
||||
arguments: identity,
|
||||
map: identity,
|
||||
set: identity,
|
||||
default: x => x instanceof Sequence ? x : new Sequence(x)
|
||||
});
|
||||
exports.seq = seq;
|
||||
|
||||
|
||||
|
||||
|
||||
// Function to cast seq to string.
|
||||
const string = (...etc) => "".concat(...etc);
|
||||
exports.string = string;
|
||||
|
||||
// Function for casting seq to plain object.
|
||||
const object = (...pairs) => {
|
||||
let result = {};
|
||||
for (let [key, value] of pairs)
|
||||
result[key] = value;
|
||||
|
||||
return result;
|
||||
};
|
||||
exports.object = object;
|
||||
|
||||
// Takes `getEnumerator` function that returns `nsISimpleEnumerator`
|
||||
// and creates lazy sequence of it's items. Note that function does
|
||||
// not take `nsISimpleEnumerator` itslef because that would allow
|
||||
// single iteration, which would not be consistent with rest of the
|
||||
// lazy sequences.
|
||||
const fromEnumerator = getEnumerator => seq(function* () {
|
||||
const enumerator = getEnumerator();
|
||||
while (enumerator.hasMoreElements())
|
||||
yield enumerator.getNext();
|
||||
});
|
||||
exports.fromEnumerator = fromEnumerator;
|
||||
|
||||
// Takes `object` and returns lazy sequence of own `[key, value]`
|
||||
// pairs (does not include inherited and non enumerable keys).
|
||||
const pairs = polymorphic({
|
||||
null: empty,
|
||||
void: empty,
|
||||
map: identity,
|
||||
indexed: indexed => seq(function* () {
|
||||
const count = indexed.length;
|
||||
let index = 0;
|
||||
while (index < count) {
|
||||
yield [index, indexed[index]];
|
||||
index = index + 1;
|
||||
}
|
||||
}),
|
||||
default: object => seq(function* () {
|
||||
for (let key of Object.keys(object))
|
||||
yield [key, object[key]];
|
||||
})
|
||||
});
|
||||
exports.pairs = pairs;
|
||||
|
||||
|
||||
const keys = polymorphic({
|
||||
null: empty,
|
||||
void: empty,
|
||||
indexed: indexed => seq(function* () {
|
||||
const count = indexed.length;
|
||||
let index = 0;
|
||||
while (index < count) {
|
||||
yield index;
|
||||
index = index + 1;
|
||||
}
|
||||
}),
|
||||
map: map => seq(function* () {
|
||||
for (let [key, _] of map)
|
||||
yield key;
|
||||
}),
|
||||
default: object => seq(function* () {
|
||||
for (let key of Object.keys(object))
|
||||
yield key;
|
||||
})
|
||||
});
|
||||
exports.keys = keys;
|
||||
|
||||
|
||||
const values = polymorphic({
|
||||
null: empty,
|
||||
void: empty,
|
||||
set: identity,
|
||||
indexed: indexed => seq(function* () {
|
||||
const count = indexed.length;
|
||||
let index = 0;
|
||||
while (index < count) {
|
||||
yield indexed[index];
|
||||
index = index + 1;
|
||||
}
|
||||
}),
|
||||
map: map => seq(function* () {
|
||||
for (let [_, value] of map) yield value;
|
||||
}),
|
||||
default: object => seq(function* () {
|
||||
for (let key of Object.keys(object)) yield object[key];
|
||||
})
|
||||
});
|
||||
exports.values = values;
|
||||
|
||||
|
||||
|
||||
// Returns a lazy sequence of `x`, `f(x)`, `f(f(x))` etc.
|
||||
// `f` must be free of side-effects. Note that returned
|
||||
// sequence is infinite so it must be consumed partially.
|
||||
//
|
||||
// Implements clojure iterate:
|
||||
// http://clojuredocs.org/clojure_core/clojure.core/iterate
|
||||
const iterate = (f, x) => seq(function* () {
|
||||
let state = x;
|
||||
while (true) {
|
||||
yield state;
|
||||
state = f(state);
|
||||
}
|
||||
});
|
||||
exports.iterate = iterate;
|
||||
|
||||
// Returns a lazy sequence of the items in sequence for which `p(item)`
|
||||
// returns `true`. `p` must be free of side-effects.
|
||||
//
|
||||
// Implements clojure filter:
|
||||
// http://clojuredocs.org/clojure_core/clojure.core/filter
|
||||
const filter = (p, sequence) => seq(function* () {
|
||||
if (sequence !== null && sequence !== void(0)) {
|
||||
for (let item of sequence) {
|
||||
if (p(item))
|
||||
yield item;
|
||||
}
|
||||
}
|
||||
});
|
||||
exports.filter = filter;
|
||||
|
||||
// Returns a lazy sequence consisting of the result of applying `f` to the
|
||||
// set of first items of each sequence, followed by applying f to the set
|
||||
// of second items in each sequence, until any one of the sequences is
|
||||
// exhausted. Any remaining items in other sequences are ignored. Function
|
||||
// `f` should accept number-of-sequences arguments.
|
||||
//
|
||||
// Implements clojure map:
|
||||
// http://clojuredocs.org/clojure_core/clojure.core/map
|
||||
const map = (f, ...sequences) => seq(function* () {
|
||||
const count = sequences.length;
|
||||
// Optimize a single sequence case
|
||||
if (count === 1) {
|
||||
let [sequence] = sequences;
|
||||
if (sequence !== null && sequence !== void(0)) {
|
||||
for (let item of sequence)
|
||||
yield f(item);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// define args array that will be recycled on each
|
||||
// step to aggregate arguments to be passed to `f`.
|
||||
let args = [];
|
||||
// define inputs to contain started generators.
|
||||
let inputs = [];
|
||||
|
||||
let index = 0;
|
||||
while (index < count) {
|
||||
inputs[index] = sequences[index][iteratorSymbol]();
|
||||
index = index + 1;
|
||||
}
|
||||
|
||||
// Run loop yielding of applying `f` to the set of
|
||||
// items at each step until one of the `inputs` is
|
||||
// exhausted.
|
||||
let done = false;
|
||||
while (!done) {
|
||||
let index = 0;
|
||||
let value = void(0);
|
||||
while (index < count && !done) {
|
||||
({ done, value }) = inputs[index].next();
|
||||
|
||||
// If input is not exhausted yet store value in args.
|
||||
if (!done) {
|
||||
args[index] = value;
|
||||
index = index + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// If none of the inputs is exhasted yet, `args` contain items
|
||||
// from each input so we yield application of `f` over them.
|
||||
if (!done)
|
||||
yield f(...args);
|
||||
}
|
||||
}
|
||||
});
|
||||
exports.map = map;
|
||||
|
||||
// Returns a lazy sequence of the intermediate values of the reduction (as
|
||||
// per reduce) of sequence by `f`, starting with `initial` value if provided.
|
||||
//
|
||||
// Implements clojure reductions:
|
||||
// http://clojuredocs.org/clojure_core/clojure.core/reductions
|
||||
const reductions = (...params) => {
|
||||
const count = params.length;
|
||||
let hasInitial = false;
|
||||
let f, initial, source;
|
||||
if (count === 2) {
|
||||
([f, source]) = params;
|
||||
}
|
||||
else if (count === 3) {
|
||||
([f, initial, source]) = params;
|
||||
hasInitial = true;
|
||||
}
|
||||
else {
|
||||
throw Error("Invoked with wrong number of arguments: " + count);
|
||||
}
|
||||
|
||||
const sequence = seq(source);
|
||||
|
||||
return seq(function* () {
|
||||
let started = hasInitial;
|
||||
let result = void(0);
|
||||
|
||||
// If initial is present yield it.
|
||||
if (hasInitial)
|
||||
yield (result = initial);
|
||||
|
||||
// For each item of the sequence accumulate new result.
|
||||
for (let item of sequence) {
|
||||
// If nothing has being yield yet set result to first
|
||||
// item and yield it.
|
||||
if (!started) {
|
||||
started = true;
|
||||
yield (result = item);
|
||||
}
|
||||
// Otherwise accumulate new result and yield it.
|
||||
else {
|
||||
yield (result = f(result, item));
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing has being yield yet it's empty sequence and no
|
||||
// `initial` was provided in which case we need to yield `f()`.
|
||||
if (!started)
|
||||
yield f();
|
||||
});
|
||||
};
|
||||
exports.reductions = reductions;
|
||||
|
||||
// `f` should be a function of 2 arguments. If `initial` is not supplied,
|
||||
// returns the result of applying `f` to the first 2 items in sequence, then
|
||||
// applying `f` to that result and the 3rd item, etc. If sequence contains no
|
||||
// items, `f` must accept no arguments as well, and reduce returns the
|
||||
// result of calling f with no arguments. If sequence has only 1 item, it
|
||||
// is returned and `f` is not called. If `initial` is supplied, returns the
|
||||
// result of applying `f` to `initial` and the first item in sequence, then
|
||||
// applying `f` to that result and the 2nd item, etc. If sequence contains no
|
||||
// items, returns `initial` and `f` is not called.
|
||||
//
|
||||
// Implements clojure reduce:
|
||||
// http://clojuredocs.org/clojure_core/clojure.core/reduce
|
||||
const reduce = (...args) => {
|
||||
const xs = reductions(...args);
|
||||
let x;
|
||||
for (x of xs) void(0);
|
||||
return x;
|
||||
};
|
||||
exports.reduce = reduce;
|
||||
|
||||
const each = (f, sequence) => {
|
||||
for (let x of seq(sequence)) void(f(x));
|
||||
};
|
||||
exports.each = each;
|
||||
|
||||
|
||||
const inc = x => x + 1;
|
||||
// Returns the number of items in the sequence. `count(null)` && `count()`
|
||||
// returns `0`. Also works on strings, arrays, Maps & Sets.
|
||||
|
||||
// Implements clojure count:
|
||||
// http://clojuredocs.org/clojure_core/clojure.core/count
|
||||
const count = polymorphic({
|
||||
null: _ => 0,
|
||||
void: _ => 0,
|
||||
indexed: indexed => indexed.length,
|
||||
map: map => map.size,
|
||||
set: set => set.size,
|
||||
default: xs => reduce(inc, 0, xs)
|
||||
});
|
||||
exports.count = count;
|
||||
|
||||
// Returns `true` if sequence has no items.
|
||||
|
||||
// Implements clojure empty?:
|
||||
// http://clojuredocs.org/clojure_core/clojure.core/empty_q
|
||||
const isEmpty = sequence => {
|
||||
// Treat `null` and `undefined` as empty sequences.
|
||||
if (sequence === null || sequence === void(0))
|
||||
return true;
|
||||
|
||||
// If contains any item non empty so return `false`.
|
||||
for (let _ of sequence)
|
||||
return false;
|
||||
|
||||
// If has not returned yet, there was nothing to iterate
|
||||
// so it's empty.
|
||||
return true;
|
||||
};
|
||||
exports.isEmpty = isEmpty;
|
||||
|
||||
const and = (a, b) => a && b;
|
||||
|
||||
// Returns true if `p(x)` is logical `true` for every `x` in sequence, else
|
||||
// `false`.
|
||||
//
|
||||
// Implements clojure every?:
|
||||
// http://clojuredocs.org/clojure_core/clojure.core/every_q
|
||||
const isEvery = (p, sequence) => {
|
||||
if (sequence !== null && sequence !== void(0)) {
|
||||
for (let item of sequence) {
|
||||
if (!p(item))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
exports.isEvery = isEvery;
|
||||
|
||||
// Returns the first logical true value of (p x) for any x in sequence,
|
||||
// else `null`.
|
||||
//
|
||||
// Implements clojure some:
|
||||
// http://clojuredocs.org/clojure_core/clojure.core/some
|
||||
const some = (p, sequence) => {
|
||||
if (sequence !== null && sequence !== void(0)) {
|
||||
for (let item of sequence) {
|
||||
if (p(item))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
exports.some = some;
|
||||
|
||||
// Returns a lazy sequence of the first `n` items in sequence, or all items if
|
||||
// there are fewer than `n`.
|
||||
//
|
||||
// Implements clojure take:
|
||||
// http://clojuredocs.org/clojure_core/clojure.core/take
|
||||
const take = (n, sequence) => n <= 0 ? empty() : seq(function* () {
|
||||
let count = n;
|
||||
for (let item of sequence) {
|
||||
yield item;
|
||||
count = count - 1;
|
||||
if (count === 0) break;
|
||||
}
|
||||
});
|
||||
exports.take = take;
|
||||
|
||||
// Returns a lazy sequence of successive items from sequence while
|
||||
// `p(item)` returns `true`. `p` must be free of side-effects.
|
||||
//
|
||||
// Implements clojure take-while:
|
||||
// http://clojuredocs.org/clojure_core/clojure.core/take-while
|
||||
const takeWhile = (p, sequence) => seq(function* () {
|
||||
for (let item of sequence) {
|
||||
if (!p(item))
|
||||
break;
|
||||
|
||||
yield item;
|
||||
}
|
||||
});
|
||||
exports.takeWhile = takeWhile;
|
||||
|
||||
// Returns a lazy sequence of all but the first `n` items in
|
||||
// sequence.
|
||||
//
|
||||
// Implements clojure drop:
|
||||
// http://clojuredocs.org/clojure_core/clojure.core/drop
|
||||
const drop = (n, sequence) => seq(function* () {
|
||||
if (sequence !== null && sequence !== void(0)) {
|
||||
let count = n;
|
||||
for (let item of sequence) {
|
||||
if (count > 0)
|
||||
count = count - 1;
|
||||
else
|
||||
yield item;
|
||||
}
|
||||
}
|
||||
});
|
||||
exports.drop = drop;
|
||||
|
||||
// Returns a lazy sequence of the items in sequence starting from the
|
||||
// first item for which `p(item)` returns falsy value.
|
||||
//
|
||||
// Implements clojure drop-while:
|
||||
// http://clojuredocs.org/clojure_core/clojure.core/drop-while
|
||||
const dropWhile = (p, sequence) => seq(function* () {
|
||||
let keep = false;
|
||||
for (let item of sequence) {
|
||||
keep = keep || !p(item);
|
||||
if (keep) yield item;
|
||||
}
|
||||
});
|
||||
exports.dropWhile = dropWhile;
|
||||
|
||||
// Returns a lazy sequence representing the concatenation of the
|
||||
// suplied sequences.
|
||||
//
|
||||
// Implements clojure conact:
|
||||
// http://clojuredocs.org/clojure_core/clojure.core/concat
|
||||
const concat = (...sequences) => seq(function* () {
|
||||
for (let sequence of sequences)
|
||||
for (let item of sequence)
|
||||
yield item;
|
||||
});
|
||||
exports.concat = concat;
|
||||
|
||||
// Returns the first item in the sequence.
|
||||
//
|
||||
// Implements clojure first:
|
||||
// http://clojuredocs.org/clojure_core/clojure.core/first
|
||||
const first = sequence => {
|
||||
if (sequence !== null && sequence !== void(0)) {
|
||||
for (let item of sequence)
|
||||
return item;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
exports.first = first;
|
||||
|
||||
// Returns a possibly empty sequence of the items after the first.
|
||||
//
|
||||
// Implements clojure rest:
|
||||
// http://clojuredocs.org/clojure_core/clojure.core/rest
|
||||
const rest = sequence => drop(1, sequence);
|
||||
exports.rest = rest;
|
||||
|
||||
// Returns the value at the index. Returns `notFound` or `undefined`
|
||||
// if index is out of bounds.
|
||||
const nth = (xs, n, notFound) => {
|
||||
if (n >= 0) {
|
||||
if (isArray(xs) || isArguments(xs) || isString(xs)) {
|
||||
return n < xs.length ? xs[n] : notFound;
|
||||
}
|
||||
else if (xs !== null && xs !== void(0)) {
|
||||
let count = n;
|
||||
for (let x of xs) {
|
||||
if (count <= 0)
|
||||
return x;
|
||||
|
||||
count = count - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return notFound;
|
||||
};
|
||||
exports.nth = nth;
|
||||
|
||||
// Return the last item in sequence, in linear time.
|
||||
// If `sequence` is an array or string or arguments
|
||||
// returns in constant time.
|
||||
// Implements clojure last:
|
||||
// http://clojuredocs.org/clojure_core/clojure.core/last
|
||||
const last = polymorphic({
|
||||
null: _ => null,
|
||||
void: _ => null,
|
||||
indexed: indexed => indexed[indexed.length - 1],
|
||||
map: xs => reduce((_, x) => x, xs),
|
||||
set: xs => reduce((_, x) => x, xs),
|
||||
default: xs => reduce((_, x) => x, xs)
|
||||
});
|
||||
exports.last = last;
|
||||
|
||||
// Return a lazy sequence of all but the last `n` (default 1) items
|
||||
// from the give `xs`.
|
||||
//
|
||||
// Implements clojure drop-last:
|
||||
// http://clojuredocs.org/clojure_core/clojure.core/drop-last
|
||||
const dropLast = flip((xs, n=1) => seq(function* () {
|
||||
let ys = [];
|
||||
for (let x of xs) {
|
||||
ys.push(x);
|
||||
if (ys.length > n)
|
||||
yield ys.shift();
|
||||
}
|
||||
}));
|
||||
exports.dropLast = dropLast;
|
||||
|
||||
// Returns a lazy sequence of the elements of `xs` with duplicates
|
||||
// removed
|
||||
//
|
||||
// Implements clojure distinct
|
||||
// http://clojuredocs.org/clojure_core/clojure.core/distinct
|
||||
const distinct = sequence => seq(function* () {
|
||||
let items = new Set();
|
||||
for (let item of sequence) {
|
||||
if (!items.has(item)) {
|
||||
items.add(item);
|
||||
yield item;
|
||||
}
|
||||
}
|
||||
});
|
||||
exports.distinct = distinct;
|
||||
|
||||
// Returns a lazy sequence of the items in `xs` for which
|
||||
// `p(x)` returns false. `p` must be free of side-effects.
|
||||
//
|
||||
// Implements clojure remove
|
||||
// http://clojuredocs.org/clojure_core/clojure.core/remove
|
||||
const remove = (p, xs) => filter(complement(p), xs);
|
||||
exports.remove = remove;
|
||||
|
||||
// Returns the result of applying concat to the result of
|
||||
// `map(f, xs)`. Thus function `f` should return a sequence.
|
||||
//
|
||||
// Implements clojure mapcat
|
||||
// http://clojuredocs.org/clojure_core/clojure.core/mapcat
|
||||
const mapcat = (f, sequence) => seq(function* () {
|
||||
const sequences = map(f, sequence);
|
||||
for (let sequence of sequences)
|
||||
for (let item of sequence)
|
||||
yield item;
|
||||
});
|
||||
exports.mapcat = mapcat;
|
@ -26,14 +26,12 @@ usage = """
|
||||
%prog [options] command [command-specific options]
|
||||
|
||||
Supported Commands:
|
||||
docs - view web-based documentation
|
||||
init - create a sample addon in an empty directory
|
||||
test - run tests
|
||||
run - run program
|
||||
xpi - generate an xpi
|
||||
|
||||
Internal Commands:
|
||||
sdocs - export static documentation
|
||||
testcfx - test the cfx tool
|
||||
testex - test all example code
|
||||
testpkgs - test all installed packages
|
||||
@ -223,11 +221,6 @@ parser_groups = (
|
||||
metavar=None,
|
||||
default=False,
|
||||
cmds=['test', 'testex', 'testpkgs'])),
|
||||
(("", "--override-version",), dict(dest="override_version",
|
||||
help="Pass in a version string to use in generated docs",
|
||||
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",
|
||||
@ -238,6 +231,10 @@ parser_groups = (
|
||||
help="Where to put the finished .xpi",
|
||||
default=None,
|
||||
cmds=['xpi'])),
|
||||
(("", "--manifest-overload",), dict(dest="manifest_overload",
|
||||
help="JSON file to overload package.json properties",
|
||||
default=None,
|
||||
cmds=['xpi'])),
|
||||
]
|
||||
),
|
||||
|
||||
@ -249,12 +246,6 @@ parser_groups = (
|
||||
default=None,
|
||||
cmds=['test', 'run', 'testex', 'testpkgs',
|
||||
'testall'])),
|
||||
(("", "--baseurl",), dict(dest="baseurl",
|
||||
help=("root of static docs tree: "
|
||||
"for example: 'http://me.com/the_docs/'"),
|
||||
metavar=None,
|
||||
default='',
|
||||
cmds=['sdocs'])),
|
||||
(("", "--test-runner-pkg",), dict(dest="test_runner_pkg",
|
||||
help=("name of package "
|
||||
"containing test runner "
|
||||
@ -626,23 +617,6 @@ def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None,
|
||||
return
|
||||
test_cfx(env_root, options.verbose)
|
||||
return
|
||||
elif command == "docs":
|
||||
from cuddlefish.docs import generate
|
||||
if len(args) > 1:
|
||||
docs_home = generate.generate_named_file(env_root, filename_and_path=args[1])
|
||||
else:
|
||||
docs_home = generate.generate_local_docs(env_root)
|
||||
webbrowser.open(docs_home)
|
||||
return
|
||||
elif command == "sdocs":
|
||||
from cuddlefish.docs import generate
|
||||
filename=""
|
||||
if options.override_version:
|
||||
filename = generate.generate_static_docs(env_root, override_version=options.override_version)
|
||||
else:
|
||||
filename = generate.generate_static_docs(env_root)
|
||||
print >>stdout, "Wrote %s." % filename
|
||||
return
|
||||
elif command not in ["xpi", "test", "run"]:
|
||||
print >>sys.stderr, "Unknown command: %s" % command
|
||||
print >>sys.stderr, "Try using '--help' for assistance."
|
||||
@ -666,6 +640,10 @@ def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None,
|
||||
target_cfg_json = os.path.join(options.pkgdir, 'package.json')
|
||||
target_cfg = packaging.get_config_in_dir(options.pkgdir)
|
||||
|
||||
if options.manifest_overload:
|
||||
for k, v in packaging.load_json_file(options.manifest_overload).items():
|
||||
target_cfg[k] = v
|
||||
|
||||
# At this point, we're either building an XPI or running Jetpack code in
|
||||
# a Mozilla application (which includes running tests).
|
||||
|
||||
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"version": "1.0-nightly"
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import os, unittest, shutil
|
||||
import zipfile
|
||||
from StringIO import StringIO
|
||||
from cuddlefish import initializer
|
||||
from cuddlefish.templates import TEST_MAIN_JS, PACKAGE_JSON
|
||||
@ -196,6 +197,21 @@ class TestCfxQuits(unittest.TestCase):
|
||||
self.assertIn("1 of 1 tests passed.", err)
|
||||
self.assertIn("Program terminated successfully.", err)
|
||||
|
||||
def test_cfx_xpi(self):
|
||||
addon_path = os.path.join(tests_path,
|
||||
"addons", "simplest-test")
|
||||
rc, out, err = self.run_cfx(addon_path, \
|
||||
["xpi", "--manifest-overload", "manifest-overload.json"])
|
||||
self.assertEqual(rc, 0)
|
||||
# Ensure that the addon version from our manifest overload is used
|
||||
# in install.rdf
|
||||
xpi_path = os.path.join(addon_path, "simplest-test.xpi")
|
||||
xpi = zipfile.ZipFile(xpi_path, "r")
|
||||
manifest = xpi.read("install.rdf")
|
||||
self.assertIn("<em:version>1.0-nightly</em:version>", manifest)
|
||||
xpi.close()
|
||||
os.remove(xpi_path)
|
||||
|
||||
def test_cfx_init(self):
|
||||
# Create an empty test directory
|
||||
addon_path = os.path.abspath(os.path.join(".test_tmp", "test-cfx-init"))
|
||||
|
24
addon-sdk/source/test/addons/translators/main.js
Normal file
24
addon-sdk/source/test/addons/translators/main.js
Normal file
@ -0,0 +1,24 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
'use strict';
|
||||
|
||||
const { Cc, Ci, Cu, Cm, components } = require('chrome');
|
||||
const self = require('sdk/self');
|
||||
const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {});
|
||||
|
||||
|
||||
exports.testTranslators = function(assert, done) {
|
||||
AddonManager.getAddonByID(self.id, function(addon) {
|
||||
let count = 0;
|
||||
addon.translators.forEach(function({ name }) {
|
||||
count++;
|
||||
assert.equal(name, 'Erik Vold', 'The translator keys are correct');
|
||||
});
|
||||
assert.equal(count, 1, 'The translator key count is correct');
|
||||
assert.equal(addon.translators.length, 1, 'The translator key length is correct');
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
require('sdk/test/runner').runTestsFromModule(module);
|
6
addon-sdk/source/test/addons/translators/package.json
Normal file
6
addon-sdk/source/test/addons/translators/package.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"id": "test-translators",
|
||||
"translators": [
|
||||
"Erik Vold"
|
||||
]
|
||||
}
|
@ -6,6 +6,9 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Context menu test</title>
|
||||
<style>
|
||||
p { display: inline-block; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
@ -52,5 +55,27 @@
|
||||
<p>
|
||||
<input type="submit" id="button">
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a class="predicate-test-a" href="#test">
|
||||
A link with no ID and an anchor, used by PredicateContext tests.
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<input type="text" id="textbox" value="test value">
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<input type="text" id="readonly-textbox" readonly="true" value="readonly value">
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<input type="text" id="disabled-textbox" disabled="true" value="disabled value">
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<p contenteditable="true" id="editable">This content is editable.</p>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -3135,6 +3135,488 @@ exports.testSelectionInOuterFrameNoMatch = function (assert, done) {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// Test that the return value of the predicate function determines if
|
||||
// item is shown
|
||||
exports.testPredicateContextControl = function (assert, done) {
|
||||
let test = new TestHelper(assert, done);
|
||||
let loader = test.newLoader();
|
||||
|
||||
let itemTrue = loader.cm.Item({
|
||||
label: "visible",
|
||||
context: loader.cm.PredicateContext(function () { return true; })
|
||||
});
|
||||
|
||||
let itemFalse = loader.cm.Item({
|
||||
label: "hidden",
|
||||
context: loader.cm.PredicateContext(function () { return false; })
|
||||
});
|
||||
|
||||
test.showMenu(null, function (popup) {
|
||||
test.checkMenu([itemTrue, itemFalse], [itemFalse], []);
|
||||
test.done();
|
||||
});
|
||||
};
|
||||
|
||||
// Test that the data object has the correct document type
|
||||
exports.testPredicateContextDocumentType = function (assert, done) {
|
||||
let test = new TestHelper(assert, done);
|
||||
let loader = test.newLoader();
|
||||
|
||||
let items = [loader.cm.Item({
|
||||
label: "item",
|
||||
context: loader.cm.PredicateContext(function (data) {
|
||||
assert.equal(data.documentType, 'text/html');
|
||||
return true;
|
||||
})
|
||||
})];
|
||||
|
||||
test.withTestDoc(function (window, doc) {
|
||||
test.showMenu(null, function (popup) {
|
||||
test.checkMenu(items, [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Test that the data object has the correct document URL
|
||||
exports.testPredicateContextDocumentURL = function (assert, done) {
|
||||
let test = new TestHelper(assert, done);
|
||||
let loader = test.newLoader();
|
||||
|
||||
let items = [loader.cm.Item({
|
||||
label: "item",
|
||||
context: loader.cm.PredicateContext(function (data) {
|
||||
assert.equal(data.documentURL, TEST_DOC_URL);
|
||||
return true;
|
||||
})
|
||||
})];
|
||||
|
||||
test.withTestDoc(function (window, doc) {
|
||||
test.showMenu(null, function (popup) {
|
||||
test.checkMenu(items, [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// Test that the data object has the correct element name
|
||||
exports.testPredicateContextTargetName = function (assert, done) {
|
||||
let test = new TestHelper(assert, done);
|
||||
let loader = test.newLoader();
|
||||
|
||||
let items = [loader.cm.Item({
|
||||
label: "item",
|
||||
context: loader.cm.PredicateContext(function (data) {
|
||||
assert.strictEqual(data.targetName, "input");
|
||||
return true;
|
||||
})
|
||||
})];
|
||||
|
||||
test.withTestDoc(function (window, doc) {
|
||||
test.showMenu(doc.getElementById("button"), function (popup) {
|
||||
test.checkMenu(items, [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// Test that the data object has the correct ID
|
||||
exports.testPredicateContextTargetIDSet = function (assert, done) {
|
||||
let test = new TestHelper(assert, done);
|
||||
let loader = test.newLoader();
|
||||
|
||||
let items = [loader.cm.Item({
|
||||
label: "item",
|
||||
context: loader.cm.PredicateContext(function (data) {
|
||||
assert.strictEqual(data.targetID, "button");
|
||||
return true;
|
||||
})
|
||||
})];
|
||||
|
||||
test.withTestDoc(function (window, doc) {
|
||||
test.showMenu(doc.getElementById("button"), function (popup) {
|
||||
test.checkMenu(items, [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Test that the data object has the correct ID
|
||||
exports.testPredicateContextTargetIDNotSet = function (assert, done) {
|
||||
let test = new TestHelper(assert, done);
|
||||
let loader = test.newLoader();
|
||||
|
||||
let items = [loader.cm.Item({
|
||||
label: "item",
|
||||
context: loader.cm.PredicateContext(function (data) {
|
||||
assert.strictEqual(data.targetID, null);
|
||||
return true;
|
||||
})
|
||||
})];
|
||||
|
||||
test.withTestDoc(function (window, doc) {
|
||||
test.showMenu(doc.getElementsByClassName("predicate-test-a")[0], function (popup) {
|
||||
test.checkMenu(items, [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Test that the data object is showing editable correctly for regular text inputs
|
||||
exports.testPredicateContextTextBoxIsEditable = function (assert, done) {
|
||||
let test = new TestHelper(assert, done);
|
||||
let loader = test.newLoader();
|
||||
|
||||
let items = [loader.cm.Item({
|
||||
label: "item",
|
||||
context: loader.cm.PredicateContext(function (data) {
|
||||
assert.strictEqual(data.isEditable, true);
|
||||
return true;
|
||||
})
|
||||
})];
|
||||
|
||||
test.withTestDoc(function (window, doc) {
|
||||
test.showMenu(doc.getElementById("textbox"), function (popup) {
|
||||
test.checkMenu(items, [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Test that the data object is showing editable correctly for readonly text inputs
|
||||
exports.testPredicateContextReadonlyTextBoxIsNotEditable = function (assert, done) {
|
||||
let test = new TestHelper(assert, done);
|
||||
let loader = test.newLoader();
|
||||
|
||||
let items = [loader.cm.Item({
|
||||
label: "item",
|
||||
context: loader.cm.PredicateContext(function (data) {
|
||||
assert.strictEqual(data.isEditable, false);
|
||||
return true;
|
||||
})
|
||||
})];
|
||||
|
||||
test.withTestDoc(function (window, doc) {
|
||||
test.showMenu(doc.getElementById("readonly-textbox"), function (popup) {
|
||||
test.checkMenu(items, [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Test that the data object is showing editable correctly for disabled text inputs
|
||||
exports.testPredicateContextDisabledTextBoxIsNotEditable = function (assert, done) {
|
||||
let test = new TestHelper(assert, done);
|
||||
let loader = test.newLoader();
|
||||
|
||||
let items = [loader.cm.Item({
|
||||
label: "item",
|
||||
context: loader.cm.PredicateContext(function (data) {
|
||||
assert.strictEqual(data.isEditable, false);
|
||||
return true;
|
||||
})
|
||||
})];
|
||||
|
||||
test.withTestDoc(function (window, doc) {
|
||||
test.showMenu(doc.getElementById("disabled-textbox"), function (popup) {
|
||||
test.checkMenu(items, [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Test that the data object is showing editable correctly for text areas
|
||||
exports.testPredicateContextTextAreaIsEditable = function (assert, done) {
|
||||
let test = new TestHelper(assert, done);
|
||||
let loader = test.newLoader();
|
||||
|
||||
let items = [loader.cm.Item({
|
||||
label: "item",
|
||||
context: loader.cm.PredicateContext(function (data) {
|
||||
assert.strictEqual(data.isEditable, true);
|
||||
return true;
|
||||
})
|
||||
})];
|
||||
|
||||
test.withTestDoc(function (window, doc) {
|
||||
test.showMenu(doc.getElementById("textfield"), function (popup) {
|
||||
test.checkMenu(items, [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Test that non-text inputs are not considered editable
|
||||
exports.testPredicateContextButtonIsNotEditable = function (assert, done) {
|
||||
let test = new TestHelper(assert, done);
|
||||
let loader = test.newLoader();
|
||||
|
||||
let items = [loader.cm.Item({
|
||||
label: "item",
|
||||
context: loader.cm.PredicateContext(function (data) {
|
||||
assert.strictEqual(data.isEditable, false);
|
||||
return true;
|
||||
})
|
||||
})];
|
||||
|
||||
test.withTestDoc(function (window, doc) {
|
||||
test.showMenu(doc.getElementById("button"), function (popup) {
|
||||
test.checkMenu(items, [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// Test that the data object is showing editable correctly
|
||||
exports.testPredicateContextNonInputIsNotEditable = function (assert, done) {
|
||||
let test = new TestHelper(assert, done);
|
||||
let loader = test.newLoader();
|
||||
|
||||
let items = [loader.cm.Item({
|
||||
label: "item",
|
||||
context: loader.cm.PredicateContext(function (data) {
|
||||
assert.strictEqual(data.isEditable, false);
|
||||
return true;
|
||||
})
|
||||
})];
|
||||
|
||||
test.withTestDoc(function (window, doc) {
|
||||
test.showMenu(doc.getElementById("image"), function (popup) {
|
||||
test.checkMenu(items, [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// Test that the data object is showing editable correctly for HTML contenteditable elements
|
||||
exports.testPredicateContextEditableElement = function (assert, done) {
|
||||
let test = new TestHelper(assert, done);
|
||||
let loader = test.newLoader();
|
||||
|
||||
let items = [loader.cm.Item({
|
||||
label: "item",
|
||||
context: loader.cm.PredicateContext(function (data) {
|
||||
assert.strictEqual(data.isEditable, true);
|
||||
return true;
|
||||
})
|
||||
})];
|
||||
|
||||
test.withTestDoc(function (window, doc) {
|
||||
test.showMenu(doc.getElementById("editable"), function (popup) {
|
||||
test.checkMenu(items, [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// Test that the data object does not have a selection when there is none
|
||||
exports.testPredicateContextNoSelectionInPage = function (assert, done) {
|
||||
let test = new TestHelper(assert, done);
|
||||
let loader = test.newLoader();
|
||||
|
||||
let items = [loader.cm.Item({
|
||||
label: "item",
|
||||
context: loader.cm.PredicateContext(function (data) {
|
||||
assert.strictEqual(data.selectionText, null);
|
||||
return true;
|
||||
})
|
||||
})];
|
||||
|
||||
test.withTestDoc(function (window, doc) {
|
||||
test.showMenu(null, function (popup) {
|
||||
test.checkMenu(items, [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Test that the data object includes the selected page text
|
||||
exports.testPredicateContextSelectionInPage = function (assert, done) {
|
||||
let test = new TestHelper(assert, done);
|
||||
let loader = test.newLoader();
|
||||
|
||||
let items = [loader.cm.Item({
|
||||
label: "item",
|
||||
context: loader.cm.PredicateContext(function (data) {
|
||||
// since we might get whitespace
|
||||
assert.ok(data.selectionText && data.selectionText.search(/^\s*Some text.\s*$/) != -1,
|
||||
'Expected "Some text.", got "' + data.selectionText + '"');
|
||||
return true;
|
||||
})
|
||||
})];
|
||||
|
||||
test.withTestDoc(function (window, doc) {
|
||||
window.getSelection().selectAllChildren(doc.getElementById("text"));
|
||||
test.showMenu(null, function (popup) {
|
||||
test.checkMenu(items, [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Test that the data object includes the selected input text
|
||||
exports.testPredicateContextSelectionInTextBox = function (assert, done) {
|
||||
let test = new TestHelper(assert, done);
|
||||
let loader = test.newLoader();
|
||||
|
||||
let items = [loader.cm.Item({
|
||||
label: "item",
|
||||
context: loader.cm.PredicateContext(function (data) {
|
||||
// since we might get whitespace
|
||||
assert.strictEqual(data.selectionText, "t v");
|
||||
return true;
|
||||
})
|
||||
})];
|
||||
|
||||
test.withTestDoc(function (window, doc) {
|
||||
let textbox = doc.getElementById("textbox");
|
||||
textbox.focus();
|
||||
textbox.setSelectionRange(3, 6);
|
||||
test.showMenu(textbox, function (popup) {
|
||||
test.checkMenu(items, [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Test that the data object has the correct src for an image
|
||||
exports.testPredicateContextTargetSrcSet = function (assert, done) {
|
||||
let test = new TestHelper(assert, done);
|
||||
let loader = test.newLoader();
|
||||
let image;
|
||||
|
||||
let items = [loader.cm.Item({
|
||||
label: "item",
|
||||
context: loader.cm.PredicateContext(function (data) {
|
||||
assert.strictEqual(data.srcURL, image.src);
|
||||
return true;
|
||||
})
|
||||
})];
|
||||
|
||||
test.withTestDoc(function (window, doc) {
|
||||
image = doc.getElementById("image");
|
||||
test.showMenu(image, function (popup) {
|
||||
test.checkMenu(items, [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Test that the data object has no src for a link
|
||||
exports.testPredicateContextTargetSrcNotSet = function (assert, done) {
|
||||
let test = new TestHelper(assert, done);
|
||||
let loader = test.newLoader();
|
||||
|
||||
let items = [loader.cm.Item({
|
||||
label: "item",
|
||||
context: loader.cm.PredicateContext(function (data) {
|
||||
assert.strictEqual(data.srcURL, null);
|
||||
return true;
|
||||
})
|
||||
})];
|
||||
|
||||
test.withTestDoc(function (window, doc) {
|
||||
test.showMenu(doc.getElementById("link"), function (popup) {
|
||||
test.checkMenu(items, [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// Test that the data object has the correct link set
|
||||
exports.testPredicateContextTargetLinkSet = function (assert, done) {
|
||||
let test = new TestHelper(assert, done);
|
||||
let loader = test.newLoader();
|
||||
let image;
|
||||
|
||||
let items = [loader.cm.Item({
|
||||
label: "item",
|
||||
context: loader.cm.PredicateContext(function (data) {
|
||||
assert.strictEqual(data.linkURL, TEST_DOC_URL + "#test");
|
||||
return true;
|
||||
})
|
||||
})];
|
||||
|
||||
test.withTestDoc(function (window, doc) {
|
||||
test.showMenu(doc.getElementsByClassName("predicate-test-a")[0], function (popup) {
|
||||
test.checkMenu(items, [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Test that the data object has no link for an image
|
||||
exports.testPredicateContextTargetLinkNotSet = function (assert, done) {
|
||||
let test = new TestHelper(assert, done);
|
||||
let loader = test.newLoader();
|
||||
|
||||
let items = [loader.cm.Item({
|
||||
label: "item",
|
||||
context: loader.cm.PredicateContext(function (data) {
|
||||
assert.strictEqual(data.linkURL, null);
|
||||
return true;
|
||||
})
|
||||
})];
|
||||
|
||||
test.withTestDoc(function (window, doc) {
|
||||
test.showMenu(doc.getElementById("image"), function (popup) {
|
||||
test.checkMenu(items, [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Test that the data object has the value for an input textbox
|
||||
exports.testPredicateContextTargetValueSet = function (assert, done) {
|
||||
let test = new TestHelper(assert, done);
|
||||
let loader = test.newLoader();
|
||||
let image;
|
||||
|
||||
let items = [loader.cm.Item({
|
||||
label: "item",
|
||||
context: loader.cm.PredicateContext(function (data) {
|
||||
assert.strictEqual(data.value, "test value");
|
||||
return true;
|
||||
})
|
||||
})];
|
||||
|
||||
test.withTestDoc(function (window, doc) {
|
||||
test.showMenu(doc.getElementById("textbox"), function (popup) {
|
||||
test.checkMenu(items, [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Test that the data object has no value for an image
|
||||
exports.testPredicateContextTargetValueNotSet = function (assert, done) {
|
||||
let test = new TestHelper(assert, done);
|
||||
let loader = test.newLoader();
|
||||
|
||||
let items = [loader.cm.Item({
|
||||
label: "item",
|
||||
context: loader.cm.PredicateContext(function (data) {
|
||||
assert.strictEqual(data.value, null);
|
||||
return true;
|
||||
})
|
||||
})];
|
||||
|
||||
test.withTestDoc(function (window, doc) {
|
||||
test.showMenu(doc.getElementById("image"), function (popup) {
|
||||
test.checkMenu(items, [], []);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// NO TESTS BELOW THIS LINE! ///////////////////////////////////////////////////
|
||||
|
||||
// This makes it easier to run tests by handling things like opening the menu,
|
||||
|
1163
addon-sdk/source/test/test-sequence.js
Normal file
1163
addon-sdk/source/test/test-sequence.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -9,6 +9,7 @@ const { getTabForWindow } = require('sdk/tabs/helpers');
|
||||
const app = require("sdk/system/xul-app");
|
||||
const { viewFor } = require("sdk/view/core");
|
||||
const { getTabId } = require("sdk/tabs/utils");
|
||||
const { defer } = require("sdk/lang/functional");
|
||||
|
||||
// The primary test tab
|
||||
var primaryTab;
|
||||
@ -139,14 +140,16 @@ exports["test behavior on close"] = function(assert, done) {
|
||||
};
|
||||
|
||||
exports["test viewFor(tab)"] = (assert, done) => {
|
||||
tabs.once("open", tab => {
|
||||
// Note we defer handlers as length collection is updated after
|
||||
// handler is invoked, so if test is finished before counnts are
|
||||
// updated wrong length will show up in followup tests.
|
||||
tabs.once("open", defer(tab => {
|
||||
const view = viewFor(tab);
|
||||
assert.ok(view, "view is returned");
|
||||
assert.equal(getTabId(view), tab.id, "tab has a same id");
|
||||
|
||||
tab.close();
|
||||
done();
|
||||
});
|
||||
tab.close(defer(done));
|
||||
}));
|
||||
|
||||
tabs.open({ url: "about:mozilla" });
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ const { browserWindows } = require('sdk/windows');
|
||||
const { viewFor } = require('sdk/view/core');
|
||||
const { Ci } = require("chrome");
|
||||
const { isBrowser, getWindowTitle } = require("sdk/window/utils");
|
||||
const { defer } = require("sdk/lang/functional");
|
||||
|
||||
|
||||
// TEST: browserWindows Iterator
|
||||
exports.testBrowserWindowsIterator = function(assert) {
|
||||
@ -30,6 +32,7 @@ exports.testBrowserWindowsIterator = function(assert) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
exports.testWindowTabsObject_alt = function(assert, done) {
|
||||
let window = browserWindows.activeWindow;
|
||||
window.tabs.open({
|
||||
@ -58,6 +61,7 @@ exports.testWindowActivateMethod_simple = function(assert) {
|
||||
'Active tab is active after window.activate() call');
|
||||
};
|
||||
|
||||
|
||||
exports["test getView(window)"] = function(assert, done) {
|
||||
browserWindows.once("open", window => {
|
||||
const view = viewFor(window);
|
||||
@ -68,9 +72,11 @@ exports["test getView(window)"] = function(assert, done) {
|
||||
"window has a right title");
|
||||
|
||||
window.close();
|
||||
window.destroy();
|
||||
assert.equal(viewFor(window), null, "window view is gone");
|
||||
done();
|
||||
// Defer handler cause window is destroyed after event is dispatched.
|
||||
browserWindows.once("close", defer(_ => {
|
||||
assert.equal(viewFor(window), null, "window view is gone");
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user