diff --git a/addon-sdk/source/lib/sdk/addon/runner.js b/addon-sdk/source/lib/sdk/addon/runner.js index 13063f34120da..7391c4c6169c8 100644 --- a/addon-sdk/source/lib/sdk/addon/runner.js +++ b/addon-sdk/source/lib/sdk/addon/runner.js @@ -125,8 +125,9 @@ function run(options) { // Do not enable HTML localization while running test as it is hard to // disable. Because unit tests are evaluated in a another Loader who // doesn't have access to this current loader. - if (options.main !== 'test-harness/run-tests') + if (options.main !== 'sdk/test/runner') { require('../l10n/html').enable(); + } } catch(error) { console.exception(error); diff --git a/addon-sdk/source/lib/sdk/context-menu.js b/addon-sdk/source/lib/sdk/context-menu.js index 0c9ebe0cb03f3..860adf8c0f7e3 100644 --- a/addon-sdk/source/lib/sdk/context-menu.js +++ b/addon-sdk/source/lib/sdk/context-menu.js @@ -259,9 +259,13 @@ function populateCallbackNodeData(node) { data.selectionText = selection.text; data.srcURL = node.src || null; - data.linkURL = node.href || null; data.value = node.value || null; + while (!data.linkURL && node) { + data.linkURL = node.href || null; + node = node.parentNode; + } + return data; } diff --git a/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js b/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js index 368efdcc6d3f8..750292c011158 100644 --- a/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js +++ b/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js @@ -10,7 +10,11 @@ module.metadata = { const file = require("../io/file"); const memory = require('./memory'); const { Loader } = require("../test/loader"); -const cuddlefish = require("../loader/cuddlefish"); + +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"); @@ -22,7 +26,7 @@ const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {} var ios = Cc['@mozilla.org/network/io-service;1'] .getService(Ci.nsIIOService); -const TEST_REGEX = /(([^\/]+\/)(?:lib\/)?)(tests?\/test-[^\.\/]+)\.js$/; +const TEST_REGEX = /(([^\/]+\/)(?:lib\/)?)?(tests?\/test-[^\.\/]+)\.js$/; const { mapcat, map, filter, fromEnumerator } = require("sdk/util/sequence"); @@ -54,8 +58,9 @@ const getSuites = function getSuites({ id }) { let file = xpiURI.QueryInterface(Ci.nsIFileURL).file; let suites = []; let addEntry = (entry) => { - if (TEST_REGEX.test(entry)) { - let suite = RegExp.$2 + RegExp.$3; + let pass = TEST_REGEX.test(entry); + if (pass) { + let suite = (isNative ? "./" : "") + RegExp.$2 + RegExp.$3; suites.push(suite); } } diff --git a/addon-sdk/source/lib/sdk/deprecated/unit-test.js b/addon-sdk/source/lib/sdk/deprecated/unit-test.js index fb615653e7df3..7fef7ca82592d 100644 --- a/addon-sdk/source/lib/sdk/deprecated/unit-test.js +++ b/addon-sdk/source/lib/sdk/deprecated/unit-test.js @@ -12,7 +12,7 @@ const timer = require("../timers"); var cfxArgs = require("@test/options"); const { getTabs, getURI } = require("../tabs/utils"); const { windows, isBrowser } = require("../window/utils"); -const { defer } = require("../core/promise"); +const { defer, all } = require("../core/promise"); const findAndRunTests = function findAndRunTests(options) { var TestFinder = require("./unit-test-finder").TestFinder; @@ -285,43 +285,58 @@ TestRunner.prototype = { } let wins = windows(null, { includePrivate: true }); - let tabs = []; - for (let win of wins.filter(isBrowser)) { - for (let tab of getTabs(win)) { - tabs.push(tab); + let winPromises = wins.map(win => { + let { promise, resolve } = defer(); + if (["interactive", "complete"].indexOf(win.document.readyState) >= 0) { + resolve() } - } + else { + win.addEventListener("DOMContentLoaded", function onLoad() { + win.removeEventListener("DOMContentLoaded", onLoad, false); + resolve(); + }, false); + } + return promise; + }); - if (wins.length != 1) - this.fail("Should not be any unexpected windows open"); - if (tabs.length != 1) - this.fail("Should not be any unexpected tabs open"); - if (tabs.length != 1 || wins.length != 1) { - console.log("Windows open:"); - for (let win of wins) { - if (isBrowser(win)) { - tabs = getTabs(win); - console.log(win.location + " - " + tabs.map(getURI).join(", ")); + all(winPromises).then(_ => { + let tabs = []; + for (let win of wins.filter(isBrowser)) { + for (let tab of getTabs(win)) { + tabs.push(tab); } - else { - console.log(win.location); + } + + if (wins.length != 1) + this.fail("Should not be any unexpected windows open"); + if (tabs.length != 1) + this.fail("Should not be any unexpected tabs open"); + if (tabs.length != 1 || wins.length != 1) { + console.log("Windows open:"); + for (let win of wins) { + if (isBrowser(win)) { + tabs = getTabs(win); + console.log(win.location + " - " + tabs.map(getURI).join(", ")); + } + else { + console.log(win.location); + } } } - } - this.testRunSummary.push({ - name: this.test.name, - passed: this.test.passed, - failed: this.test.failed, - errors: [error for (error in this.test.errors)].join(", ") + this.testRunSummary.push({ + name: this.test.name, + passed: this.test.passed, + failed: this.test.failed, + errors: [error for (error in this.test.errors)].join(", ") + }); + + if (this.onDone !== null) { + let onDone = this.onDone; + this.onDone = null; + timer.setTimeout(_ => onDone(this), 0); + } }); - - if (this.onDone !== null) { - var onDone = this.onDone; - var self = this; - this.onDone = null; - timer.setTimeout(function() { onDone(self); }, 0); - } } }, diff --git a/addon-sdk/source/lib/sdk/tabs/tab-fennec.js b/addon-sdk/source/lib/sdk/tabs/tab-fennec.js index c78af1b5fcdc2..e823d51053e51 100644 --- a/addon-sdk/source/lib/sdk/tabs/tab-fennec.js +++ b/addon-sdk/source/lib/sdk/tabs/tab-fennec.js @@ -7,9 +7,9 @@ const { Cc, Ci } = require('chrome'); const { Class } = require('../core/heritage'); const { tabNS, rawTabNS } = require('./namespace'); const { EventTarget } = require('../event/target'); -const { activateTab, getTabTitle, setTabTitle, closeTab, getTabURL, getTabContentWindow, - getTabForBrowser, - setTabURL, getOwnerWindow, getTabContentType, getTabId } = require('./utils'); +const { activateTab, getTabTitle, setTabTitle, closeTab, getTabURL, + getTabContentWindow, getTabForBrowser, setTabURL, getOwnerWindow, + getTabContentDocument, getTabContentType, getTabId } = require('./utils'); const { emit } = require('../event/core'); const { isPrivate } = require('../private-browsing/utils'); const { isWindowPrivate } = require('../window/utils'); @@ -97,6 +97,14 @@ const Tab = Class({ return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAAtCAYAAAA5reyyAAAAJElEQVRoge3BAQEAAACCIP+vbkhAAQAAAAAAAAAAAAAAAADXBjhtAAGQ0AF/AAAAAElFTkSuQmCC'; }, + /** + * tab's document readyState, or 'uninitialized' if it doesn't even exist yet. + */ + get readyState() { + let doc = getTabContentDocument(tabNS(this).tab); + return doc && doc.readyState || 'uninitialized'; + }, + get id() { return getTabId(tabNS(this).tab); }, diff --git a/addon-sdk/source/lib/sdk/tabs/tab-firefox.js b/addon-sdk/source/lib/sdk/tabs/tab-firefox.js index ae4851c68ba3b..fde97dcba1ea5 100644 --- a/addon-sdk/source/lib/sdk/tabs/tab-firefox.js +++ b/addon-sdk/source/lib/sdk/tabs/tab-firefox.js @@ -10,8 +10,9 @@ const { has } = require("../util/array"); const { EVENTS } = require("./events"); const { getThumbnailURIForWindow } = require("../content/thumbnail"); const { getFaviconURIForLocation } = require("../io/data"); -const { activateTab, getOwnerWindow, getBrowserForTab, getTabTitle, setTabTitle, - getTabURL, setTabURL, getTabContentType, getTabId } = require('./utils'); +const { activateTab, getOwnerWindow, getBrowserForTab, getTabTitle, + setTabTitle, getTabContentDocument, getTabURL, setTabURL, + getTabContentType, getTabId } = require('./utils'); const { isPrivate } = require('../private-browsing/utils'); const { isWindowPrivate } = require('../window/utils'); const viewNS = require('../core/namespace').ns(); @@ -143,12 +144,20 @@ const TabTrait = Trait.compose(EventEmitter, { /** * Document object of the page that is currently loaded in this tab. */ - get _contentDocument() this._browser.contentDocument, + get _contentDocument() getTabContentDocument(this._tab), /** * Window object of the page that is currently loaded in this tab. */ get _contentWindow() this._browser.contentWindow, + /** + * tab's document readyState, or 'uninitialized' if it doesn't even exist yet. + */ + get readyState() { + let doc = this._contentDocument; + return doc && doc.readyState || 'uninitialized'; + }, + /** * Unique id for the tab, actually maps to tab.linkedPanel but with some munging. */ diff --git a/addon-sdk/source/lib/sdk/tabs/utils.js b/addon-sdk/source/lib/sdk/tabs/utils.js index 6909cce006df5..63f7c92b6918a 100644 --- a/addon-sdk/source/lib/sdk/tabs/utils.js +++ b/addon-sdk/source/lib/sdk/tabs/utils.js @@ -226,6 +226,11 @@ function setTabTitle(tab, title) { } exports.setTabTitle = setTabTitle; +function getTabContentDocument(tab) { + return getBrowserForTab(tab).contentDocument; +} +exports.getTabContentDocument = getTabContentDocument; + function getTabContentWindow(tab) { return getBrowserForTab(tab).contentWindow; } diff --git a/addon-sdk/source/lib/sdk/test.js b/addon-sdk/source/lib/sdk/test.js index 46ceab2654af3..4d6ab2cf1ab0f 100644 --- a/addon-sdk/source/lib/sdk/test.js +++ b/addon-sdk/source/lib/sdk/test.js @@ -1,7 +1,6 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - "use strict"; module.metadata = { @@ -13,19 +12,10 @@ const { Task } = Cu.import("resource://gre/modules/Task.jsm", {}); const { defer } = require("sdk/core/promise"); const BaseAssert = require("sdk/test/assert").Assert; const { isFunction, isObject } = require("sdk/lang/type"); +const { extend } = require("sdk/util/object"); exports.Assert = BaseAssert; -function extend(target) { - let descriptor = {} - Array.slice(arguments, 1).forEach(function(source) { - Object.getOwnPropertyNames(source).forEach(function onEach(name) { - descriptor[name] = Object.getOwnPropertyDescriptor(source, name); - }); - }); - return Object.create(target, descriptor); -} - /** * Function takes test `suite` object in CommonJS format and defines all of the * tests from that suite and nested suites in a jetpack format on a given @@ -110,7 +100,6 @@ function defineTestSuite(target, suite, prefix) { * test runner will be able to run CommonJS test without manual changes. */ exports.run = function run(exports) { - // We can't leave old properties on exports since those are test in a CommonJS // format that why we move everything to a new `suite` object. let suite = {}; diff --git a/addon-sdk/source/python-lib/cuddlefish/__init__.py b/addon-sdk/source/python-lib/cuddlefish/__init__.py index 6e86615ccbc32..5b721604e7883 100644 --- a/addon-sdk/source/python-lib/cuddlefish/__init__.py +++ b/addon-sdk/source/python-lib/cuddlefish/__init__.py @@ -791,7 +791,6 @@ def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None, extra_environment = {} if command == "test": # This should be contained in the test runner package. - # maybe just do: target_cfg.main = 'test-harness/run-tests' harness_options['main'] = 'sdk/test/runner' harness_options['mainPath'] = 'sdk/test/runner' else: diff --git a/addon-sdk/source/test/test-context-menu.html b/addon-sdk/source/test/test-context-menu.html index 1d4304b87351a..63a365ae794a8 100644 --- a/addon-sdk/source/test/test-context-menu.html +++ b/addon-sdk/source/test/test-context-menu.html @@ -62,6 +62,23 @@
++ + + +
++ + + + + A complex nested structure. + + + + +
+diff --git a/addon-sdk/source/test/test-context-menu.js b/addon-sdk/source/test/test-context-menu.js index 997af80cc0e22..7eafc8b691641 100644 --- a/addon-sdk/source/test/test-context-menu.js +++ b/addon-sdk/source/test/test-context-menu.js @@ -3572,6 +3572,48 @@ exports.testPredicateContextTargetLinkNotSet = function (assert, done) { }); }; +// Test that the data object has the correct link for a nested image +exports.testPredicateContextTargetLinkSetNestedImage = 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, TEST_DOC_URL + "#nested-image"); + return true; + }) + })]; + + test.withTestDoc(function (window, doc) { + test.showMenu(doc.getElementById("predicate-test-nested-image"), function (popup) { + test.checkMenu(items, [], []); + test.done(); + }); + }); +}; + +// Test that the data object has the correct link for a complex nested structure +exports.testPredicateContextTargetLinkSetNestedStructure = 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, TEST_DOC_URL + "#nested-structure"); + return true; + }) + })]; + + test.withTestDoc(function (window, doc) { + test.showMenu(doc.getElementById("predicate-test-nested-structure"), 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); diff --git a/addon-sdk/source/test/test-tab.js b/addon-sdk/source/test/test-tab.js index c49b431dcfd60..5b487092bfc92 100644 --- a/addon-sdk/source/test/test-tab.js +++ b/addon-sdk/source/test/test-tab.js @@ -172,4 +172,22 @@ exports["test modelFor(xulTab)"] = (assert, done) => { }); }; +exports["test tab.readyState"] = (assert, done) => { + tabs.open({ + url: "data:text/html;charset=utf-8,test_readyState", + onOpen: (tab) => { + assert.equal(tab.readyState, "uninitialized", + "tab is 'uninitialized' when opened"); + }, + onReady: (tab) => { + assert.notEqual(["interactive", "complete"].indexOf(tab.readyState), -1, + "tab is either interactive or complete when onReady"); + }, + onLoad: (tab) => { + assert.equal(tab.readyState, "complete", "tab is complete onLoad"); + tab.close(defer(done)); + } + }); +} + require("sdk/test").run(exports);