зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1073238 - Split UITour.jsm into chrome and content parts that communicate via messages. r=MattN
This commit is contained in:
Родитель
64d2cea345
Коммит
1b9c50100d
|
@ -853,6 +853,7 @@ var gBrowserInit = {
|
|||
|
||||
let mm = window.getGroupMessageManager("browsers");
|
||||
mm.loadFrameScript("chrome://browser/content/content.js", true);
|
||||
mm.loadFrameScript("chrome://browser/content/content-UITour.js", true);
|
||||
|
||||
// initialize observers and listeners
|
||||
// and give C++ access to gBrowser
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
let {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
const PREF_TEST_WHITELIST = "browser.uitour.testingOrigins";
|
||||
const UITOUR_PERMISSION = "uitour";
|
||||
|
||||
let UITourListener = {
|
||||
handleEvent: function (event) {
|
||||
if (!Services.prefs.getBoolPref("browser.uitour.enabled")) {
|
||||
return;
|
||||
}
|
||||
if (!this.ensureTrustedOrigin()) {
|
||||
return;
|
||||
}
|
||||
addMessageListener("UITour:SendPageCallback", this);
|
||||
sendAsyncMessage("UITour:onPageEvent", {detail: event.detail, type: event.type});
|
||||
},
|
||||
|
||||
isTestingOrigin: function(aURI) {
|
||||
if (Services.prefs.getPrefType(PREF_TEST_WHITELIST) != Services.prefs.PREF_STRING) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add any testing origins (comma-seperated) to the whitelist for the session.
|
||||
for (let origin of Services.prefs.getCharPref(PREF_TEST_WHITELIST).split(",")) {
|
||||
try {
|
||||
let testingURI = Services.io.newURI(origin, null, null);
|
||||
if (aURI.prePath == testingURI.prePath) {
|
||||
return true;
|
||||
}
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
// This function is copied from UITour.jsm.
|
||||
isSafeScheme: function(aURI) {
|
||||
let allowedSchemes = new Set(["https", "about"]);
|
||||
if (!Services.prefs.getBoolPref("browser.uitour.requireSecure"))
|
||||
allowedSchemes.add("http");
|
||||
|
||||
if (!allowedSchemes.has(aURI.scheme))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
ensureTrustedOrigin: function() {
|
||||
if (content.top != content)
|
||||
return false;
|
||||
|
||||
let uri = content.document.documentURIObject;
|
||||
|
||||
if (uri.schemeIs("chrome"))
|
||||
return true;
|
||||
|
||||
if (!this.isSafeScheme(uri))
|
||||
return false;
|
||||
|
||||
let permission = Services.perms.testPermission(uri, UITOUR_PERMISSION);
|
||||
if (permission == Services.perms.ALLOW_ACTION)
|
||||
return true;
|
||||
|
||||
return this.isTestingOrigin(uri);
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
switch (aMessage.name) {
|
||||
case "UITour:SendPageCallback":
|
||||
this.sendPageCallback(aMessage.data);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
sendPageCallback: function (detail) {
|
||||
let doc = content.document;
|
||||
let event = new doc.defaultView.CustomEvent("mozUITourResponse", {
|
||||
bubbles: true,
|
||||
detail: Cu.cloneInto(detail, doc.defaultView)
|
||||
});
|
||||
doc.dispatchEvent(event);
|
||||
}
|
||||
};
|
||||
|
||||
addEventListener("mozUITour", UITourListener, false, true);
|
|
@ -25,8 +25,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "PluginContent",
|
|||
"resource:///modules/PluginContent.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "UITour",
|
||||
"resource:///modules/UITour.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FormSubmitObserver",
|
||||
"resource:///modules/FormSubmitObserver.jsm");
|
||||
|
||||
|
@ -122,15 +120,6 @@ if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
|
|||
.getService(Ci.nsIEventListenerService)
|
||||
.addSystemEventListener(global, "contextmenu", handleContentContextMenu, true);
|
||||
|
||||
} else {
|
||||
addEventListener("mozUITour", function(event) {
|
||||
if (!Services.prefs.getBoolPref("browser.uitour.enabled"))
|
||||
return;
|
||||
|
||||
let handled = UITour.onPageEvent(event);
|
||||
if (handled)
|
||||
addEventListener("pagehide", UITour);
|
||||
}, false, true);
|
||||
}
|
||||
|
||||
let AboutHomeListener = {
|
||||
|
|
|
@ -77,6 +77,7 @@ browser.jar:
|
|||
* content/browser/browser-tabPreviews.xml (content/browser-tabPreviews.xml)
|
||||
* content/browser/chatWindow.xul (content/chatWindow.xul)
|
||||
content/browser/content.js (content/content.js)
|
||||
content/browser/content-UITour.js (content/content-UITour.js)
|
||||
content/browser/defaultthemes/1.footer.jpg (content/defaultthemes/1.footer.jpg)
|
||||
content/browser/defaultthemes/1.header.jpg (content/defaultthemes/1.header.jpg)
|
||||
content/browser/defaultthemes/1.icon.jpg (content/defaultthemes/1.icon.jpg)
|
||||
|
|
|
@ -17,6 +17,9 @@ Cu.import("resource://gre/modules/Services.jsm");
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "AboutHome",
|
||||
"resource:///modules/AboutHome.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "UITour",
|
||||
"resource:///modules/UITour.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
|
||||
"resource://gre/modules/AddonManager.jsm");
|
||||
|
||||
|
@ -2553,3 +2556,12 @@ let E10SUINotification = {
|
|||
|
||||
var components = [BrowserGlue, ContentPermissionPrompt];
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
|
||||
|
||||
|
||||
// Listen for UITour messages.
|
||||
// Do it here instead of the UITour module itself so that the UITour module is lazy loaded
|
||||
// when the first message is received.
|
||||
let globalMM = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager);
|
||||
globalMM.addMessageListener("UITour:onPageEvent", function(aMessage) {
|
||||
UITour.onPageEvent(aMessage, aMessage.data);
|
||||
});
|
||||
|
|
|
@ -25,8 +25,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
|
|||
"resource:///modules/BrowserUITelemetry.jsm");
|
||||
|
||||
|
||||
const UITOUR_PERMISSION = "uitour";
|
||||
const PREF_TEST_WHITELIST = "browser.uitour.testingOrigins";
|
||||
const PREF_SEENPAGEIDS = "browser.uitour.seenPageIDs";
|
||||
const MAX_BUTTONS = 4;
|
||||
|
||||
|
@ -222,18 +220,13 @@ this.UITour = {
|
|||
JSON.stringify([...this.seenPageIDs]));
|
||||
},
|
||||
|
||||
onPageEvent: function(aEvent) {
|
||||
onPageEvent: function(aMessage, aEvent) {
|
||||
let contentDocument = null;
|
||||
if (aEvent.target instanceof Ci.nsIDOMHTMLDocument)
|
||||
contentDocument = aEvent.target;
|
||||
else if (aEvent.target instanceof Ci.nsIDOMHTMLElement)
|
||||
contentDocument = aEvent.target.ownerDocument;
|
||||
else
|
||||
return false;
|
||||
|
||||
// Ignore events if they're not from a trusted origin.
|
||||
if (!this.ensureTrustedOrigin(contentDocument))
|
||||
return false;
|
||||
let browser = aMessage.target;
|
||||
let window = browser.ownerDocument.defaultView;
|
||||
let tab = window.gBrowser.getTabForBrowser(browser);
|
||||
let messageManager = browser.messageManager;
|
||||
|
||||
if (typeof aEvent.detail != "object")
|
||||
return false;
|
||||
|
@ -246,20 +239,22 @@ this.UITour = {
|
|||
if (typeof data != "object")
|
||||
return false;
|
||||
|
||||
let window = this.getChromeWindow(contentDocument);
|
||||
// Do this before bailing if there's no tab, so later we can pick up the pieces:
|
||||
window.gBrowser.tabContainer.addEventListener("TabSelect", this);
|
||||
let tab = window.gBrowser._getTabForContentWindow(contentDocument.defaultView);
|
||||
if (!tab) {
|
||||
// This should only happen while detaching a tab:
|
||||
if (this._detachingTab) {
|
||||
this._queuedEvents.push(aEvent);
|
||||
this._pendingDoc = Cu.getWeakReference(contentDocument);
|
||||
|
||||
if (!window.gMultiProcessBrowser) { // Non-e10s. See bug 1089000.
|
||||
contentDocument = browser.contentWindow.document;
|
||||
if (!tab) {
|
||||
// This should only happen while detaching a tab:
|
||||
if (this._detachingTab) {
|
||||
this._queuedEvents.push(aEvent);
|
||||
this._pendingDoc = Cu.getWeakReference(contentDocument);
|
||||
return;
|
||||
}
|
||||
Cu.reportError("Discarding tabless UITour event (" + action + ") while not detaching a tab." +
|
||||
"This shouldn't happen!");
|
||||
return;
|
||||
}
|
||||
Cu.reportError("Discarding tabless UITour event (" + action + ") while not detaching a tab." +
|
||||
"This shouldn't happen!");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
|
@ -315,7 +310,7 @@ this.UITour = {
|
|||
|
||||
let iconURL = null;
|
||||
if (typeof data.icon == "string")
|
||||
iconURL = this.resolveURL(contentDocument, data.icon);
|
||||
iconURL = this.resolveURL(browser, data.icon);
|
||||
|
||||
let buttons = [];
|
||||
if (Array.isArray(data.buttons) && data.buttons.length > 0) {
|
||||
|
@ -329,7 +324,7 @@ this.UITour = {
|
|||
};
|
||||
|
||||
if (typeof buttonData.icon == "string")
|
||||
button.iconURL = this.resolveURL(contentDocument, buttonData.icon);
|
||||
button.iconURL = this.resolveURL(browser, buttonData.icon);
|
||||
|
||||
if (typeof buttonData.style == "string")
|
||||
button.style = buttonData.style;
|
||||
|
@ -349,7 +344,7 @@ this.UITour = {
|
|||
if (typeof data.targetCallbackID == "string")
|
||||
infoOptions.targetCallbackID = data.targetCallbackID;
|
||||
|
||||
this.showInfo(contentDocument, target, data.title, data.text, iconURL, buttons, infoOptions);
|
||||
this.showInfo(messageManager, target, data.title, data.text, iconURL, buttons, infoOptions);
|
||||
}).then(null, Cu.reportError);
|
||||
break;
|
||||
}
|
||||
|
@ -382,7 +377,7 @@ this.UITour = {
|
|||
case "showMenu": {
|
||||
this.showMenu(window, data.name, () => {
|
||||
if (typeof data.showCallbackID == "string")
|
||||
this.sendPageCallback(contentDocument, data.showCallbackID);
|
||||
this.sendPageCallback(messageManager, data.showCallbackID);
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
@ -428,7 +423,7 @@ this.UITour = {
|
|||
return false;
|
||||
}
|
||||
|
||||
this.getConfiguration(contentDocument, data.configuration, data.callbackID);
|
||||
this.getConfiguration(messageManager, window, data.configuration, data.callbackID);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -450,19 +445,22 @@ this.UITour = {
|
|||
// Add a widget to the toolbar
|
||||
let targetPromise = this.getTarget(window, data.name);
|
||||
targetPromise.then(target => {
|
||||
this.addNavBarWidget(target, contentDocument, data.callbackID);
|
||||
this.addNavBarWidget(target, messageManager, data.callbackID);
|
||||
}).then(null, Cu.reportError);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.originTabs.has(window))
|
||||
this.originTabs.set(window, new Set());
|
||||
if (!window.gMultiProcessBrowser) { // Non-e10s. See bug 1089000.
|
||||
if (!this.originTabs.has(window)) {
|
||||
this.originTabs.set(window, new Set());
|
||||
}
|
||||
|
||||
this.originTabs.get(window).add(tab);
|
||||
tab.addEventListener("TabClose", this);
|
||||
tab.addEventListener("TabBecomingWindow", this);
|
||||
window.addEventListener("SSWindowClosing", this);
|
||||
this.originTabs.get(window).add(tab);
|
||||
tab.addEventListener("TabClose", this);
|
||||
tab.addEventListener("TabBecomingWindow", this);
|
||||
window.addEventListener("SSWindowClosing", this);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
@ -621,44 +619,7 @@ this.UITour = {
|
|||
.wrappedJSObject;
|
||||
},
|
||||
|
||||
isTestingOrigin: function(aURI) {
|
||||
if (Services.prefs.getPrefType(PREF_TEST_WHITELIST) != Services.prefs.PREF_STRING) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add any testing origins (comma-seperated) to the whitelist for the session.
|
||||
for (let origin of Services.prefs.getCharPref(PREF_TEST_WHITELIST).split(",")) {
|
||||
try {
|
||||
let testingURI = Services.io.newURI(origin, null, null);
|
||||
if (aURI.prePath == testingURI.prePath) {
|
||||
return true;
|
||||
}
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
ensureTrustedOrigin: function(aDocument) {
|
||||
if (aDocument.defaultView.top != aDocument.defaultView)
|
||||
return false;
|
||||
|
||||
let uri = aDocument.documentURIObject;
|
||||
|
||||
if (uri.schemeIs("chrome"))
|
||||
return true;
|
||||
|
||||
if (!this.isSafeScheme(uri))
|
||||
return false;
|
||||
|
||||
let permission = Services.perms.testPermission(uri, UITOUR_PERMISSION);
|
||||
if (permission == Services.perms.ALLOW_ACTION)
|
||||
return true;
|
||||
|
||||
return this.isTestingOrigin(uri);
|
||||
},
|
||||
|
||||
// This function is copied to UITourListener.
|
||||
isSafeScheme: function(aURI) {
|
||||
let allowedSchemes = new Set(["https", "about"]);
|
||||
if (!Services.prefs.getBoolPref("browser.uitour.requireSecure"))
|
||||
|
@ -670,9 +631,9 @@ this.UITour = {
|
|||
return true;
|
||||
},
|
||||
|
||||
resolveURL: function(aDocument, aURL) {
|
||||
resolveURL: function(aBrowser, aURL) {
|
||||
try {
|
||||
let uri = Services.io.newURI(aURL, null, aDocument.documentURIObject);
|
||||
let uri = Services.io.newURI(aURL, null, aBrowser.currentURI);
|
||||
|
||||
if (!this.isSafeScheme(uri))
|
||||
return null;
|
||||
|
@ -683,16 +644,9 @@ this.UITour = {
|
|||
return null;
|
||||
},
|
||||
|
||||
sendPageCallback: function(aDocument, aCallbackID, aData = {}) {
|
||||
|
||||
sendPageCallback: function(aMessageManager, aCallbackID, aData = {}) {
|
||||
let detail = {data: aData, callbackID: aCallbackID};
|
||||
detail = Cu.cloneInto(detail, aDocument.defaultView);
|
||||
let event = new aDocument.defaultView.CustomEvent("mozUITourResponse", {
|
||||
bubbles: true,
|
||||
detail: detail
|
||||
});
|
||||
|
||||
aDocument.dispatchEvent(event);
|
||||
aMessageManager.sendAsyncMessage("UITour:SendPageCallback", detail);
|
||||
},
|
||||
|
||||
isElementVisible: function(aElement) {
|
||||
|
@ -966,7 +920,7 @@ this.UITour = {
|
|||
/**
|
||||
* Show an info panel.
|
||||
*
|
||||
* @param {Document} aContentDocument
|
||||
* @param {nsIMessageSender} aMessageManager
|
||||
* @param {Node} aAnchor
|
||||
* @param {String} [aTitle=""]
|
||||
* @param {String} [aDescription=""]
|
||||
|
@ -975,7 +929,7 @@ this.UITour = {
|
|||
* @param {Object} [aOptions={}]
|
||||
* @param {String} [aOptions.closeButtonCallbackID]
|
||||
*/
|
||||
showInfo: function(aContentDocument, aAnchor, aTitle = "", aDescription = "", aIconURL = "",
|
||||
showInfo: function(aMessageManager, aAnchor, aTitle = "", aDescription = "", aIconURL = "",
|
||||
aButtons = [], aOptions = {}) {
|
||||
function showInfoPanel(aAnchorEl) {
|
||||
aAnchorEl.focus();
|
||||
|
@ -1014,7 +968,7 @@ this.UITour = {
|
|||
let callbackID = button.callbackID;
|
||||
el.addEventListener("command", event => {
|
||||
tooltip.hidePopup();
|
||||
this.sendPageCallback(aContentDocument, callbackID);
|
||||
this.sendPageCallback(aMessageManager, callbackID);
|
||||
});
|
||||
|
||||
tooltipButtons.appendChild(el);
|
||||
|
@ -1026,7 +980,7 @@ this.UITour = {
|
|||
let closeButtonCallback = (event) => {
|
||||
this.hideInfo(document.defaultView);
|
||||
if (aOptions && aOptions.closeButtonCallbackID)
|
||||
this.sendPageCallback(aContentDocument, aOptions.closeButtonCallbackID);
|
||||
this.sendPageCallback(aMessageManager, aOptions.closeButtonCallbackID);
|
||||
};
|
||||
tooltipClose.addEventListener("command", closeButtonCallback);
|
||||
|
||||
|
@ -1035,7 +989,7 @@ this.UITour = {
|
|||
target: aAnchor.targetName,
|
||||
type: event.type,
|
||||
};
|
||||
this.sendPageCallback(aContentDocument, aOptions.targetCallbackID, details);
|
||||
this.sendPageCallback(aMessageManager, aOptions.targetCallbackID, details);
|
||||
};
|
||||
if (aOptions.targetCallbackID && aAnchor.addTargetListener) {
|
||||
aAnchor.addTargetListener(document, targetCallback);
|
||||
|
@ -1214,13 +1168,13 @@ this.UITour = {
|
|||
aWindow.gBrowser.selectedTab = tab;
|
||||
},
|
||||
|
||||
getConfiguration: function(aContentDocument, aConfiguration, aCallbackID) {
|
||||
getConfiguration: function(aMessageManager, aWindow, aConfiguration, aCallbackID) {
|
||||
switch (aConfiguration) {
|
||||
case "availableTargets":
|
||||
this.getAvailableTargets(aContentDocument, aCallbackID);
|
||||
this.getAvailableTargets(aMessageManager, aWindow, aCallbackID);
|
||||
break;
|
||||
case "sync":
|
||||
this.sendPageCallback(aContentDocument, aCallbackID, {
|
||||
this.sendPageCallback(aMessageManager, aCallbackID, {
|
||||
setup: Services.prefs.prefHasUserValue("services.sync.username"),
|
||||
});
|
||||
break;
|
||||
|
@ -1228,7 +1182,7 @@ this.UITour = {
|
|||
let props = ["defaultUpdateChannel", "version"];
|
||||
let appinfo = {};
|
||||
props.forEach(property => appinfo[property] = Services.appinfo[property]);
|
||||
this.sendPageCallback(aContentDocument, aCallbackID, appinfo);
|
||||
this.sendPageCallback(aMessageManager, aCallbackID, appinfo);
|
||||
break;
|
||||
default:
|
||||
Cu.reportError("getConfiguration: Unknown configuration requested: " + aConfiguration);
|
||||
|
@ -1236,12 +1190,12 @@ this.UITour = {
|
|||
}
|
||||
},
|
||||
|
||||
getAvailableTargets: function(aContentDocument, aCallbackID) {
|
||||
getAvailableTargets: function(aMessageManager, aChromeWindow, aCallbackID) {
|
||||
Task.spawn(function*() {
|
||||
let window = this.getChromeWindow(aContentDocument);
|
||||
let window = aChromeWindow;
|
||||
let data = this.availableTargetsCache.get(window);
|
||||
if (data) {
|
||||
this.sendPageCallback(aContentDocument, aCallbackID, data);
|
||||
this.sendPageCallback(aMessageManager, aCallbackID, data);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1268,16 +1222,16 @@ this.UITour = {
|
|||
targets: targetNames,
|
||||
};
|
||||
this.availableTargetsCache.set(window, data);
|
||||
this.sendPageCallback(aContentDocument, aCallbackID, data);
|
||||
this.sendPageCallback(aMessageManager, aCallbackID, data);
|
||||
}.bind(this)).catch(err => {
|
||||
Cu.reportError(err);
|
||||
this.sendPageCallback(aContentDocument, aCallbackID, {
|
||||
this.sendPageCallback(aMessageManager, aCallbackID, {
|
||||
targets: [],
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
addNavBarWidget: function (aTarget, aContentDocument, aCallbackID) {
|
||||
addNavBarWidget: function (aTarget, aMessageManager, aCallbackID) {
|
||||
if (aTarget.node) {
|
||||
Cu.reportError("UITour: can't add a widget already present: " + data.target);
|
||||
return;
|
||||
|
@ -1292,7 +1246,7 @@ this.UITour = {
|
|||
}
|
||||
|
||||
CustomizableUI.addWidgetToArea(aTarget.widgetName, CustomizableUI.AREA_NAVBAR);
|
||||
this.sendPageCallback(aContentDocument, aCallbackID);
|
||||
this.sendPageCallback(aMessageManager, aCallbackID);
|
||||
},
|
||||
|
||||
_addAnnotationPanelMutationObserver: function(aPanelEl) {
|
||||
|
|
|
@ -81,12 +81,16 @@ let tests = [
|
|||
function test_highlight_2() {
|
||||
let highlight = document.getElementById("UITourHighlight");
|
||||
gContentAPI.hideHighlight();
|
||||
|
||||
waitForElementToBeHidden(highlight, test_highlight_3, "Highlight should be hidden after hideHighlight()");
|
||||
}
|
||||
function test_highlight_3() {
|
||||
is_element_hidden(highlight, "Highlight should be hidden after hideHighlight()");
|
||||
|
||||
gContentAPI.showHighlight("urlbar");
|
||||
waitForElementToBeVisible(highlight, test_highlight_3, "Highlight should be shown after showHighlight()");
|
||||
waitForElementToBeVisible(highlight, test_highlight_4, "Highlight should be shown after showHighlight()");
|
||||
}
|
||||
function test_highlight_3() {
|
||||
function test_highlight_4() {
|
||||
let highlight = document.getElementById("UITourHighlight");
|
||||
gContentAPI.showHighlight("backForward");
|
||||
waitForElementToBeVisible(highlight, done, "Highlight should be shown after showHighlight()");
|
||||
|
@ -302,33 +306,27 @@ let tests = [
|
|||
|
||||
gContentAPI.showInfo("urlbar", "test title", "test text");
|
||||
},
|
||||
function test_info_2(done) {
|
||||
taskify(function* test_info_2() {
|
||||
let popup = document.getElementById("UITourTooltip");
|
||||
let title = document.getElementById("UITourTooltipTitle");
|
||||
let desc = document.getElementById("UITourTooltipDescription");
|
||||
let icon = document.getElementById("UITourTooltipIcon");
|
||||
let buttons = document.getElementById("UITourTooltipButtons");
|
||||
|
||||
popup.addEventListener("popupshown", function onPopupShown() {
|
||||
popup.removeEventListener("popupshown", onPopupShown);
|
||||
is(popup.popupBoxObject.anchorNode, document.getElementById("urlbar"), "Popup should be anchored to the urlbar");
|
||||
is(title.textContent, "urlbar title", "Popup should have correct title");
|
||||
is(desc.textContent, "urlbar text", "Popup should have correct description text");
|
||||
is(icon.src, "", "Popup should have no icon");
|
||||
is(buttons.hasChildNodes(), false, "Popup should have no buttons");
|
||||
yield showInfoPromise("urlbar", "urlbar title", "urlbar text");
|
||||
|
||||
gContentAPI.showInfo("search", "search title", "search text");
|
||||
executeSoon(function() {
|
||||
is(popup.popupBoxObject.anchorNode, document.getElementById("searchbar"), "Popup should be anchored to the searchbar");
|
||||
is(title.textContent, "search title", "Popup should have correct title");
|
||||
is(desc.textContent, "search text", "Popup should have correct description text");
|
||||
is(popup.popupBoxObject.anchorNode, document.getElementById("urlbar"), "Popup should be anchored to the urlbar");
|
||||
is(title.textContent, "urlbar title", "Popup should have correct title");
|
||||
is(desc.textContent, "urlbar text", "Popup should have correct description text");
|
||||
is(icon.src, "", "Popup should have no icon");
|
||||
is(buttons.hasChildNodes(), false, "Popup should have no buttons");
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
yield showInfoPromise("search", "search title", "search text");
|
||||
|
||||
gContentAPI.showInfo("urlbar", "urlbar title", "urlbar text");
|
||||
},
|
||||
is(popup.popupBoxObject.anchorNode, document.getElementById("searchbar"), "Popup should be anchored to the searchbar");
|
||||
is(title.textContent, "search title", "Popup should have correct title");
|
||||
is(desc.textContent, "search text", "Popup should have correct description text");
|
||||
}),
|
||||
function test_getConfigurationVersion(done) {
|
||||
function callback(result) {
|
||||
let props = ["defaultUpdateChannel", "version"];
|
||||
|
@ -368,8 +366,9 @@ let tests = [
|
|||
},
|
||||
|
||||
// Make sure this test is last in the file so the appMenu gets left open and done will confirm it got tore down.
|
||||
function cleanupMenus(done) {
|
||||
taskify(function* cleanupMenus() {
|
||||
let shownPromise = promisePanelShown(window);
|
||||
gContentAPI.showMenu("appMenu");
|
||||
done();
|
||||
},
|
||||
yield shownPromise;
|
||||
}),
|
||||
];
|
||||
|
|
|
@ -56,19 +56,22 @@ let tests = [
|
|||
waitForPopupAtAnchor(popup, target.node, function checkMenuIsStillOpen() {
|
||||
isnot(PanelUI.panel.state, "closed",
|
||||
"Menu should remain open since UITour didn't open it in the first place");
|
||||
waitForElementToBeHidden(window.PanelUI.panel, () => {
|
||||
ok(!PanelUI.panel.hasAttribute("noautohide"), "@noautohide on the menu panel should have been cleaned up on close");
|
||||
done();
|
||||
});
|
||||
gContentAPI.hideMenu("appMenu");
|
||||
ok(!PanelUI.panel.hasAttribute("noautohide"), "@noautohide on the menu panel should have been cleaned up on close");
|
||||
done();
|
||||
}, "Info should move to the appMenu button");
|
||||
});
|
||||
}, "Info should be shown after showInfo() for fixed menu panel items");
|
||||
});
|
||||
}).then(null, Components.utils.reportError);
|
||||
},
|
||||
function test_pinnedTab(done) {
|
||||
taskify(function* test_pinnedTab() {
|
||||
is(UITour.pinnedTabs.get(window), null, "Should not already have a pinned tab");
|
||||
|
||||
gContentAPI.addPinnedTab();
|
||||
yield addPinnedTabPromise();
|
||||
|
||||
let tabInfo = UITour.pinnedTabs.get(window);
|
||||
isnot(tabInfo, null, "Should have recorded data about a pinned tab after addPinnedTab()");
|
||||
isnot(tabInfo.tab, null, "Should have added a pinned tab after addPinnedTab()");
|
||||
|
@ -76,28 +79,29 @@ let tests = [
|
|||
|
||||
let tab = tabInfo.tab;
|
||||
|
||||
gContentAPI.removePinnedTab();
|
||||
yield removePinnedTabPromise();
|
||||
isnot(gBrowser.tabs[0], tab, "First tab should not be the pinned tab");
|
||||
tabInfo = UITour.pinnedTabs.get(window);
|
||||
is(tabInfo, null, "Should not have any data about the removed pinned tab after removePinnedTab()");
|
||||
|
||||
gContentAPI.addPinnedTab();
|
||||
gContentAPI.addPinnedTab();
|
||||
gContentAPI.addPinnedTab();
|
||||
yield addPinnedTabPromise();
|
||||
yield addPinnedTabPromise();
|
||||
yield addPinnedTabPromise();
|
||||
is(gBrowser.tabs[1].pinned, false, "After multiple calls of addPinnedTab, should still only have one pinned tab");
|
||||
|
||||
done();
|
||||
},
|
||||
function test_menu(done) {
|
||||
}),
|
||||
taskify(function* test_menu() {
|
||||
let bookmarksMenuButton = document.getElementById("bookmarks-menu-button");
|
||||
ise(bookmarksMenuButton.open, false, "Menu should initially be closed");
|
||||
|
||||
ise(bookmarksMenuButton.open, false, "Menu should initially be closed");
|
||||
gContentAPI.showMenu("bookmarks");
|
||||
ise(bookmarksMenuButton.open, true, "Menu should be shown after showMenu()");
|
||||
|
||||
yield waitForConditionPromise(() => {
|
||||
return bookmarksMenuButton.open;
|
||||
}, "Menu should be visible after showMenu()");
|
||||
|
||||
gContentAPI.hideMenu("bookmarks");
|
||||
ise(bookmarksMenuButton.open, false, "Menu should be closed after hideMenu()");
|
||||
|
||||
done();
|
||||
},
|
||||
yield waitForConditionPromise(() => {
|
||||
return !bookmarksMenuButton.open;
|
||||
}, "Menu should be hidden after hideMenu()");
|
||||
}),
|
||||
];
|
||||
|
|
|
@ -16,7 +16,7 @@ function test() {
|
|||
}
|
||||
|
||||
let tests = [
|
||||
function test_info_icon(done) {
|
||||
taskify(function* test_info_icon() {
|
||||
let popup = document.getElementById("UITourTooltip");
|
||||
let title = document.getElementById("UITourTooltipTitle");
|
||||
let desc = document.getElementById("UITourTooltipDescription");
|
||||
|
@ -27,139 +27,122 @@ let tests = [
|
|||
// window during the transition instead of the buttons in the popup.
|
||||
popup.setAttribute("animate", "false");
|
||||
|
||||
popup.addEventListener("popupshown", function onPopupShown() {
|
||||
popup.removeEventListener("popupshown", onPopupShown);
|
||||
yield showInfoPromise("urlbar", "a title", "some text", "image.png");
|
||||
|
||||
is(title.textContent, "a title", "Popup should have correct title");
|
||||
is(desc.textContent, "some text", "Popup should have correct description text");
|
||||
is(title.textContent, "a title", "Popup should have correct title");
|
||||
is(desc.textContent, "some text", "Popup should have correct description text");
|
||||
|
||||
let imageURL = getRootDirectory(gTestPath) + "image.png";
|
||||
imageURL = imageURL.replace("chrome://mochitests/content/", "https://example.com/");
|
||||
is(icon.src, imageURL, "Popup should have correct icon shown");
|
||||
let imageURL = getRootDirectory(gTestPath) + "image.png";
|
||||
imageURL = imageURL.replace("chrome://mochitests/content/", "https://example.com/");
|
||||
is(icon.src, imageURL, "Popup should have correct icon shown");
|
||||
|
||||
is(buttons.hasChildNodes(), false, "Popup should have no buttons");
|
||||
is(buttons.hasChildNodes(), false, "Popup should have no buttons");
|
||||
}),
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
gContentAPI.showInfo("urlbar", "a title", "some text", "image.png");
|
||||
},
|
||||
function test_info_buttons_1(done) {
|
||||
taskify(function* test_info_buttons_1() {
|
||||
let popup = document.getElementById("UITourTooltip");
|
||||
let title = document.getElementById("UITourTooltipTitle");
|
||||
let desc = document.getElementById("UITourTooltipDescription");
|
||||
let icon = document.getElementById("UITourTooltipIcon");
|
||||
|
||||
popup.addEventListener("popupshown", function onPopupShown() {
|
||||
popup.removeEventListener("popupshown", onPopupShown);
|
||||
|
||||
is(title.textContent, "another title", "Popup should have correct title");
|
||||
is(desc.textContent, "moar text", "Popup should have correct description text");
|
||||
|
||||
let imageURL = getRootDirectory(gTestPath) + "image.png";
|
||||
imageURL = imageURL.replace("chrome://mochitests/content/", "https://example.com/");
|
||||
is(icon.src, imageURL, "Popup should have correct icon shown");
|
||||
|
||||
let buttons = document.getElementById("UITourTooltipButtons");
|
||||
is(buttons.childElementCount, 2, "Popup should have two buttons");
|
||||
|
||||
is(buttons.childNodes[0].getAttribute("label"), "Button 1", "First button should have correct label");
|
||||
is(buttons.childNodes[0].getAttribute("image"), "", "First button should have no image");
|
||||
|
||||
is(buttons.childNodes[1].getAttribute("label"), "Button 2", "Second button should have correct label");
|
||||
is(buttons.childNodes[1].getAttribute("image"), imageURL, "Second button should have correct image");
|
||||
|
||||
popup.addEventListener("popuphidden", function onPopupHidden() {
|
||||
popup.removeEventListener("popuphidden", onPopupHidden);
|
||||
ok(true, "Popup should close automatically");
|
||||
|
||||
executeSoon(function() {
|
||||
is(gContentWindow.callbackResult, "button1", "Correct callback should have been called");
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(buttons.childNodes[0], {}, window);
|
||||
});
|
||||
|
||||
let buttons = gContentWindow.makeButtons();
|
||||
gContentAPI.showInfo("urlbar", "another title", "moar text", "./image.png", buttons);
|
||||
},
|
||||
function test_info_buttons_2(done) {
|
||||
|
||||
yield showInfoPromise("urlbar", "another title", "moar text", "./image.png", buttons);
|
||||
|
||||
is(title.textContent, "another title", "Popup should have correct title");
|
||||
is(desc.textContent, "moar text", "Popup should have correct description text");
|
||||
|
||||
let imageURL = getRootDirectory(gTestPath) + "image.png";
|
||||
imageURL = imageURL.replace("chrome://mochitests/content/", "https://example.com/");
|
||||
is(icon.src, imageURL, "Popup should have correct icon shown");
|
||||
|
||||
buttons = document.getElementById("UITourTooltipButtons");
|
||||
is(buttons.childElementCount, 2, "Popup should have two buttons");
|
||||
|
||||
is(buttons.childNodes[0].getAttribute("label"), "Button 1", "First button should have correct label");
|
||||
is(buttons.childNodes[0].getAttribute("image"), "", "First button should have no image");
|
||||
|
||||
is(buttons.childNodes[1].getAttribute("label"), "Button 2", "Second button should have correct label");
|
||||
is(buttons.childNodes[1].getAttribute("image"), imageURL, "Second button should have correct image");
|
||||
|
||||
let promiseHidden = promisePanelElementHidden(window, popup);
|
||||
EventUtils.synthesizeMouseAtCenter(buttons.childNodes[0], {}, window);
|
||||
yield promiseHidden;
|
||||
|
||||
ok(true, "Popup should close automatically");
|
||||
|
||||
yield waitForCallbackResultPromise();
|
||||
|
||||
is(gContentWindow.callbackResult, "button1", "Correct callback should have been called");
|
||||
}),
|
||||
taskify(function* test_info_buttons_2() {
|
||||
let popup = document.getElementById("UITourTooltip");
|
||||
let title = document.getElementById("UITourTooltipTitle");
|
||||
let desc = document.getElementById("UITourTooltipDescription");
|
||||
let icon = document.getElementById("UITourTooltipIcon");
|
||||
|
||||
popup.addEventListener("popupshown", function onPopupShown() {
|
||||
popup.removeEventListener("popupshown", onPopupShown);
|
||||
|
||||
is(title.textContent, "another title", "Popup should have correct title");
|
||||
is(desc.textContent, "moar text", "Popup should have correct description text");
|
||||
|
||||
let imageURL = getRootDirectory(gTestPath) + "image.png";
|
||||
imageURL = imageURL.replace("chrome://mochitests/content/", "https://example.com/");
|
||||
is(icon.src, imageURL, "Popup should have correct icon shown");
|
||||
|
||||
let buttons = document.getElementById("UITourTooltipButtons");
|
||||
is(buttons.childElementCount, 2, "Popup should have two buttons");
|
||||
|
||||
is(buttons.childNodes[0].getAttribute("label"), "Button 1", "First button should have correct label");
|
||||
is(buttons.childNodes[0].getAttribute("image"), "", "First button should have no image");
|
||||
|
||||
is(buttons.childNodes[1].getAttribute("label"), "Button 2", "Second button should have correct label");
|
||||
is(buttons.childNodes[1].getAttribute("image"), imageURL, "Second button should have correct image");
|
||||
|
||||
popup.addEventListener("popuphidden", function onPopupHidden() {
|
||||
popup.removeEventListener("popuphidden", onPopupHidden);
|
||||
ok(true, "Popup should close automatically");
|
||||
|
||||
executeSoon(function() {
|
||||
is(gContentWindow.callbackResult, "button2", "Correct callback should have been called");
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(buttons.childNodes[1], {}, window);
|
||||
});
|
||||
|
||||
let buttons = gContentWindow.makeButtons();
|
||||
gContentAPI.showInfo("urlbar", "another title", "moar text", "./image.png", buttons);
|
||||
},
|
||||
|
||||
function test_info_close_button(done) {
|
||||
yield showInfoPromise("urlbar", "another title", "moar text", "./image.png", buttons);
|
||||
|
||||
is(title.textContent, "another title", "Popup should have correct title");
|
||||
is(desc.textContent, "moar text", "Popup should have correct description text");
|
||||
|
||||
let imageURL = getRootDirectory(gTestPath) + "image.png";
|
||||
imageURL = imageURL.replace("chrome://mochitests/content/", "https://example.com/");
|
||||
is(icon.src, imageURL, "Popup should have correct icon shown");
|
||||
|
||||
buttons = document.getElementById("UITourTooltipButtons");
|
||||
is(buttons.childElementCount, 2, "Popup should have two buttons");
|
||||
|
||||
is(buttons.childNodes[0].getAttribute("label"), "Button 1", "First button should have correct label");
|
||||
is(buttons.childNodes[0].getAttribute("image"), "", "First button should have no image");
|
||||
|
||||
is(buttons.childNodes[1].getAttribute("label"), "Button 2", "Second button should have correct label");
|
||||
is(buttons.childNodes[1].getAttribute("image"), imageURL, "Second button should have correct image");
|
||||
|
||||
let promiseHidden = promisePanelElementHidden(window, popup);
|
||||
EventUtils.synthesizeMouseAtCenter(buttons.childNodes[1], {}, window);
|
||||
yield promiseHidden;
|
||||
|
||||
ok(true, "Popup should close automatically");
|
||||
|
||||
yield waitForCallbackResultPromise();
|
||||
|
||||
is(gContentWindow.callbackResult, "button2", "Correct callback should have been called");
|
||||
}),
|
||||
|
||||
taskify(function* test_info_close_button() {
|
||||
let popup = document.getElementById("UITourTooltip");
|
||||
let closeButton = document.getElementById("UITourTooltipClose");
|
||||
|
||||
popup.addEventListener("popupshown", function onPopupShown() {
|
||||
popup.removeEventListener("popupshown", onPopupShown);
|
||||
EventUtils.synthesizeMouseAtCenter(closeButton, {}, window);
|
||||
executeSoon(function() {
|
||||
is(gContentWindow.callbackResult, "closeButton", "Close button callback called");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
let infoOptions = gContentWindow.makeInfoOptions();
|
||||
gContentAPI.showInfo("urlbar", "Close me", "X marks the spot", null, null, infoOptions);
|
||||
},
|
||||
|
||||
function test_info_target_callback(done) {
|
||||
yield showInfoPromise("urlbar", "Close me", "X marks the spot", null, null, infoOptions);
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(closeButton, {}, window);
|
||||
|
||||
yield waitForCallbackResultPromise();
|
||||
|
||||
is(gContentWindow.callbackResult, "closeButton", "Close button callback called");
|
||||
}),
|
||||
|
||||
taskify(function* test_info_target_callback() {
|
||||
let popup = document.getElementById("UITourTooltip");
|
||||
popup.addEventListener("popupshown", function onPopupShown() {
|
||||
popup.removeEventListener("popupshown", onPopupShown);
|
||||
PanelUI.show().then(() => {
|
||||
is(gContentWindow.callbackResult, "target", "target callback called");
|
||||
is(gContentWindow.callbackData.target, "appMenu", "target callback was from the appMenu");
|
||||
is(gContentWindow.callbackData.type, "popupshown", "target callback was from the mousedown");
|
||||
popup.removeAttribute("animate");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
let infoOptions = gContentWindow.makeInfoOptions();
|
||||
gContentAPI.showInfo("appMenu", "I want to know when the target is clicked", "*click*", null, null, infoOptions);
|
||||
},
|
||||
|
||||
yield showInfoPromise("appMenu", "I want to know when the target is clicked", "*click*", null, null, infoOptions);
|
||||
|
||||
yield PanelUI.show();
|
||||
|
||||
yield waitForCallbackResultPromise();
|
||||
|
||||
is(gContentWindow.callbackResult, "target", "target callback called");
|
||||
is(gContentWindow.callbackData.target, "appMenu", "target callback was from the appMenu");
|
||||
is(gContentWindow.callbackData.type, "popupshown", "target callback was from the mousedown");
|
||||
|
||||
// Cleanup.
|
||||
yield hideInfoPromise();
|
||||
|
||||
popup.removeAttribute("animate");
|
||||
}),
|
||||
];
|
||||
|
|
|
@ -11,8 +11,6 @@ let gTestTab;
|
|||
let gContentAPI;
|
||||
let gContentWindow;
|
||||
let gContentDoc;
|
||||
let highlight = document.getElementById("UITourHighlight");
|
||||
let tooltip = document.getElementById("UITourTooltip");
|
||||
|
||||
Components.utils.import("resource:///modules/UITour.jsm");
|
||||
|
||||
|
@ -23,61 +21,69 @@ function test() {
|
|||
UITourTest();
|
||||
}
|
||||
|
||||
/**
|
||||
* When tab is changed we're tearing the tour down. So the UITour client has to always be aware of this
|
||||
* fact and therefore listens to visibilitychange events.
|
||||
* In particular this scenario happens for detaching the tab (ie. moving it to a new window).
|
||||
*/
|
||||
let tests = [
|
||||
function test_move_tab_to_new_window(done) {
|
||||
let gOpenedWindow;
|
||||
taskify(function* test_move_tab_to_new_window(done) {
|
||||
let onVisibilityChange = (aEvent) => {
|
||||
if (!document.hidden && window != UITour.getChromeWindow(aEvent.target)) {
|
||||
gContentAPI.showHighlight("appMenu");
|
||||
}
|
||||
};
|
||||
let onDOMWindowDestroyed = (aWindow, aTopic, aData) => {
|
||||
if (gOpenedWindow && aWindow == gOpenedWindow) {
|
||||
|
||||
let highlight = document.getElementById("UITourHighlight");
|
||||
let windowDestroyedDeferred = Promise.defer();
|
||||
let onDOMWindowDestroyed = (aWindow) => {
|
||||
if (gContentWindow && aWindow == gContentWindow) {
|
||||
Services.obs.removeObserver(onDOMWindowDestroyed, "dom-window-destroyed", false);
|
||||
done();
|
||||
}
|
||||
};
|
||||
let onBrowserDelayedStartup = (aWindow, aTopic, aData) => {
|
||||
gOpenedWindow = aWindow;
|
||||
Services.obs.removeObserver(onBrowserDelayedStartup, "browser-delayed-startup-finished");
|
||||
try {
|
||||
let newWindowHighlight = gOpenedWindow.document.getElementById("UITourHighlight");
|
||||
let selectedTab = aWindow.gBrowser.selectedTab;
|
||||
is(selectedTab.linkedBrowser && selectedTab.linkedBrowser.contentDocument, gContentDoc, "Document should be selected in new window");
|
||||
ok(UITour.originTabs && UITour.originTabs.has(aWindow), "Window should be known");
|
||||
ok(UITour.originTabs.get(aWindow).has(selectedTab), "Tab should be known");
|
||||
waitForElementToBeVisible(newWindowHighlight, function checkHighlightIsThere() {
|
||||
let shownPromise = promisePanelShown(aWindow);
|
||||
gContentAPI.showMenu("appMenu");
|
||||
shownPromise.then(() => {
|
||||
isnot(aWindow.PanelUI.panel.state, "closed", "Panel should be open");
|
||||
ok(aWindow.PanelUI.contents.children.length > 0, "Panel contents should have children");
|
||||
gContentAPI.hideHighlight();
|
||||
gContentAPI.hideMenu("appMenu");
|
||||
gTestTab = null;
|
||||
aWindow.close();
|
||||
}).then(null, Components.utils.reportError);
|
||||
}, "Highlight should be shown in new window.");
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
ok(false, "An error occurred running UITour tab detach test.");
|
||||
} finally {
|
||||
gContentDoc.removeEventListener("visibilitychange", onVisibilityChange, false);
|
||||
Services.obs.addObserver(onDOMWindowDestroyed, "dom-window-destroyed", false);
|
||||
windowDestroyedDeferred.resolve();
|
||||
}
|
||||
};
|
||||
|
||||
Services.obs.addObserver(onBrowserDelayedStartup, "browser-delayed-startup-finished", false);
|
||||
let browserStartupDeferred = Promise.defer();
|
||||
Services.obs.addObserver(function onBrowserDelayedStartup(aWindow) {
|
||||
Services.obs.removeObserver(onBrowserDelayedStartup, "browser-delayed-startup-finished");
|
||||
browserStartupDeferred.resolve(aWindow);
|
||||
}, "browser-delayed-startup-finished", false);
|
||||
|
||||
// NB: we're using this rather than gContentWindow.document because the latter wouldn't
|
||||
// have an XRayWrapper, and we need to compare this to the doc we get using this method
|
||||
// later on...
|
||||
gContentDoc = gBrowser.selectedTab.linkedBrowser.contentDocument;
|
||||
gContentDoc.addEventListener("visibilitychange", onVisibilityChange, false);
|
||||
gContentAPI.showHighlight("appMenu");
|
||||
waitForElementToBeVisible(highlight, function checkForInitialHighlight() {
|
||||
gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
|
||||
});
|
||||
|
||||
},
|
||||
yield elementVisiblePromise(highlight);
|
||||
|
||||
gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
|
||||
|
||||
gContentWindow = yield browserStartupDeferred.promise;
|
||||
|
||||
// This highlight should be shown thanks to the visibilitychange listener.
|
||||
let newWindowHighlight = gContentWindow.document.getElementById("UITourHighlight");
|
||||
yield elementVisiblePromise(newWindowHighlight);
|
||||
|
||||
let selectedTab = gContentWindow.gBrowser.selectedTab;
|
||||
is(selectedTab.linkedBrowser && selectedTab.linkedBrowser.contentDocument, gContentDoc, "Document should be selected in new window");
|
||||
ok(UITour.originTabs && UITour.originTabs.has(gContentWindow), "Window should be known");
|
||||
ok(UITour.originTabs.get(gContentWindow).has(selectedTab), "Tab should be known");
|
||||
|
||||
let shownPromise = promisePanelShown(gContentWindow);
|
||||
gContentAPI.showMenu("appMenu");
|
||||
yield shownPromise;
|
||||
|
||||
isnot(gContentWindow.PanelUI.panel.state, "closed", "Panel should be open");
|
||||
ok(gContentWindow.PanelUI.contents.children.length > 0, "Panel contents should have children");
|
||||
gContentAPI.hideHighlight();
|
||||
gContentAPI.hideMenu("appMenu");
|
||||
gTestTab = null;
|
||||
|
||||
Services.obs.addObserver(onDOMWindowDestroyed, "dom-window-destroyed", false);
|
||||
gContentWindow.close();
|
||||
|
||||
yield windowDestroyedDeferred.promise;
|
||||
}),
|
||||
];
|
||||
|
||||
|
|
|
@ -66,9 +66,11 @@ let tests = [
|
|||
|
||||
done();
|
||||
},
|
||||
function test_seenPageIDs_set_1(done) {
|
||||
taskify(function* test_seenPageIDs_set_1() {
|
||||
gContentAPI.registerPageID("testpage1");
|
||||
|
||||
yield waitForConditionPromise(() => UITour.seenPageIDs.size == 3, "Waiting for page to be registered.");
|
||||
|
||||
checkExpectedSeenPageIDs(["savedID1", "savedID2", "testpage1"]);
|
||||
|
||||
const PREFIX = BrowserUITelemetry.BUCKET_PREFIX;
|
||||
|
@ -85,11 +87,12 @@ let tests = [
|
|||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
gBrowser.selectedTab = gTestTab;
|
||||
BrowserUITelemetry.setBucket(null);
|
||||
done();
|
||||
},
|
||||
function test_seenPageIDs_set_2(done) {
|
||||
}),
|
||||
taskify(function* test_seenPageIDs_set_2() {
|
||||
gContentAPI.registerPageID("testpage2");
|
||||
|
||||
yield waitForConditionPromise(() => UITour.seenPageIDs.size == 4, "Waiting for page to be registered.");
|
||||
|
||||
checkExpectedSeenPageIDs(["savedID1", "savedID2", "testpage1", "testpage2"]);
|
||||
|
||||
const PREFIX = BrowserUITelemetry.BUCKET_PREFIX;
|
||||
|
@ -105,6 +108,5 @@ let tests = [
|
|||
"After closing tab, bucket should be expiring");
|
||||
|
||||
BrowserUITelemetry.setBucket(null);
|
||||
done();
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
|
|
@ -2,27 +2,51 @@
|
|||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource:///modules/UITour.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
function waitForCondition(condition, nextTest, errorMsg) {
|
||||
var tries = 0;
|
||||
var interval = setInterval(function() {
|
||||
if (tries >= 30) {
|
||||
ok(false, errorMsg);
|
||||
moveOn();
|
||||
const SINGLE_TRY_TIMEOUT = 100;
|
||||
const NUMBER_OF_TRIES = 30;
|
||||
|
||||
function waitForConditionPromise(condition, timeoutMsg) {
|
||||
let defer = Promise.defer();
|
||||
let tries = 0;
|
||||
function checkCondition() {
|
||||
if (tries >= NUMBER_OF_TRIES) {
|
||||
defer.reject(timeoutMsg);
|
||||
}
|
||||
var conditionPassed;
|
||||
try {
|
||||
conditionPassed = condition();
|
||||
} catch (e) {
|
||||
ok(false, e + "\n" + e.stack);
|
||||
conditionPassed = false;
|
||||
return defer.reject(e);
|
||||
}
|
||||
if (conditionPassed) {
|
||||
moveOn();
|
||||
return defer.resolve();
|
||||
}
|
||||
tries++;
|
||||
}, 100);
|
||||
var moveOn = function() { clearInterval(interval); nextTest(); };
|
||||
setTimeout(checkCondition, SINGLE_TRY_TIMEOUT);
|
||||
}
|
||||
setTimeout(checkCondition, SINGLE_TRY_TIMEOUT);
|
||||
return defer.promise;
|
||||
}
|
||||
|
||||
function waitForCondition(condition, nextTest, errorMsg) {
|
||||
waitForConditionPromise(condition, errorMsg).then(nextTest, (reason) => {
|
||||
ok(false, reason + (reason.stack ? "\n" + e.stack : ""));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper to partially transition tests to Task.
|
||||
*/
|
||||
function taskify(fun) {
|
||||
return (done) => {
|
||||
return Task.spawn(fun).then(done, (reason) => {
|
||||
ok(false, reason);
|
||||
done();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function is_hidden(element) {
|
||||
|
@ -80,6 +104,14 @@ function waitForElementToBeHidden(element, nextTest, msg) {
|
|||
"Timeout waiting for invisibility: " + msg);
|
||||
}
|
||||
|
||||
function elementVisiblePromise(element, msg) {
|
||||
return waitForConditionPromise(() => is_visible(element), "Timeout waiting for visibility: " + msg);
|
||||
}
|
||||
|
||||
function elementHiddenPromise(element, msg) {
|
||||
return waitForConditionPromise(() => is_hidden(element), "Timeout waiting for invisibility: " + msg);
|
||||
}
|
||||
|
||||
function waitForPopupAtAnchor(popup, anchorNode, nextTest, msg) {
|
||||
waitForCondition(() => is_visible(popup) && popup.popupBoxObject.anchorNode == anchorNode,
|
||||
() => {
|
||||
|
@ -90,24 +122,69 @@ function waitForPopupAtAnchor(popup, anchorNode, nextTest, msg) {
|
|||
"Timeout waiting for popup at anchor: " + msg);
|
||||
}
|
||||
|
||||
function hideInfoPromise(...args) {
|
||||
let popup = document.getElementById("UITourTooltip");
|
||||
gContentAPI.hideInfo.apply(gContentAPI, args);
|
||||
return promisePanelElementHidden(window, popup);
|
||||
}
|
||||
|
||||
function showInfoPromise(...args) {
|
||||
let popup = document.getElementById("UITourTooltip");
|
||||
gContentAPI.showInfo.apply(gContentAPI, args);
|
||||
return promisePanelElementShown(window, popup);
|
||||
}
|
||||
|
||||
function waitForCallbackResultPromise() {
|
||||
return waitForConditionPromise(() => {
|
||||
return gContentWindow.callbackResult;
|
||||
}, "callback should be called");
|
||||
}
|
||||
|
||||
function addPinnedTabPromise() {
|
||||
gContentAPI.addPinnedTab();
|
||||
return waitForConditionPromise(() => {
|
||||
let tabInfo = UITour.pinnedTabs.get(window);
|
||||
if (!tabInfo) {
|
||||
return false;
|
||||
}
|
||||
return tabInfo.tab.pinned;
|
||||
});
|
||||
}
|
||||
|
||||
function removePinnedTabPromise() {
|
||||
gContentAPI.removePinnedTab();
|
||||
return waitForConditionPromise(() => {
|
||||
let tabInfo = UITour.pinnedTabs.get(window);
|
||||
return tabInfo == null;
|
||||
});
|
||||
}
|
||||
|
||||
function promisePanelShown(win) {
|
||||
let panelEl = win.PanelUI.panel;
|
||||
return promisePanelElementShown(win, panelEl);
|
||||
}
|
||||
|
||||
function promisePanelElementShown(win, aPanel) {
|
||||
function promisePanelElementEvent(win, aPanel, aEvent) {
|
||||
let deferred = Promise.defer();
|
||||
let timeoutId = win.setTimeout(() => {
|
||||
deferred.reject("Panel did not show within 5 seconds.");
|
||||
}, 5000);
|
||||
aPanel.addEventListener("popupshown", function onPanelOpen(e) {
|
||||
aPanel.removeEventListener("popupshown", onPanelOpen);
|
||||
aPanel.addEventListener(aEvent, function onPanelEvent(e) {
|
||||
aPanel.removeEventListener(aEvent, onPanelEvent);
|
||||
win.clearTimeout(timeoutId);
|
||||
deferred.resolve();
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function promisePanelElementShown(win, aPanel) {
|
||||
return promisePanelElementEvent(win, aPanel, "popupshown");
|
||||
}
|
||||
|
||||
function promisePanelElementHidden(win, aPanel) {
|
||||
return promisePanelElementEvent(win, aPanel, "popuphidden");
|
||||
}
|
||||
|
||||
function is_element_hidden(element, msg) {
|
||||
isnot(element, null, "Element should not be null, when checking visibility");
|
||||
ok(is_hidden(element), msg);
|
||||
|
|
Загрузка…
Ссылка в новой задаче