diff options
Diffstat (limited to 'addon-sdk/source/lib/sdk/deprecated')
-rw-r--r-- | addon-sdk/source/lib/sdk/deprecated/api-utils.js | 197 | ||||
-rw-r--r-- | addon-sdk/source/lib/sdk/deprecated/events/assembler.js | 54 | ||||
-rw-r--r-- | addon-sdk/source/lib/sdk/deprecated/sync-worker.js | 288 | ||||
-rw-r--r-- | addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js | 199 | ||||
-rw-r--r-- | addon-sdk/source/lib/sdk/deprecated/unit-test.js | 584 | ||||
-rw-r--r-- | addon-sdk/source/lib/sdk/deprecated/window-utils.js | 193 |
6 files changed, 0 insertions, 1515 deletions
diff --git a/addon-sdk/source/lib/sdk/deprecated/api-utils.js b/addon-sdk/source/lib/sdk/deprecated/api-utils.js deleted file mode 100644 index 856fc50cb..000000000 --- a/addon-sdk/source/lib/sdk/deprecated/api-utils.js +++ /dev/null @@ -1,197 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -"use strict"; - -module.metadata = { - "stability": "deprecated" -}; - -const { merge } = require("../util/object"); -const { union } = require("../util/array"); -const { isNil, isRegExp } = require("../lang/type"); - -// The possible return values of getTypeOf. -const VALID_TYPES = [ - "array", - "boolean", - "function", - "null", - "number", - "object", - "string", - "undefined", - "regexp" -]; - -const { isArray } = Array; - -/** - * Returns a validated options dictionary given some requirements. If any of - * the requirements are not met, an exception is thrown. - * - * @param options - * An object, the options dictionary to validate. It's not modified. - * If it's null or otherwise falsey, an empty object is assumed. - * @param requirements - * An object whose keys are the expected keys in options. Any key in - * options that is not present in requirements is ignored. Each value - * in requirements is itself an object describing the requirements of - * its key. There are four optional keys in this object: - * map: A function that's passed the value of the key in options. - * map's return value is taken as the key's value in the final - * validated options, is, and ok. If map throws an exception - * it's caught and discarded, and the key's value is its value in - * options. - * is: An array containing any number of the typeof type names. If - * the key's value is none of these types, it fails validation. - * Arrays, null and regexps are identified by the special type names - * "array", "null", "regexp"; "object" will not match either. No type - * coercion is done. - * ok: A function that's passed the key's value. If it returns - * false, the value fails validation. - * msg: If the key's value fails validation, an exception is thrown. - * This string will be used as its message. If undefined, a - * generic message is used, unless is is defined, in which case - * the message will state that the value needs to be one of the - * given types. - * @return An object whose keys are those keys in requirements that are also in - * options and whose values are the corresponding return values of map - * or the corresponding values in options. Note that any keys not - * shared by both requirements and options are not in the returned - * object. - */ -exports.validateOptions = function validateOptions(options, requirements) { - options = options || {}; - let validatedOptions = {}; - - for (let key in requirements) { - let isOptional = false; - let mapThrew = false; - let req = requirements[key]; - let [optsVal, keyInOpts] = (key in options) ? - [options[key], true] : - [undefined, false]; - if (req.map) { - try { - optsVal = req.map(optsVal); - } - catch (err) { - if (err instanceof RequirementError) - throw err; - - mapThrew = true; - } - } - if (req.is) { - let types = req.is; - - if (!isArray(types) && isArray(types.is)) - types = types.is; - - if (isArray(types)) { - isOptional = ['undefined', 'null'].every(v => ~types.indexOf(v)); - - // Sanity check the caller's type names. - types.forEach(function (typ) { - if (VALID_TYPES.indexOf(typ) < 0) { - let msg = 'Internal error: invalid requirement type "' + typ + '".'; - throw new Error(msg); - } - }); - if (types.indexOf(getTypeOf(optsVal)) < 0) - throw new RequirementError(key, req); - } - } - - if (req.ok && ((!isOptional || !isNil(optsVal)) && !req.ok(optsVal))) - throw new RequirementError(key, req); - - if (keyInOpts || (req.map && !mapThrew && optsVal !== undefined)) - validatedOptions[key] = optsVal; - } - - return validatedOptions; -}; - -exports.addIterator = function addIterator(obj, keysValsGenerator) { - obj.__iterator__ = function(keysOnly, keysVals) { - let keysValsIterator = keysValsGenerator.call(this); - - // "for (.. in ..)" gets only keys, "for each (.. in ..)" gets values, - // and "for (.. in Iterator(..))" gets [key, value] pairs. - let index = keysOnly ? 0 : 1; - while (true) - yield keysVals ? keysValsIterator.next() : keysValsIterator.next()[index]; - }; -}; - -// Similar to typeof, except arrays, null and regexps are identified by "array" and -// "null" and "regexp", not "object". -var getTypeOf = exports.getTypeOf = function getTypeOf(val) { - let typ = typeof(val); - if (typ === "object") { - if (!val) - return "null"; - if (isArray(val)) - return "array"; - if (isRegExp(val)) - return "regexp"; - } - return typ; -} - -function RequirementError(key, requirement) { - Error.call(this); - - this.name = "RequirementError"; - - let msg = requirement.msg; - if (!msg) { - msg = 'The option "' + key + '" '; - msg += requirement.is ? - "must be one of the following types: " + requirement.is.join(", ") : - "is invalid."; - } - - this.message = msg; -} -RequirementError.prototype = Object.create(Error.prototype); - -var string = { is: ['string', 'undefined', 'null'] }; -exports.string = string; - -var number = { is: ['number', 'undefined', 'null'] }; -exports.number = number; - -var boolean = { is: ['boolean', 'undefined', 'null'] }; -exports.boolean = boolean; - -var object = { is: ['object', 'undefined', 'null'] }; -exports.object = object; - -var array = { is: ['array', 'undefined', 'null'] }; -exports.array = array; - -var isTruthyType = type => !(type === 'undefined' || type === 'null'); -var findTypes = v => { while (!isArray(v) && v.is) v = v.is; return v }; - -function required(req) { - let types = (findTypes(req) || VALID_TYPES).filter(isTruthyType); - - return merge({}, req, {is: types}); -} -exports.required = required; - -function optional(req) { - req = merge({is: []}, req); - req.is = findTypes(req).filter(isTruthyType).concat('undefined', 'null'); - - return req; -} -exports.optional = optional; - -function either(...types) { - return union.apply(null, types.map(findTypes)); -} -exports.either = either; diff --git a/addon-sdk/source/lib/sdk/deprecated/events/assembler.js b/addon-sdk/source/lib/sdk/deprecated/events/assembler.js deleted file mode 100644 index bb297c24f..000000000 --- a/addon-sdk/source/lib/sdk/deprecated/events/assembler.js +++ /dev/null @@ -1,54 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -"use strict"; - -const { Class } = require("../../core/heritage"); -const { removeListener, on } = require("../../dom/events"); - -/** - * Event targets - * can be added / removed by calling `observe / ignore` methods. Composer should - * provide array of event types it wishes to handle as property - * `supportedEventsTypes` and function for handling all those events as - * `handleEvent` property. - */ -exports.DOMEventAssembler = Class({ - /** - * Function that is supposed to handle all the supported events (that are - * present in the `supportedEventsTypes`) from all the observed - * `eventTargets`. - * @param {Event} event - * Event being dispatched. - */ - handleEvent() { - throw new TypeError("Instance of DOMEventAssembler must implement `handleEvent` method"); - }, - /** - * Array of supported event names. - * @type {String[]} - */ - get supportedEventsTypes() { - throw new TypeError("Instance of DOMEventAssembler must implement `handleEvent` field"); - }, - /** - * Adds `eventTarget` to the list of observed `eventTarget`s. Listeners for - * supported events will be registered on the given `eventTarget`. - * @param {EventTarget} eventTarget - */ - observe: function observe(eventTarget) { - this.supportedEventsTypes.forEach(function(eventType) { - on(eventTarget, eventType, this); - }, this); - }, - /** - * Removes `eventTarget` from the list of observed `eventTarget`s. Listeners - * for all supported events will be unregistered from the given `eventTarget`. - * @param {EventTarget} eventTarget - */ - ignore: function ignore(eventTarget) { - this.supportedEventsTypes.forEach(function(eventType) { - removeListener(eventTarget, eventType, this); - }, this); - } -}); diff --git a/addon-sdk/source/lib/sdk/deprecated/sync-worker.js b/addon-sdk/source/lib/sdk/deprecated/sync-worker.js deleted file mode 100644 index 71cadac36..000000000 --- a/addon-sdk/source/lib/sdk/deprecated/sync-worker.js +++ /dev/null @@ -1,288 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * - * `deprecated/sync-worker` was previously `content/worker`, that was - * incompatible with e10s. we are in the process of switching to the new - * asynchronous `Worker`, which behaves slightly differently in some edge - * cases, so we are keeping this one around for a short period. - * try to switch to the new one as soon as possible.. - * - */ - -"use strict"; - -module.metadata = { - "stability": "unstable" -}; - -const { Class } = require('../core/heritage'); -const { EventTarget } = require('../event/target'); -const { on, off, emit, setListeners } = require('../event/core'); -const { - attach, detach, destroy -} = require('../content/utils'); -const { method } = require('../lang/functional'); -const { Ci, Cu, Cc } = require('chrome'); -const unload = require('../system/unload'); -const events = require('../system/events'); -const { getInnerId } = require("../window/utils"); -const { WorkerSandbox } = require('../content/sandbox'); -const { isPrivate } = require('../private-browsing/utils'); - -// A weak map of workers to hold private attributes that -// should not be exposed -const workers = new WeakMap(); - -var modelFor = (worker) => workers.get(worker); - -const ERR_DESTROYED = - "Couldn't find the worker to receive this message. " + - "The script may not be initialized yet, or may already have been unloaded."; - -const ERR_FROZEN = "The page is currently hidden and can no longer be used " + - "until it is visible again."; - -/** - * Message-passing facility for communication between code running - * in the content and add-on process. - * @see https://developer.mozilla.org/en-US/Add-ons/SDK/Low-Level_APIs/content_worker - */ -const Worker = Class({ - implements: [EventTarget], - initialize: function WorkerConstructor (options) { - // Save model in weak map to not expose properties - let model = createModel(); - workers.set(this, model); - - options = options || {}; - - if ('contentScriptFile' in options) - this.contentScriptFile = options.contentScriptFile; - if ('contentScriptOptions' in options) - this.contentScriptOptions = options.contentScriptOptions; - if ('contentScript' in options) - this.contentScript = options.contentScript; - if ('injectInDocument' in options) - this.injectInDocument = !!options.injectInDocument; - - setListeners(this, options); - - unload.ensure(this, "destroy"); - - // Ensure that worker.port is initialized for contentWorker to be able - // to send events during worker initialization. - this.port = createPort(this); - - model.documentUnload = documentUnload.bind(this); - model.pageShow = pageShow.bind(this); - model.pageHide = pageHide.bind(this); - - if ('window' in options) - attach(this, options.window); - }, - - /** - * Sends a message to the worker's global scope. Method takes single - * argument, which represents data to be sent to the worker. The data may - * be any primitive type value or `JSON`. Call of this method asynchronously - * emits `message` event with data value in the global scope of this - * worker. - * - * `message` event listeners can be set either by calling - * `self.on` with a first argument string `"message"` or by - * implementing `onMessage` function in the global scope of this worker. - * @param {Number|String|JSON} data - */ - postMessage: function (...data) { - let model = modelFor(this); - let args = ['message'].concat(data); - if (!model.inited) { - model.earlyEvents.push(args); - return; - } - processMessage.apply(null, [this].concat(args)); - }, - - get url () { - let model = modelFor(this); - // model.window will be null after detach - return model.window ? model.window.document.location.href : null; - }, - - get contentURL () { - let model = modelFor(this); - return model.window ? model.window.document.URL : null; - }, - - // Implemented to provide some of the previous features of exposing sandbox - // so that Worker can be extended - getSandbox: function () { - return modelFor(this).contentWorker; - }, - - toString: function () { return '[object Worker]'; }, - attach: method(attach), - detach: method(detach), - destroy: method(destroy) -}); -exports.Worker = Worker; - -attach.define(Worker, function (worker, window) { - let model = modelFor(worker); - model.window = window; - // Track document unload to destroy this worker. - // We can't watch for unload event on page's window object as it - // prevents bfcache from working: - // https://developer.mozilla.org/En/Working_with_BFCache - model.windowID = getInnerId(model.window); - events.on("inner-window-destroyed", model.documentUnload); - - // will set model.contentWorker pointing to the private API: - model.contentWorker = WorkerSandbox(worker, model.window); - - // Listen to pagehide event in order to freeze the content script - // while the document is frozen in bfcache: - model.window.addEventListener("pageshow", model.pageShow, true); - model.window.addEventListener("pagehide", model.pageHide, true); - - // Mainly enable worker.port.emit to send event to the content worker - model.inited = true; - model.frozen = false; - - // Fire off `attach` event - emit(worker, 'attach', window); - - // Process all events and messages that were fired before the - // worker was initialized. - model.earlyEvents.forEach(args => processMessage.apply(null, [worker].concat(args))); -}); - -/** - * Remove all internal references to the attached document - * Tells _port to unload itself and removes all the references from itself. - */ -detach.define(Worker, function (worker, reason) { - let model = modelFor(worker); - - // maybe unloaded before content side is created - if (model.contentWorker) { - model.contentWorker.destroy(reason); - } - - model.contentWorker = null; - if (model.window) { - model.window.removeEventListener("pageshow", model.pageShow, true); - model.window.removeEventListener("pagehide", model.pageHide, true); - } - model.window = null; - // This method may be called multiple times, - // avoid dispatching `detach` event more than once - if (model.windowID) { - model.windowID = null; - events.off("inner-window-destroyed", model.documentUnload); - model.earlyEvents.length = 0; - emit(worker, 'detach'); - } - model.inited = false; -}); - -isPrivate.define(Worker, ({ tab }) => isPrivate(tab)); - -/** - * Tells content worker to unload itself and - * removes all the references from itself. - */ -destroy.define(Worker, function (worker, reason) { - detach(worker, reason); - modelFor(worker).inited = true; - // Specifying no type or listener removes all listeners - // from target - off(worker); - off(worker.port); -}); - -/** - * Events fired by workers - */ -function documentUnload ({ subject, data }) { - let model = modelFor(this); - let innerWinID = subject.QueryInterface(Ci.nsISupportsPRUint64).data; - if (innerWinID != model.windowID) return false; - detach(this); - return true; -} - -function pageShow () { - let model = modelFor(this); - model.contentWorker.emitSync('pageshow'); - emit(this, 'pageshow'); - model.frozen = false; -} - -function pageHide () { - let model = modelFor(this); - model.contentWorker.emitSync('pagehide'); - emit(this, 'pagehide'); - model.frozen = true; -} - -/** - * Fired from postMessage and emitEventToContent, or from the earlyMessage - * queue when fired before the content is loaded. Sends arguments to - * contentWorker if able - */ - -function processMessage (worker, ...args) { - let model = modelFor(worker) || {}; - if (!model.contentWorker) - throw new Error(ERR_DESTROYED); - if (model.frozen) - throw new Error(ERR_FROZEN); - model.contentWorker.emit.apply(null, args); -} - -function createModel () { - return { - // List of messages fired before worker is initialized - earlyEvents: [], - // Is worker connected to the content worker sandbox ? - inited: false, - // Is worker being frozen? i.e related document is frozen in bfcache. - // Content script should not be reachable if frozen. - frozen: true, - /** - * Reference to the content side of the worker. - * @type {WorkerGlobalScope} - */ - contentWorker: null, - /** - * Reference to the window that is accessible from - * the content scripts. - * @type {Object} - */ - window: null - }; -} - -function createPort (worker) { - let port = EventTarget(); - port.emit = emitEventToContent.bind(null, worker); - return port; -} - -/** - * Emit a custom event to the content script, - * i.e. emit this event on `self.port` - */ -function emitEventToContent (worker, ...eventArgs) { - let model = modelFor(worker); - let args = ['event'].concat(eventArgs); - if (!model.inited) { - model.earlyEvents.push(args); - return; - } - processMessage.apply(null, [worker].concat(args)); -} diff --git a/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js b/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js deleted file mode 100644 index e38629f45..000000000 --- a/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js +++ /dev/null @@ -1,199 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -"use strict"; - -module.metadata = { - "stability": "deprecated" -}; - -const file = require("../io/file"); -const { Loader } = require("../test/loader"); - -const { isNative } = require('@loader/options'); - -const cuddlefish = isNative ? require("toolkit/loader") : require("../loader/cuddlefish"); - -const { defer, resolve } = require("../core/promise"); -const { getAddon } = require("../addon/installer"); -const { id } = require("sdk/self"); -const { newURI } = require('sdk/url/utils'); -const { getZipReader } = require("../zip/utils"); - -const { Cc, Ci, Cu } = require("chrome"); -const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {}); -var ios = Cc['@mozilla.org/network/io-service;1'] - .getService(Ci.nsIIOService); - -const CFX_TEST_REGEX = /(([^\/]+\/)(?:lib\/)?)?(tests?\/test-[^\.\/]+)\.js$/; -const JPM_TEST_REGEX = /^()(tests?\/test-[^\.\/]+)\.js$/; - -const { mapcat, map, filter, fromEnumerator } = require("sdk/util/sequence"); - -const toFile = x => x.QueryInterface(Ci.nsIFile); -const isTestFile = ({leafName}) => leafName.substr(0, 5) == "test-" && leafName.substr(-3, 3) == ".js"; -const getFileURI = x => ios.newFileURI(x).spec; - -const getDirectoryEntries = file => map(toFile, fromEnumerator(_ => file.directoryEntries)); -const getTestFiles = directory => filter(isTestFile, getDirectoryEntries(directory)); -const getTestURIs = directory => map(getFileURI, getTestFiles(directory)); - -const isDirectory = x => x.isDirectory(); -const getTestEntries = directory => mapcat(entry => - /^tests?$/.test(entry.leafName) ? getTestURIs(entry) : getTestEntries(entry), - filter(isDirectory, getDirectoryEntries(directory))); - -const removeDups = (array) => array.reduce((result, value) => { - if (value != result[result.length - 1]) { - result.push(value); - } - return result; -}, []); - -const getSuites = function getSuites({ id, filter }) { - const TEST_REGEX = isNative ? JPM_TEST_REGEX : CFX_TEST_REGEX; - - return getAddon(id).then(addon => { - let fileURI = addon.getResourceURI("tests/"); - let isPacked = fileURI.scheme == "jar"; - let xpiURI = addon.getResourceURI(); - let file = xpiURI.QueryInterface(Ci.nsIFileURL).file; - let suites = []; - let addEntry = (entry) => { - if (filter(entry) && TEST_REGEX.test(entry)) { - let suite = (isNative ? "./" : "") + (RegExp.$2 || "") + RegExp.$3; - suites.push(suite); - } - } - - if (isPacked) { - return getZipReader(file).then(zip => { - let entries = zip.findEntries(null); - while (entries.hasMore()) { - let entry = entries.getNext(); - addEntry(entry); - } - zip.close(); - - // sort and remove dups - suites = removeDups(suites.sort()); - return suites; - }) - } - else { - let tests = [...getTestEntries(file)]; - let rootURI = addon.getResourceURI("/"); - tests.forEach((entry) => { - addEntry(entry.replace(rootURI.spec, "")); - }); - } - - // sort and remove dups - suites = removeDups(suites.sort()); - return suites; - }); -} -exports.getSuites = getSuites; - -const makeFilters = function makeFilters(options) { - options = options || {}; - - // A filter string is {fileNameRegex}[:{testNameRegex}] - ie, a colon - // optionally separates a regex for the test fileName from a regex for the - // testName. - if (options.filter) { - let colonPos = options.filter.indexOf(':'); - let filterFileRegex, filterNameRegex; - - if (colonPos === -1) { - filterFileRegex = new RegExp(options.filter); - filterNameRegex = { test: () => true } - } - else { - filterFileRegex = new RegExp(options.filter.substr(0, colonPos)); - filterNameRegex = new RegExp(options.filter.substr(colonPos + 1)); - } - - return { - fileFilter: (name) => filterFileRegex.test(name), - testFilter: (name) => filterNameRegex.test(name) - } - } - - return { - fileFilter: () => true, - testFilter: () => true - }; -} -exports.makeFilters = makeFilters; - -var loader = Loader(module); -const NOT_TESTS = ['setup', 'teardown']; - -var TestFinder = exports.TestFinder = function TestFinder(options) { - this.filter = options.filter; - this.testInProcess = options.testInProcess === false ? false : true; - this.testOutOfProcess = options.testOutOfProcess === true ? true : false; -}; - -TestFinder.prototype = { - findTests: function findTests() { - let { fileFilter, testFilter } = makeFilters({ filter: this.filter }); - - return getSuites({ id: id, filter: fileFilter }).then(suites => { - let testsRemaining = []; - - let getNextTest = () => { - if (testsRemaining.length) { - return testsRemaining.shift(); - } - - if (!suites.length) { - return null; - } - - let suite = suites.shift(); - - // Load each test file as a main module in its own loader instance - // `suite` is defined by cuddlefish/manifest.py:ManifestBuilder.build - let suiteModule; - - try { - suiteModule = cuddlefish.main(loader, suite); - } - catch (e) { - if (/Unsupported Application/i.test(e.message)) { - // If `Unsupported Application` error thrown during test, - // skip the test suite - suiteModule = { - 'test suite skipped': assert => assert.pass(e.message) - }; - } - else { - console.exception(e); - throw e; - } - } - - if (this.testInProcess) { - for (let name of Object.keys(suiteModule).sort()) { - if (NOT_TESTS.indexOf(name) === -1 && testFilter(name)) { - testsRemaining.push({ - setup: suiteModule.setup, - teardown: suiteModule.teardown, - testFunction: suiteModule[name], - name: suite + "." + name - }); - } - } - } - - return getNextTest(); - }; - - return { - getNext: () => resolve(getNextTest()) - }; - }); - } -}; diff --git a/addon-sdk/source/lib/sdk/deprecated/unit-test.js b/addon-sdk/source/lib/sdk/deprecated/unit-test.js deleted file mode 100644 index 32bba8f6b..000000000 --- a/addon-sdk/source/lib/sdk/deprecated/unit-test.js +++ /dev/null @@ -1,584 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -"use strict"; - -module.metadata = { - "stability": "deprecated" -}; - -const timer = require("../timers"); -const cfxArgs = require("../test/options"); -const { getTabs, closeTab, getURI, getTabId, getSelectedTab } = require("../tabs/utils"); -const { windows, isBrowser, getMostRecentBrowserWindow } = require("../window/utils"); -const { defer, all, Debugging: PromiseDebugging, resolve } = require("../core/promise"); -const { getInnerId } = require("../window/utils"); -const { cleanUI } = require("../test/utils"); - -const findAndRunTests = function findAndRunTests(options) { - var TestFinder = require("./unit-test-finder").TestFinder; - var finder = new TestFinder({ - filter: options.filter, - testInProcess: options.testInProcess, - testOutOfProcess: options.testOutOfProcess - }); - var runner = new TestRunner({fs: options.fs}); - finder.findTests().then(tests => { - runner.startMany({ - tests: tests, - stopOnError: options.stopOnError, - onDone: options.onDone - }); - }); -}; -exports.findAndRunTests = findAndRunTests; - -var runnerWindows = new WeakMap(); -var runnerTabs = new WeakMap(); - -const TestRunner = function TestRunner(options) { - options = options || {}; - - // remember the id's for the open window and tab - let window = getMostRecentBrowserWindow(); - runnerWindows.set(this, getInnerId(window)); - runnerTabs.set(this, getTabId(getSelectedTab(window))); - - this.fs = options.fs; - this.console = options.console || console; - this.passed = 0; - this.failed = 0; - this.testRunSummary = []; - this.expectFailNesting = 0; - this.done = TestRunner.prototype.done.bind(this); -}; - -TestRunner.prototype = { - toString: function toString() { - return "[object TestRunner]"; - }, - - DEFAULT_PAUSE_TIMEOUT: (cfxArgs.parseable ? 300000 : 15000), //Five minutes (5*60*1000ms) - PAUSE_DELAY: 500, - - _logTestFailed: function _logTestFailed(why) { - if (!(why in this.test.errors)) - this.test.errors[why] = 0; - this.test.errors[why]++; - }, - - _uncaughtErrorObserver: function({message, date, fileName, stack, lineNumber}) { - this.fail("There was an uncaught Promise rejection: " + message + " @ " + - fileName + ":" + lineNumber + "\n" + stack); - }, - - pass: function pass(message) { - if(!this.expectFailure) { - if ("testMessage" in this.console) - this.console.testMessage(true, true, this.test.name, message); - else - this.console.info("pass:", message); - this.passed++; - this.test.passed++; - this.test.last = message; - } - else { - this.expectFailure = false; - this._logTestFailed("failure"); - if ("testMessage" in this.console) { - this.console.testMessage(true, false, this.test.name, message); - } - else { - this.console.error("fail:", 'Failure Expected: ' + message) - this.console.trace(); - } - this.failed++; - this.test.failed++; - } - }, - - fail: function fail(message) { - if(!this.expectFailure) { - this._logTestFailed("failure"); - if ("testMessage" in this.console) { - this.console.testMessage(false, false, this.test.name, message); - } - else { - this.console.error("fail:", message) - this.console.trace(); - } - this.failed++; - this.test.failed++; - } - else { - this.expectFailure = false; - if ("testMessage" in this.console) - this.console.testMessage(false, true, this.test.name, message); - else - this.console.info("pass:", message); - this.passed++; - this.test.passed++; - this.test.last = message; - } - }, - - expectFail: function(callback) { - this.expectFailure = true; - callback(); - this.expectFailure = false; - }, - - exception: function exception(e) { - this._logTestFailed("exception"); - if (cfxArgs.parseable) - this.console.print("TEST-UNEXPECTED-FAIL | " + this.test.name + " | " + e + "\n"); - this.console.exception(e); - this.failed++; - this.test.failed++; - }, - - assertMatches: function assertMatches(string, regexp, message) { - if (regexp.test(string)) { - if (!message) - message = uneval(string) + " matches " + uneval(regexp); - this.pass(message); - } else { - var no = uneval(string) + " doesn't match " + uneval(regexp); - if (!message) - message = no; - else - message = message + " (" + no + ")"; - this.fail(message); - } - }, - - assertRaises: function assertRaises(func, predicate, message) { - try { - func(); - if (message) - this.fail(message + " (no exception thrown)"); - else - this.fail("function failed to throw exception"); - } catch (e) { - var errorMessage; - if (typeof(e) == "string") - errorMessage = e; - else - errorMessage = e.message; - if (typeof(predicate) == "string") - this.assertEqual(errorMessage, predicate, message); - else - this.assertMatches(errorMessage, predicate, message); - } - }, - - assert: function assert(a, message) { - if (!a) { - if (!message) - message = "assertion failed, value is " + a; - this.fail(message); - } else - this.pass(message || "assertion successful"); - }, - - assertNotEqual: function assertNotEqual(a, b, message) { - if (a != b) { - if (!message) - message = "a != b != " + uneval(a); - this.pass(message); - } else { - var equality = uneval(a) + " == " + uneval(b); - if (!message) - message = equality; - else - message += " (" + equality + ")"; - this.fail(message); - } - }, - - assertEqual: function assertEqual(a, b, message) { - if (a == b) { - if (!message) - message = "a == b == " + uneval(a); - this.pass(message); - } else { - var inequality = uneval(a) + " != " + uneval(b); - if (!message) - message = inequality; - else - message += " (" + inequality + ")"; - this.fail(message); - } - }, - - assertNotStrictEqual: function assertNotStrictEqual(a, b, message) { - if (a !== b) { - if (!message) - message = "a !== b !== " + uneval(a); - this.pass(message); - } else { - var equality = uneval(a) + " === " + uneval(b); - if (!message) - message = equality; - else - message += " (" + equality + ")"; - this.fail(message); - } - }, - - assertStrictEqual: function assertStrictEqual(a, b, message) { - if (a === b) { - if (!message) - message = "a === b === " + uneval(a); - this.pass(message); - } else { - var inequality = uneval(a) + " !== " + uneval(b); - if (!message) - message = inequality; - else - message += " (" + inequality + ")"; - this.fail(message); - } - }, - - assertFunction: function assertFunction(a, message) { - this.assertStrictEqual('function', typeof a, message); - }, - - assertUndefined: function(a, message) { - this.assertStrictEqual('undefined', typeof a, message); - }, - - assertNotUndefined: function(a, message) { - this.assertNotStrictEqual('undefined', typeof a, message); - }, - - assertNull: function(a, message) { - this.assertStrictEqual(null, a, message); - }, - - assertNotNull: function(a, message) { - this.assertNotStrictEqual(null, a, message); - }, - - assertObject: function(a, message) { - this.assertStrictEqual('[object Object]', Object.prototype.toString.apply(a), message); - }, - - assertString: function(a, message) { - this.assertStrictEqual('[object String]', Object.prototype.toString.apply(a), message); - }, - - assertArray: function(a, message) { - this.assertStrictEqual('[object Array]', Object.prototype.toString.apply(a), message); - }, - - assertNumber: function(a, message) { - this.assertStrictEqual('[object Number]', Object.prototype.toString.apply(a), message); - }, - - done: function done() { - if (this.isDone) { - return resolve(); - } - - this.isDone = true; - this.pass("This test is done."); - - if (this.test.teardown) { - this.test.teardown(this); - } - - if (this.waitTimeout !== null) { - timer.clearTimeout(this.waitTimeout); - this.waitTimeout = null; - } - - // Do not leave any callback set when calling to `waitUntil` - this.waitUntilCallback = null; - if (this.test.passed == 0 && this.test.failed == 0) { - this._logTestFailed("empty test"); - - if ("testMessage" in this.console) { - this.console.testMessage(false, false, this.test.name, "Empty test"); - } - else { - this.console.error("fail:", "Empty test") - } - - this.failed++; - this.test.failed++; - } - - let wins = windows(null, { includePrivate: true }); - let winPromises = wins.map(win => { - return new Promise(resolve => { - if (["interactive", "complete"].indexOf(win.document.readyState) >= 0) { - resolve() - } - else { - win.addEventListener("DOMContentLoaded", function onLoad() { - win.removeEventListener("DOMContentLoaded", onLoad, false); - resolve(); - }, false); - } - }); - }); - - PromiseDebugging.flushUncaughtErrors(); - PromiseDebugging.removeUncaughtErrorObserver(this._uncaughtErrorObserver); - - - return all(winPromises).then(() => { - let browserWins = wins.filter(isBrowser); - let tabs = browserWins.reduce((tabs, window) => tabs.concat(getTabs(window)), []); - let newTabID = getTabId(getSelectedTab(wins[0])); - let oldTabID = runnerTabs.get(this); - let hasMoreTabsOpen = browserWins.length && tabs.length != 1; - let failure = false; - - if (wins.length != 1 || getInnerId(wins[0]) !== runnerWindows.get(this)) { - failure = true; - this.fail("Should not be any unexpected windows open"); - } - else if (hasMoreTabsOpen) { - failure = true; - this.fail("Should not be any unexpected tabs open"); - } - else if (oldTabID != newTabID) { - failure = true; - runnerTabs.set(this, newTabID); - this.fail("Should not be any new tabs left open, old id: " + oldTabID + " new id: " + newTabID); - } - - if (failure) { - console.log("Windows open:"); - for (let win of wins) { - if (isBrowser(win)) { - tabs = getTabs(win); - console.log(win.location + " - " + tabs.map(getURI).join(", ")); - } - else { - console.log(win.location); - } - } - } - - return failure; - }). - then(failure => { - if (!failure) { - this.pass("There was a clean UI."); - return null; - } - return cleanUI().then(() => { - this.pass("There is a clean UI."); - }); - }). - then(() => { - this.testRunSummary.push({ - name: this.test.name, - passed: this.test.passed, - failed: this.test.failed, - errors: Object.keys(this.test.errors).join(", ") - }); - - if (this.onDone !== null) { - let onDone = this.onDone; - this.onDone = null; - timer.setTimeout(_ => onDone(this)); - } - }). - catch(console.exception); - }, - - // Set of assertion functions to wait for an assertion to become true - // These functions take the same arguments as the TestRunner.assert* methods. - waitUntil: function waitUntil() { - return this._waitUntil(this.assert, arguments); - }, - - waitUntilNotEqual: function waitUntilNotEqual() { - return this._waitUntil(this.assertNotEqual, arguments); - }, - - waitUntilEqual: function waitUntilEqual() { - return this._waitUntil(this.assertEqual, arguments); - }, - - waitUntilMatches: function waitUntilMatches() { - return this._waitUntil(this.assertMatches, arguments); - }, - - /** - * Internal function that waits for an assertion to become true. - * @param {Function} assertionMethod - * Reference to a TestRunner assertion method like test.assert, - * test.assertEqual, ... - * @param {Array} args - * List of arguments to give to the previous assertion method. - * All functions in this list are going to be called to retrieve current - * assertion values. - */ - _waitUntil: function waitUntil(assertionMethod, args) { - let { promise, resolve } = defer(); - let count = 0; - let maxCount = this.DEFAULT_PAUSE_TIMEOUT / this.PAUSE_DELAY; - - // We need to ensure that test is asynchronous - if (!this.waitTimeout) - this.waitUntilDone(this.DEFAULT_PAUSE_TIMEOUT); - - let finished = false; - let test = this; - - // capture a traceback before we go async. - let traceback = require("../console/traceback"); - let stack = traceback.get(); - stack.splice(-2, 2); - let currentWaitStack = traceback.format(stack); - let timeout = null; - - function loop(stopIt) { - timeout = null; - - // Build a mockup object to fake TestRunner API and intercept calls to - // pass and fail methods, in order to retrieve nice error messages - // and assertion result - let mock = { - pass: function (msg) { - test.pass(msg); - test.waitUntilCallback = null; - if (!stopIt) - resolve(); - }, - fail: function (msg) { - // If we are called on test timeout, we stop the loop - // and print which test keeps failing: - if (stopIt) { - test.console.error("test assertion never became true:\n", - msg + "\n", - currentWaitStack); - if (timeout) - timer.clearTimeout(timeout); - return; - } - timeout = timer.setTimeout(loop, test.PAUSE_DELAY); - } - }; - - // Automatically call args closures in order to build arguments for - // assertion function - let appliedArgs = []; - for (let i = 0, l = args.length; i < l; i++) { - let a = args[i]; - if (typeof a == "function") { - try { - a = a(); - } - catch(e) { - test.fail("Exception when calling asynchronous assertion: " + e + - "\n" + e.stack); - return resolve(); - } - } - appliedArgs.push(a); - } - - // Finally call assertion function with current assertion values - assertionMethod.apply(mock, appliedArgs); - } - loop(); - this.waitUntilCallback = loop; - - return promise; - }, - - waitUntilDone: function waitUntilDone(ms) { - if (ms === undefined) - ms = this.DEFAULT_PAUSE_TIMEOUT; - - var self = this; - - function tiredOfWaiting() { - self._logTestFailed("timed out"); - if ("testMessage" in self.console) { - self.console.testMessage(false, false, self.test.name, - `Test timed out (after: ${self.test.last})`); - } - else { - self.console.error("fail:", `Timed out (after: ${self.test.last})`) - } - if (self.waitUntilCallback) { - self.waitUntilCallback(true); - self.waitUntilCallback = null; - } - self.failed++; - self.test.failed++; - self.done(); - } - - // We may already have registered a timeout callback - if (this.waitTimeout) - timer.clearTimeout(this.waitTimeout); - - this.waitTimeout = timer.setTimeout(tiredOfWaiting, ms); - }, - - startMany: function startMany(options) { - function runNextTest(self) { - let { tests, onDone } = options; - - return tests.getNext().then((test) => { - if (options.stopOnError && self.test && self.test.failed) { - self.console.error("aborted: test failed and --stop-on-error was specified"); - onDone(self); - } - else if (test) { - self.start({test: test, onDone: runNextTest}); - } - else { - onDone(self); - } - }); - } - - return runNextTest(this).catch(console.exception); - }, - - start: function start(options) { - this.test = options.test; - this.test.passed = 0; - this.test.failed = 0; - this.test.errors = {}; - this.test.last = 'START'; - PromiseDebugging.clearUncaughtErrorObservers(); - this._uncaughtErrorObserver = this._uncaughtErrorObserver.bind(this); - PromiseDebugging.addUncaughtErrorObserver(this._uncaughtErrorObserver); - - this.isDone = false; - this.onDone = function(self) { - if (cfxArgs.parseable) - self.console.print("TEST-END | " + self.test.name + "\n"); - options.onDone(self); - } - this.waitTimeout = null; - - try { - if (cfxArgs.parseable) - this.console.print("TEST-START | " + this.test.name + "\n"); - else - this.console.info("executing '" + this.test.name + "'"); - - if(this.test.setup) { - this.test.setup(this); - } - this.test.testFunction(this); - } catch (e) { - this.exception(e); - } - if (this.waitTimeout === null) - this.done(); - } -}; -exports.TestRunner = TestRunner; diff --git a/addon-sdk/source/lib/sdk/deprecated/window-utils.js b/addon-sdk/source/lib/sdk/deprecated/window-utils.js deleted file mode 100644 index 93c0ab7b8..000000000 --- a/addon-sdk/source/lib/sdk/deprecated/window-utils.js +++ /dev/null @@ -1,193 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -'use strict'; - -module.metadata = { - 'stability': 'deprecated' -}; - -const { Cc, Ci } = require('chrome'); -const events = require('../system/events'); -const { getInnerId, getOuterId, windows, isDocumentLoaded, isBrowser, - getMostRecentBrowserWindow, getToplevelWindow, getMostRecentWindow } = require('../window/utils'); -const { deprecateFunction } = require('../util/deprecate'); -const { ignoreWindow } = require('sdk/private-browsing/utils'); -const { isPrivateBrowsingSupported } = require('../self'); - -const windowWatcher = Cc['@mozilla.org/embedcomp/window-watcher;1']. - getService(Ci.nsIWindowWatcher); -const appShellService = Cc['@mozilla.org/appshell/appShellService;1']. - getService(Ci.nsIAppShellService); - -// Bug 834961: ignore private windows when they are not supported -function getWindows() { - return windows(null, { includePrivate: isPrivateBrowsingSupported }); -} - -/** - * An iterator for XUL windows currently in the application. - * - * @return A generator that yields XUL windows exposing the - * nsIDOMWindow interface. - */ -function windowIterator() { - // Bug 752631: We only pass already loaded window in order to avoid - // breaking XUL windows DOM. DOM is broken when some JS code try - // to access DOM during "uninitialized" state of the related document. - let list = getWindows().filter(isDocumentLoaded); - for (let i = 0, l = list.length; i < l; i++) { - yield list[i]; - } -}; -exports.windowIterator = windowIterator; - -/** - * An iterator for browser windows currently open in the application. - * @returns {Function} - * A generator that yields browser windows exposing the `nsIDOMWindow` - * interface. - */ -function browserWindowIterator() { - for (let window of windowIterator()) { - if (isBrowser(window)) - yield window; - } -} -exports.browserWindowIterator = browserWindowIterator; - -function WindowTracker(delegate) { - if (!(this instanceof WindowTracker)) { - return new WindowTracker(delegate); - } - - this._delegate = delegate; - - for (let window of getWindows()) - this._regWindow(window); - windowWatcher.registerNotification(this); - this._onToplevelWindowReady = this._onToplevelWindowReady.bind(this); - events.on('toplevel-window-ready', this._onToplevelWindowReady); - - require('../system/unload').ensure(this); - - return this; -}; - -WindowTracker.prototype = { - _regLoadingWindow: function _regLoadingWindow(window) { - // Bug 834961: ignore private windows when they are not supported - if (ignoreWindow(window)) - return; - - window.addEventListener('load', this, true); - }, - - _unregLoadingWindow: function _unregLoadingWindow(window) { - // This may have no effect if we ignored the window in _regLoadingWindow(). - window.removeEventListener('load', this, true); - }, - - _regWindow: function _regWindow(window) { - // Bug 834961: ignore private windows when they are not supported - if (ignoreWindow(window)) - return; - - if (window.document.readyState == 'complete') { - this._unregLoadingWindow(window); - this._delegate.onTrack(window); - } else - this._regLoadingWindow(window); - }, - - _unregWindow: function _unregWindow(window) { - if (window.document.readyState == 'complete') { - if (this._delegate.onUntrack) - this._delegate.onUntrack(window); - } else { - this._unregLoadingWindow(window); - } - }, - - unload: function unload() { - windowWatcher.unregisterNotification(this); - events.off('toplevel-window-ready', this._onToplevelWindowReady); - for (let window of getWindows()) - this._unregWindow(window); - }, - - handleEvent: function handleEvent(event) { - try { - if (event.type == 'load' && event.target) { - var window = event.target.defaultView; - if (window) - this._regWindow(getToplevelWindow(window)); - } - } - catch(e) { - console.exception(e); - } - }, - - _onToplevelWindowReady: function _onToplevelWindowReady({subject}) { - let window = getToplevelWindow(subject); - // ignore private windows if they are not supported - if (ignoreWindow(window)) - return; - this._regWindow(window); - }, - - observe: function observe(subject, topic, data) { - try { - var window = subject.QueryInterface(Ci.nsIDOMWindow); - // ignore private windows if they are not supported - if (ignoreWindow(window)) - return; - if (topic == 'domwindowclosed') - this._unregWindow(window); - } - catch(e) { - console.exception(e); - } - } -}; -exports.WindowTracker = WindowTracker; - -Object.defineProperties(exports, { - activeWindow: { - enumerable: true, - get: function() { - return getMostRecentWindow(null); - }, - set: function(window) { - try { - window.focus(); - } catch (e) {} - } - }, - activeBrowserWindow: { - enumerable: true, - get: getMostRecentBrowserWindow - } -}); - - -/** - * Returns the ID of the window's current inner window. - */ -exports.getInnerId = deprecateFunction(getInnerId, - 'require("window-utils").getInnerId is deprecated, ' + - 'please use require("sdk/window/utils").getInnerId instead' -); - -exports.getOuterId = deprecateFunction(getOuterId, - 'require("window-utils").getOuterId is deprecated, ' + - 'please use require("sdk/window/utils").getOuterId instead' -); - -exports.isBrowser = deprecateFunction(isBrowser, - 'require("window-utils").isBrowser is deprecated, ' + - 'please use require("sdk/window/utils").isBrowser instead' -); - -exports.hiddenWindow = appShellService.hiddenDOMWindow; |