mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
merge m-c to fx-team; a=merge
This commit is contained in:
commit
1106fb6fb5
@ -346,9 +346,9 @@ function setupSearchEngine()
|
||||
/**
|
||||
* Inform the test harness that we're done loading the page.
|
||||
*/
|
||||
function loadSucceeded()
|
||||
function loadCompleted()
|
||||
{
|
||||
var event = new CustomEvent("AboutHomeLoadSnippetsSucceeded", {bubbles:true});
|
||||
var event = new CustomEvent("AboutHomeLoadSnippetsCompleted", {bubbles:true});
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
|
||||
@ -381,32 +381,29 @@ function loadSnippets()
|
||||
if (updateURL && shouldUpdate) {
|
||||
// Try to update from network.
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.timeout = 5000;
|
||||
try {
|
||||
xhr.open("GET", updateURL, true);
|
||||
} catch (ex) {
|
||||
showSnippets();
|
||||
loadSucceeded();
|
||||
loadCompleted();
|
||||
return;
|
||||
}
|
||||
// Even if fetching should fail we don't want to spam the server, thus
|
||||
// set the last update time regardless its results. Will retry tomorrow.
|
||||
gSnippetsMap.set("snippets-last-update", Date.now());
|
||||
xhr.onerror = function (event) {
|
||||
showSnippets();
|
||||
};
|
||||
xhr.onload = function (event)
|
||||
{
|
||||
xhr.onloadend = function (event) {
|
||||
if (xhr.status == 200) {
|
||||
gSnippetsMap.set("snippets", xhr.responseText);
|
||||
gSnippetsMap.set("snippets-cached-version", currentVersion);
|
||||
}
|
||||
showSnippets();
|
||||
loadSucceeded();
|
||||
loadCompleted();
|
||||
};
|
||||
xhr.send(null);
|
||||
} else {
|
||||
showSnippets();
|
||||
loadSucceeded();
|
||||
loadCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5184,18 +5184,22 @@ function middleMousePaste(event) {
|
||||
function stripUnsafeProtocolOnPaste(pasteData) {
|
||||
// Don't allow pasting in full URIs which inherit the security context.
|
||||
const URI_INHERITS_SECURITY_CONTEXT = Ci.nsIProtocolHandler.URI_INHERITS_SECURITY_CONTEXT;
|
||||
|
||||
let pastedURI;
|
||||
pasteData = pasteData.trim();
|
||||
do {
|
||||
if (pastedURI) {
|
||||
pasteData = pastedURI.path.trim();
|
||||
}
|
||||
try {
|
||||
pastedURI = makeURI(pasteData.trim());
|
||||
} catch (ex) {
|
||||
return pasteData;
|
||||
}
|
||||
|
||||
while (Services.netutil.URIChainHasFlags(pastedURI, URI_INHERITS_SECURITY_CONTEXT)) {
|
||||
pasteData = pastedURI.path.trim();
|
||||
try {
|
||||
pastedURI = makeURI(pasteData);
|
||||
} catch (ex) {
|
||||
break;
|
||||
}
|
||||
} while (Services.netutil.URIChainHasFlags(pastedURI, URI_INHERITS_SECURITY_CONTEXT));
|
||||
}
|
||||
|
||||
return pasteData;
|
||||
}
|
||||
|
@ -334,8 +334,6 @@ skip-if = e10s # Bug ?????? - test directly manipulates content
|
||||
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
|
||||
[browser_plainTextLinks.js]
|
||||
skip-if = e10s # Bug ?????? - test directly manipulates content (creates and fetches elements directly from content document)
|
||||
[browser_popupNotification.js]
|
||||
skip-if = toolkit == "windows" || e10s # Disabled on Windows due to frequent failures (bugs 825739, 841341) / e10s - Bug ?????? - popup notification test probably confused re content process notifications etc
|
||||
[browser_popupUI.js]
|
||||
skip-if = e10s # Bug ?????? - test directly manipulates content (tries to get a popup element directly from content)
|
||||
[browser_printpreview.js]
|
||||
|
@ -397,7 +397,7 @@ function test()
|
||||
let snippetsPromise = promiseSetupSnippetsMap(tab, test.setup);
|
||||
|
||||
// Start loading about:home and wait for it to complete.
|
||||
yield promiseTabLoadEvent(tab, "about:home", "AboutHomeLoadSnippetsSucceeded");
|
||||
yield promiseTabLoadEvent(tab, "about:home", "AboutHomeLoadSnippetsCompleted");
|
||||
|
||||
// This promise should already be resolved since the page is done,
|
||||
// but we still want to get the snippets map out of it.
|
||||
@ -414,35 +414,6 @@ function test()
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a load in an existing tab and waits for it to finish (via some event).
|
||||
*
|
||||
* @param aTab
|
||||
* The tab to load into.
|
||||
* @param aUrl
|
||||
* The url to load.
|
||||
* @param aEvent
|
||||
* The load event type to wait for. Defaults to "load".
|
||||
* @return {Promise} resolved when the event is handled.
|
||||
*/
|
||||
function promiseTabLoadEvent(aTab, aURL, aEventType="load")
|
||||
{
|
||||
let deferred = Promise.defer();
|
||||
info("Wait tab event: " + aEventType);
|
||||
aTab.linkedBrowser.addEventListener(aEventType, function load(event) {
|
||||
if (event.originalTarget != aTab.linkedBrowser.contentDocument ||
|
||||
event.target.location.href == "about:blank") {
|
||||
info("skipping spurious load event");
|
||||
return;
|
||||
}
|
||||
aTab.linkedBrowser.removeEventListener(aEventType, load, true);
|
||||
info("Tab event received: " + aEventType);
|
||||
deferred.resolve();
|
||||
}, true, true);
|
||||
aTab.linkedBrowser.loadURI(aURL);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up snippets and ensures that by default we don't try to check for
|
||||
* remote snippets since that may cause network bustage or slowness.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -219,11 +219,7 @@ function whenNewTabLoaded(aWindow, aCallback) {
|
||||
}
|
||||
|
||||
function whenTabLoaded(aTab, aCallback) {
|
||||
let browser = aTab.linkedBrowser;
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
executeSoon(aCallback);
|
||||
}, true);
|
||||
promiseTabLoadEvent(aTab).then(aCallback);
|
||||
}
|
||||
|
||||
function promiseTabLoaded(aTab) {
|
||||
@ -311,6 +307,7 @@ function promiseHistoryClearedState(aURIs, aShouldBeCleared) {
|
||||
function promiseTopicObserved(topic)
|
||||
{
|
||||
let deferred = Promise.defer();
|
||||
info("Waiting for observer topic " + topic);
|
||||
Services.obs.addObserver(function PTO_observe(subject, topic, data) {
|
||||
Services.obs.removeObserver(PTO_observe, topic);
|
||||
deferred.resolve([subject, data]);
|
||||
@ -397,8 +394,7 @@ let FullZoomHelper = {
|
||||
let didLoad = false;
|
||||
let didZoom = false;
|
||||
|
||||
tab.linkedBrowser.addEventListener("load", function (event) {
|
||||
event.currentTarget.removeEventListener("load", arguments.callee, true);
|
||||
promiseTabLoadEvent(tab).then(event => {
|
||||
didLoad = true;
|
||||
if (didZoom)
|
||||
deferred.resolve();
|
||||
@ -472,3 +468,46 @@ let FullZoomHelper = {
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Waits for a load (or custom) event to finish in a given tab. If provided
|
||||
* load an uri into the tab.
|
||||
*
|
||||
* @param tab
|
||||
* The tab to load into.
|
||||
* @param [optional] url
|
||||
* The url to load, or the current url.
|
||||
* @param [optional] event
|
||||
* The load event type to wait for. Defaults to "load".
|
||||
* @return {Promise} resolved when the event is handled.
|
||||
* @resolves to the received event
|
||||
* @rejects if a valid load event is not received within a meaningful interval
|
||||
*/
|
||||
function promiseTabLoadEvent(tab, url, eventType="load")
|
||||
{
|
||||
let deferred = Promise.defer();
|
||||
info("Wait tab event: " + eventType);
|
||||
|
||||
function handle(event) {
|
||||
if (event.originalTarget != tab.linkedBrowser.contentDocument ||
|
||||
event.target.location.href == "about:blank" ||
|
||||
(url && event.target.location.href != url)) {
|
||||
info("Skipping spurious '" + eventType + "'' event" +
|
||||
" for " + event.target.location.href);
|
||||
return;
|
||||
}
|
||||
clearTimeout(timeout);
|
||||
tab.linkedBrowser.removeEventListener(eventType, handle, true);
|
||||
info("Tab event received: " + eventType);
|
||||
deferred.resolve(event);
|
||||
}
|
||||
|
||||
let timeout = setTimeout(() => {
|
||||
tab.linkedBrowser.removeEventListener(eventType, handle, true);
|
||||
deferred.reject(new Error("Timed out while waiting for a '" + eventType + "'' event"));
|
||||
}, 30000);
|
||||
|
||||
tab.linkedBrowser.addEventListener(eventType, handle, true, true);
|
||||
if (url)
|
||||
tab.linkedBrowser.loadURI(url);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
12
browser/base/content/test/popupNotifications/browser.ini
Normal file
12
browser/base/content/test/popupNotifications/browser.ini
Normal file
@ -0,0 +1,12 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
head.js
|
||||
|
||||
[browser_popupNotification.js]
|
||||
skip-if = (os == "linux" && debug) || e10s # e10s - Bug ?????? - popup notification test probably confused re content process notifications etc
|
||||
[browser_popupNotification_2.js]
|
||||
skip-if = (os == "linux" && debug) || e10s # e10s - Bug ?????? - popup notification test probably confused re content process notifications etc
|
||||
[browser_popupNotification_3.js]
|
||||
skip-if = (os == "linux" && debug) || e10s # e10s - Bug ?????? - popup notification test probably confused re content process notifications etc
|
||||
[browser_popupNotification_4.js]
|
||||
skip-if = (os == "linux" && debug) || e10s # e10s - Bug ?????? - popup notification test probably confused re content process notifications etc
|
@ -0,0 +1,203 @@
|
||||
/* 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/. */
|
||||
|
||||
// These are shared between test #4 to #5
|
||||
let wrongBrowserNotificationObject = new BasicNotification("wrongBrowser");
|
||||
let wrongBrowserNotification;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
ok(PopupNotifications, "PopupNotifications object exists");
|
||||
ok(PopupNotifications.panel, "PopupNotifications panel exists");
|
||||
|
||||
setup();
|
||||
goNext();
|
||||
}
|
||||
|
||||
let tests = [
|
||||
{ id: "Test#1",
|
||||
run: function () {
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
showNotification(this.notifyObj);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
checkPopup(popup, this.notifyObj);
|
||||
triggerMainCommand(popup);
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
ok(this.notifyObj.mainActionClicked, "mainAction was clicked");
|
||||
ok(!this.notifyObj.dismissalCallbackTriggered, "dismissal callback wasn't triggered");
|
||||
ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
|
||||
}
|
||||
},
|
||||
{ id: "Test#2",
|
||||
run: function () {
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
showNotification(this.notifyObj);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
checkPopup(popup, this.notifyObj);
|
||||
triggerSecondaryCommand(popup, 0);
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
ok(this.notifyObj.secondaryActionClicked, "secondaryAction was clicked");
|
||||
ok(!this.notifyObj.dismissalCallbackTriggered, "dismissal callback wasn't triggered");
|
||||
ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
|
||||
}
|
||||
},
|
||||
{ id: "Test#3",
|
||||
run: function () {
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
this.notification = showNotification(this.notifyObj);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
checkPopup(popup, this.notifyObj);
|
||||
dismissNotification(popup);
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered");
|
||||
this.notification.remove();
|
||||
ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
|
||||
}
|
||||
},
|
||||
// test opening a notification for a background browser
|
||||
// Note: test 4 to 6 share a tab.
|
||||
{ id: "Test#4",
|
||||
run: function* () {
|
||||
let tab = gBrowser.addTab("about:blank");
|
||||
isnot(gBrowser.selectedTab, tab, "new tab isn't selected");
|
||||
wrongBrowserNotificationObject.browser = gBrowser.getBrowserForTab(tab);
|
||||
let promiseTopic = promiseTopicObserved("PopupNotifications-backgroundShow");
|
||||
wrongBrowserNotification = showNotification(wrongBrowserNotificationObject);
|
||||
yield promiseTopic;
|
||||
is(PopupNotifications.isPanelOpen, false, "panel isn't open");
|
||||
ok(!wrongBrowserNotificationObject.mainActionClicked, "main action wasn't clicked");
|
||||
ok(!wrongBrowserNotificationObject.secondaryActionClicked, "secondary action wasn't clicked");
|
||||
ok(!wrongBrowserNotificationObject.dismissalCallbackTriggered, "dismissal callback wasn't called");
|
||||
goNext();
|
||||
}
|
||||
},
|
||||
// now select that browser and test to see that the notification appeared
|
||||
{ id: "Test#5",
|
||||
run: function () {
|
||||
this.oldSelectedTab = gBrowser.selectedTab;
|
||||
gBrowser.selectedTab = gBrowser.tabs[gBrowser.tabs.length - 1];
|
||||
},
|
||||
onShown: function (popup) {
|
||||
checkPopup(popup, wrongBrowserNotificationObject);
|
||||
is(PopupNotifications.isPanelOpen, true, "isPanelOpen getter doesn't lie");
|
||||
|
||||
// switch back to the old browser
|
||||
gBrowser.selectedTab = this.oldSelectedTab;
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
// actually remove the notification to prevent it from reappearing
|
||||
ok(wrongBrowserNotificationObject.dismissalCallbackTriggered, "dismissal callback triggered due to tab switch");
|
||||
wrongBrowserNotification.remove();
|
||||
ok(wrongBrowserNotificationObject.removedCallbackTriggered, "removed callback triggered");
|
||||
wrongBrowserNotification = null;
|
||||
}
|
||||
},
|
||||
// test that the removed notification isn't shown on browser re-select
|
||||
{ id: "Test#6",
|
||||
run: function* () {
|
||||
let promiseTopic = promiseTopicObserved("PopupNotifications-updateNotShowing");
|
||||
gBrowser.selectedTab = gBrowser.tabs[gBrowser.tabs.length - 1];
|
||||
yield promiseTopic;
|
||||
is(PopupNotifications.isPanelOpen, false, "panel isn't open");
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
goNext();
|
||||
}
|
||||
},
|
||||
// Test that two notifications with the same ID result in a single displayed
|
||||
// notification.
|
||||
{ id: "Test#7",
|
||||
run: function () {
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
// Show the same notification twice
|
||||
this.notification1 = showNotification(this.notifyObj);
|
||||
this.notification2 = showNotification(this.notifyObj);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
checkPopup(popup, this.notifyObj);
|
||||
this.notification2.remove();
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
ok(!this.notifyObj.dismissalCallbackTriggered, "dismissal callback wasn't triggered");
|
||||
ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
|
||||
}
|
||||
},
|
||||
// Test that two notifications with different IDs are displayed
|
||||
{ id: "Test#8",
|
||||
run: function () {
|
||||
this.testNotif1 = new BasicNotification(this.id);
|
||||
this.testNotif1.message += " 1";
|
||||
showNotification(this.testNotif1);
|
||||
this.testNotif2 = new BasicNotification(this.id);
|
||||
this.testNotif2.message += " 2";
|
||||
this.testNotif2.id += "-2";
|
||||
showNotification(this.testNotif2);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
is(popup.childNodes.length, 2, "two notifications are shown");
|
||||
// Trigger the main command for the first notification, and the secondary
|
||||
// for the second. Need to do mainCommand first since the secondaryCommand
|
||||
// triggering is async.
|
||||
triggerMainCommand(popup);
|
||||
is(popup.childNodes.length, 1, "only one notification left");
|
||||
triggerSecondaryCommand(popup, 0);
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
ok(this.testNotif1.mainActionClicked, "main action #1 was clicked");
|
||||
ok(!this.testNotif1.secondaryActionClicked, "secondary action #1 wasn't clicked");
|
||||
ok(!this.testNotif1.dismissalCallbackTriggered, "dismissal callback #1 wasn't called");
|
||||
|
||||
ok(!this.testNotif2.mainActionClicked, "main action #2 wasn't clicked");
|
||||
ok(this.testNotif2.secondaryActionClicked, "secondary action #2 was clicked");
|
||||
ok(!this.testNotif2.dismissalCallbackTriggered, "dismissal callback #2 wasn't called");
|
||||
}
|
||||
},
|
||||
// Test notification without mainAction
|
||||
{ id: "Test#9",
|
||||
run: function () {
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
this.notifyObj.mainAction = null;
|
||||
this.notification = showNotification(this.notifyObj);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
checkPopup(popup, this.notifyObj);
|
||||
dismissNotification(popup);
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
this.notification.remove();
|
||||
}
|
||||
},
|
||||
// Test two notifications with different anchors
|
||||
{ id: "Test#10",
|
||||
run: function () {
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
this.firstNotification = showNotification(this.notifyObj);
|
||||
this.notifyObj2 = new BasicNotification(this.id);
|
||||
this.notifyObj2.id += "-2";
|
||||
this.notifyObj2.anchorID = "addons-notification-icon";
|
||||
// Second showNotification() overrides the first
|
||||
this.secondNotification = showNotification(this.notifyObj2);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
// This also checks that only one element is shown.
|
||||
checkPopup(popup, this.notifyObj2);
|
||||
is(document.getElementById("geo-notification-icon").boxObject.width, 0,
|
||||
"geo anchor shouldn't be visible");
|
||||
dismissNotification(popup);
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
// Remove the notifications
|
||||
this.firstNotification.remove();
|
||||
this.secondNotification.remove();
|
||||
ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
|
||||
ok(this.notifyObj2.removedCallbackTriggered, "removed callback triggered");
|
||||
}
|
||||
}
|
||||
];
|
@ -0,0 +1,242 @@
|
||||
/* 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/. */
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
ok(PopupNotifications, "PopupNotifications object exists");
|
||||
ok(PopupNotifications.panel, "PopupNotifications panel exists");
|
||||
|
||||
setup();
|
||||
goNext();
|
||||
}
|
||||
|
||||
let tests = [
|
||||
// Test optional params
|
||||
{ id: "Test#1",
|
||||
run: function () {
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
this.notifyObj.secondaryActions = undefined;
|
||||
this.notification = showNotification(this.notifyObj);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
checkPopup(popup, this.notifyObj);
|
||||
dismissNotification(popup);
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered");
|
||||
this.notification.remove();
|
||||
ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
|
||||
}
|
||||
},
|
||||
// Test that icons appear
|
||||
{ id: "Test#2",
|
||||
run: function () {
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
this.notifyObj.id = "geolocation";
|
||||
this.notifyObj.anchorID = "geo-notification-icon";
|
||||
this.notification = showNotification(this.notifyObj);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
checkPopup(popup, this.notifyObj);
|
||||
isnot(document.getElementById("geo-notification-icon").boxObject.width, 0,
|
||||
"geo anchor should be visible");
|
||||
dismissNotification(popup);
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
let icon = document.getElementById("geo-notification-icon");
|
||||
isnot(icon.boxObject.width, 0,
|
||||
"geo anchor should be visible after dismissal");
|
||||
this.notification.remove();
|
||||
is(icon.boxObject.width, 0,
|
||||
"geo anchor should not be visible after removal");
|
||||
}
|
||||
},
|
||||
|
||||
// Test that persistence allows the notification to persist across reloads
|
||||
{ id: "Test#3",
|
||||
run: function* () {
|
||||
this.oldSelectedTab = gBrowser.selectedTab;
|
||||
gBrowser.selectedTab = gBrowser.addTab("about:blank");
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.com/");
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
this.notifyObj.addOptions({
|
||||
persistence: 2
|
||||
});
|
||||
this.notification = showNotification(this.notifyObj);
|
||||
},
|
||||
onShown: function* (popup) {
|
||||
this.complete = false;
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.org/");
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.com/")
|
||||
// Next load will remove the notification
|
||||
this.complete = true;
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.org/");
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
ok(this.complete, "Should only have hidden the notification after 3 page loads");
|
||||
ok(this.notifyObj.removedCallbackTriggered, "removal callback triggered");
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
gBrowser.selectedTab = this.oldSelectedTab;
|
||||
}
|
||||
},
|
||||
// Test that a timeout allows the notification to persist across reloads
|
||||
{ id: "Test#4",
|
||||
run: function* () {
|
||||
this.oldSelectedTab = gBrowser.selectedTab;
|
||||
gBrowser.selectedTab = gBrowser.addTab("about:blank");
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.com/");
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
// Set a timeout of 10 minutes that should never be hit
|
||||
this.notifyObj.addOptions({
|
||||
timeout: Date.now() + 600000
|
||||
});
|
||||
this.notification = showNotification(this.notifyObj);
|
||||
},
|
||||
onShown: function* (popup) {
|
||||
this.complete = false;
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.org/");
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.com/");
|
||||
// Next load will hide the notification
|
||||
this.notification.options.timeout = Date.now() - 1;
|
||||
this.complete = true;
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.org/");
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
ok(this.complete, "Should only have hidden the notification after the timeout was passed");
|
||||
this.notification.remove();
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
gBrowser.selectedTab = this.oldSelectedTab;
|
||||
}
|
||||
},
|
||||
// Test that setting persistWhileVisible allows a visible notification to
|
||||
// persist across location changes
|
||||
{ id: "Test#5",
|
||||
run: function* () {
|
||||
this.oldSelectedTab = gBrowser.selectedTab;
|
||||
gBrowser.selectedTab = gBrowser.addTab("about:blank");
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.com/");
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
this.notifyObj.addOptions({
|
||||
persistWhileVisible: true
|
||||
});
|
||||
this.notification = showNotification(this.notifyObj);
|
||||
},
|
||||
onShown: function* (popup) {
|
||||
this.complete = false;
|
||||
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.org/");
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.com/");
|
||||
// Notification should persist across location changes
|
||||
this.complete = true;
|
||||
dismissNotification(popup);
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
ok(this.complete, "Should only have hidden the notification after it was dismissed");
|
||||
this.notification.remove();
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
gBrowser.selectedTab = this.oldSelectedTab;
|
||||
}
|
||||
},
|
||||
|
||||
// Test that nested icon nodes correctly activate popups
|
||||
{ id: "Test#6",
|
||||
run: function() {
|
||||
// Add a temporary box as the anchor with a button
|
||||
this.box = document.createElement("box");
|
||||
PopupNotifications.iconBox.appendChild(this.box);
|
||||
|
||||
let button = document.createElement("button");
|
||||
button.setAttribute("label", "Please click me!");
|
||||
this.box.appendChild(button);
|
||||
|
||||
// The notification should open up on the box
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
this.notifyObj.anchorID = this.box.id = "nested-box";
|
||||
this.notifyObj.addOptions({dismissed: true});
|
||||
this.notification = showNotification(this.notifyObj);
|
||||
|
||||
// This test places a normal button in the notification area, which has
|
||||
// standard GTK styling and dimensions. Due to the clip-path, this button
|
||||
// gets clipped off, which makes it necessary to synthesize the mouse click
|
||||
// a little bit downward. To be safe, I adjusted the x-offset with the same
|
||||
// amount.
|
||||
EventUtils.synthesizeMouse(button, 4, 4, {});
|
||||
},
|
||||
onShown: function(popup) {
|
||||
checkPopup(popup, this.notifyObj);
|
||||
dismissNotification(popup);
|
||||
},
|
||||
onHidden: function(popup) {
|
||||
this.notification.remove();
|
||||
this.box.parentNode.removeChild(this.box);
|
||||
}
|
||||
},
|
||||
// Test that popupnotifications without popups have anchor icons shown
|
||||
{ id: "Test#7",
|
||||
run: function* () {
|
||||
let notifyObj = new BasicNotification(this.id);
|
||||
notifyObj.anchorID = "geo-notification-icon";
|
||||
notifyObj.addOptions({neverShow: true});
|
||||
let promiseTopic = promiseTopicObserved("PopupNotifications-updateNotShowing");
|
||||
showNotification(notifyObj);
|
||||
yield promiseTopic;
|
||||
isnot(document.getElementById("geo-notification-icon").boxObject.width, 0,
|
||||
"geo anchor should be visible");
|
||||
goNext();
|
||||
}
|
||||
},
|
||||
// Test notification "Not Now" menu item
|
||||
{ id: "Test#8",
|
||||
run: function () {
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
this.notification = showNotification(this.notifyObj);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
checkPopup(popup, this.notifyObj);
|
||||
triggerSecondaryCommand(popup, 1);
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered");
|
||||
this.notification.remove();
|
||||
ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
|
||||
}
|
||||
},
|
||||
// Test notification close button
|
||||
{ id: "Test#9",
|
||||
run: function () {
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
this.notification = showNotification(this.notifyObj);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
checkPopup(popup, this.notifyObj);
|
||||
let notification = popup.childNodes[0];
|
||||
EventUtils.synthesizeMouseAtCenter(notification.closebutton, {});
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered");
|
||||
this.notification.remove();
|
||||
ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
|
||||
}
|
||||
},
|
||||
// Test notification when chrome is hidden
|
||||
{ id: "Test#10",
|
||||
run: function () {
|
||||
window.locationbar.visible = false;
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
this.notification = showNotification(this.notifyObj);
|
||||
window.locationbar.visible = true;
|
||||
},
|
||||
onShown: function (popup) {
|
||||
checkPopup(popup, this.notifyObj);
|
||||
is(popup.anchorNode.className, "tabbrowser-tab", "notification anchored to tab");
|
||||
dismissNotification(popup);
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered");
|
||||
this.notification.remove();
|
||||
ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
|
||||
}
|
||||
}
|
||||
];
|
@ -0,0 +1,310 @@
|
||||
/* 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/. */
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
ok(PopupNotifications, "PopupNotifications object exists");
|
||||
ok(PopupNotifications.panel, "PopupNotifications panel exists");
|
||||
|
||||
setup();
|
||||
goNext();
|
||||
}
|
||||
|
||||
let tests = [
|
||||
// Test notification is removed when dismissed if removeOnDismissal is true
|
||||
{ id: "Test#1",
|
||||
run: function () {
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
this.notifyObj.addOptions({
|
||||
removeOnDismissal: true
|
||||
});
|
||||
this.notification = showNotification(this.notifyObj);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
checkPopup(popup, this.notifyObj);
|
||||
dismissNotification(popup);
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
ok(!this.notifyObj.dismissalCallbackTriggered, "dismissal callback wasn't triggered");
|
||||
ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
|
||||
}
|
||||
},
|
||||
// Test multiple notification icons are shown
|
||||
{ id: "Test#2",
|
||||
run: function () {
|
||||
this.notifyObj1 = new BasicNotification(this.id);
|
||||
this.notifyObj1.id += "_1";
|
||||
this.notifyObj1.anchorID = "default-notification-icon";
|
||||
this.notification1 = showNotification(this.notifyObj1);
|
||||
|
||||
this.notifyObj2 = new BasicNotification(this.id);
|
||||
this.notifyObj2.id += "_2";
|
||||
this.notifyObj2.anchorID = "geo-notification-icon";
|
||||
this.notification2 = showNotification(this.notifyObj2);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
checkPopup(popup, this.notifyObj2);
|
||||
|
||||
// check notifyObj1 anchor icon is showing
|
||||
isnot(document.getElementById("default-notification-icon").boxObject.width, 0,
|
||||
"default anchor should be visible");
|
||||
// check notifyObj2 anchor icon is showing
|
||||
isnot(document.getElementById("geo-notification-icon").boxObject.width, 0,
|
||||
"geo anchor should be visible");
|
||||
|
||||
dismissNotification(popup);
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
this.notification1.remove();
|
||||
ok(this.notifyObj1.removedCallbackTriggered, "removed callback triggered");
|
||||
|
||||
this.notification2.remove();
|
||||
ok(this.notifyObj2.removedCallbackTriggered, "removed callback triggered");
|
||||
}
|
||||
},
|
||||
// Test that multiple notification icons are removed when switching tabs
|
||||
{ id: "Test#3",
|
||||
run: function () {
|
||||
// show the notification on old tab.
|
||||
this.notifyObjOld = new BasicNotification(this.id);
|
||||
this.notifyObjOld.anchorID = "default-notification-icon";
|
||||
this.notificationOld = showNotification(this.notifyObjOld);
|
||||
|
||||
// switch tab
|
||||
this.oldSelectedTab = gBrowser.selectedTab;
|
||||
gBrowser.selectedTab = gBrowser.addTab("about:blank");
|
||||
|
||||
// show the notification on new tab.
|
||||
this.notifyObjNew = new BasicNotification(this.id);
|
||||
this.notifyObjNew.anchorID = "geo-notification-icon";
|
||||
this.notificationNew = showNotification(this.notifyObjNew);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
checkPopup(popup, this.notifyObjNew);
|
||||
|
||||
// check notifyObjOld anchor icon is removed
|
||||
is(document.getElementById("default-notification-icon").boxObject.width, 0,
|
||||
"default anchor shouldn't be visible");
|
||||
// check notifyObjNew anchor icon is showing
|
||||
isnot(document.getElementById("geo-notification-icon").boxObject.width, 0,
|
||||
"geo anchor should be visible");
|
||||
|
||||
dismissNotification(popup);
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
this.notificationNew.remove();
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
|
||||
gBrowser.selectedTab = this.oldSelectedTab;
|
||||
this.notificationOld.remove();
|
||||
}
|
||||
},
|
||||
// test security delay - too early
|
||||
{ id: "Test#4",
|
||||
run: function () {
|
||||
// Set the security delay to 100s
|
||||
PopupNotifications.buttonDelay = 100000;
|
||||
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
showNotification(this.notifyObj);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
checkPopup(popup, this.notifyObj);
|
||||
triggerMainCommand(popup);
|
||||
|
||||
// Wait to see if the main command worked
|
||||
executeSoon(function delayedDismissal() {
|
||||
dismissNotification(popup);
|
||||
});
|
||||
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
ok(!this.notifyObj.mainActionClicked, "mainAction was not clicked because it was too soon");
|
||||
ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback was triggered");
|
||||
}
|
||||
},
|
||||
// test security delay - after delay
|
||||
{ id: "Test#5",
|
||||
run: function () {
|
||||
// Set the security delay to 10ms
|
||||
PopupNotifications.buttonDelay = 10;
|
||||
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
showNotification(this.notifyObj);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
checkPopup(popup, this.notifyObj);
|
||||
|
||||
// Wait until after the delay to trigger the main action
|
||||
setTimeout(function delayedDismissal() {
|
||||
triggerMainCommand(popup);
|
||||
}, 500);
|
||||
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
ok(this.notifyObj.mainActionClicked, "mainAction was clicked after the delay");
|
||||
ok(!this.notifyObj.dismissalCallbackTriggered, "dismissal callback was not triggered");
|
||||
PopupNotifications.buttonDelay = PREF_SECURITY_DELAY_INITIAL;
|
||||
}
|
||||
},
|
||||
// reload removes notification
|
||||
{ id: "Test#6",
|
||||
run: function* () {
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.com/");
|
||||
let notifyObj = new BasicNotification(this.id);
|
||||
notifyObj.options.eventCallback = function (eventName) {
|
||||
if (eventName == "removed") {
|
||||
ok(true, "Notification removed in background tab after reloading");
|
||||
goNext();
|
||||
}
|
||||
};
|
||||
showNotification(notifyObj);
|
||||
executeSoon(function () {
|
||||
gBrowser.selectedBrowser.reload();
|
||||
});
|
||||
}
|
||||
},
|
||||
// location change in background tab removes notification
|
||||
{ id: "Test#7",
|
||||
run: function* () {
|
||||
let oldSelectedTab = gBrowser.selectedTab;
|
||||
let newTab = gBrowser.addTab("about:blank");
|
||||
gBrowser.selectedTab = newTab;
|
||||
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.com/");
|
||||
gBrowser.selectedTab = oldSelectedTab;
|
||||
let browser = gBrowser.getBrowserForTab(newTab);
|
||||
|
||||
let notifyObj = new BasicNotification(this.id);
|
||||
notifyObj.browser = browser;
|
||||
notifyObj.options.eventCallback = function (eventName) {
|
||||
if (eventName == "removed") {
|
||||
ok(true, "Notification removed in background tab after reloading");
|
||||
executeSoon(function () {
|
||||
gBrowser.removeTab(newTab);
|
||||
goNext();
|
||||
});
|
||||
}
|
||||
};
|
||||
showNotification(notifyObj);
|
||||
executeSoon(function () {
|
||||
browser.reload();
|
||||
});
|
||||
}
|
||||
},
|
||||
// Popup notification anchor shouldn't disappear when a notification with the same ID is re-added in a background tab
|
||||
{ id: "Test#8",
|
||||
run: function* () {
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.com/");
|
||||
let originalTab = gBrowser.selectedTab;
|
||||
let bgTab = gBrowser.addTab("about:blank");
|
||||
gBrowser.selectedTab = bgTab;
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.com/");
|
||||
let anchor = document.createElement("box");
|
||||
anchor.id = "test26-anchor";
|
||||
anchor.className = "notification-anchor-icon";
|
||||
PopupNotifications.iconBox.appendChild(anchor);
|
||||
|
||||
gBrowser.selectedTab = originalTab;
|
||||
|
||||
let fgNotifyObj = new BasicNotification(this.id);
|
||||
fgNotifyObj.anchorID = anchor.id;
|
||||
fgNotifyObj.options.dismissed = true;
|
||||
let fgNotification = showNotification(fgNotifyObj);
|
||||
|
||||
let bgNotifyObj = new BasicNotification(this.id);
|
||||
bgNotifyObj.anchorID = anchor.id;
|
||||
bgNotifyObj.browser = gBrowser.getBrowserForTab(bgTab);
|
||||
// show the notification in the background tab ...
|
||||
let bgNotification = showNotification(bgNotifyObj);
|
||||
// ... and re-show it
|
||||
bgNotification = showNotification(bgNotifyObj);
|
||||
|
||||
ok(fgNotification.id, "notification has id");
|
||||
is(fgNotification.id, bgNotification.id, "notification ids are the same");
|
||||
is(anchor.getAttribute("showing"), "true", "anchor still showing");
|
||||
|
||||
fgNotification.remove();
|
||||
gBrowser.removeTab(bgTab);
|
||||
goNext();
|
||||
}
|
||||
},
|
||||
// location change in an embedded frame should not remove a notification
|
||||
{ id: "Test#9",
|
||||
run: function* () {
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html;charset=utf8,<iframe%20id='iframe'%20src='http://example.com/'>");
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
this.notifyObj.options.eventCallback = function (eventName) {
|
||||
if (eventName == "removed") {
|
||||
ok(false, "Notification removed from browser when subframe navigated");
|
||||
}
|
||||
};
|
||||
showNotification(this.notifyObj);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
let self = this;
|
||||
let progressListener = {
|
||||
onLocationChange: function onLocationChange(aBrowser) {
|
||||
if (aBrowser != gBrowser.selectedBrowser) {
|
||||
return;
|
||||
}
|
||||
let notification = PopupNotifications.getNotification(self.notifyObj.id,
|
||||
self.notifyObj.browser);
|
||||
ok(notification != null, "Notification remained when subframe navigated");
|
||||
self.notifyObj.options.eventCallback = undefined;
|
||||
|
||||
notification.remove();
|
||||
gBrowser.removeTabsProgressListener(progressListener);
|
||||
},
|
||||
};
|
||||
|
||||
info("Adding progress listener and performing navigation");
|
||||
gBrowser.addTabsProgressListener(progressListener);
|
||||
content.document.getElementById("iframe")
|
||||
.setAttribute("src", "http://example.org/");
|
||||
},
|
||||
onHidden: function () {}
|
||||
},
|
||||
// Popup Notifications should catch exceptions from callbacks
|
||||
{ id: "Test#10",
|
||||
run: function () {
|
||||
let callbackCount = 0;
|
||||
this.testNotif1 = new BasicNotification(this.id);
|
||||
this.testNotif1.message += " 1";
|
||||
this.notification1 = showNotification(this.testNotif1);
|
||||
this.testNotif1.options.eventCallback = function (eventName) {
|
||||
info("notifyObj1.options.eventCallback: " + eventName);
|
||||
if (eventName == "dismissed") {
|
||||
throw new Error("Oops 1!");
|
||||
if (++callbackCount == 2) {
|
||||
goNext();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.testNotif2 = new BasicNotification(this.id);
|
||||
this.testNotif2.message += " 2";
|
||||
this.testNotif2.id += "-2";
|
||||
this.testNotif2.options.eventCallback = function (eventName) {
|
||||
info("notifyObj2.options.eventCallback: " + eventName);
|
||||
if (eventName == "dismissed") {
|
||||
throw new Error("Oops 2!");
|
||||
if (++callbackCount == 2) {
|
||||
goNext();
|
||||
}
|
||||
}
|
||||
};
|
||||
this.notification2 = showNotification(this.testNotif2);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
is(popup.childNodes.length, 2, "two notifications are shown");
|
||||
dismissNotification(popup);
|
||||
},
|
||||
onHidden: function () {
|
||||
this.notification1.remove();
|
||||
this.notification2.remove();
|
||||
}
|
||||
}
|
||||
];
|
@ -0,0 +1,210 @@
|
||||
/* 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/. */
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
ok(PopupNotifications, "PopupNotifications object exists");
|
||||
ok(PopupNotifications.panel, "PopupNotifications panel exists");
|
||||
|
||||
setup();
|
||||
goNext();
|
||||
}
|
||||
|
||||
let tests = [
|
||||
// Popup Notifications main actions should catch exceptions from callbacks
|
||||
{ id: "Test#1",
|
||||
run: function () {
|
||||
this.testNotif = new ErrorNotification();
|
||||
showNotification(this.testNotif);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
checkPopup(popup, this.testNotif);
|
||||
triggerMainCommand(popup);
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
ok(this.testNotif.mainActionClicked, "main action has been triggered");
|
||||
}
|
||||
},
|
||||
// Popup Notifications secondary actions should catch exceptions from callbacks
|
||||
{ id: "Test#2",
|
||||
run: function () {
|
||||
this.testNotif = new ErrorNotification();
|
||||
showNotification(this.testNotif);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
checkPopup(popup, this.testNotif);
|
||||
triggerSecondaryCommand(popup, 0);
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
ok(this.testNotif.secondaryActionClicked, "secondary action has been triggered");
|
||||
}
|
||||
},
|
||||
// Existing popup notification shouldn't disappear when adding a dismissed notification
|
||||
{ id: "Test#3",
|
||||
run: function () {
|
||||
this.notifyObj1 = new BasicNotification(this.id);
|
||||
this.notifyObj1.id += "_1";
|
||||
this.notifyObj1.anchorID = "default-notification-icon";
|
||||
this.notification1 = showNotification(this.notifyObj1);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
// Now show a dismissed notification, and check that it doesn't clobber
|
||||
// the showing one.
|
||||
this.notifyObj2 = new BasicNotification(this.id);
|
||||
this.notifyObj2.id += "_2";
|
||||
this.notifyObj2.anchorID = "geo-notification-icon";
|
||||
this.notifyObj2.options.dismissed = true;
|
||||
this.notification2 = showNotification(this.notifyObj2);
|
||||
|
||||
checkPopup(popup, this.notifyObj1);
|
||||
|
||||
// check that both anchor icons are showing
|
||||
is(document.getElementById("default-notification-icon").getAttribute("showing"), "true",
|
||||
"notification1 anchor should be visible");
|
||||
is(document.getElementById("geo-notification-icon").getAttribute("showing"), "true",
|
||||
"notification2 anchor should be visible");
|
||||
|
||||
dismissNotification(popup);
|
||||
},
|
||||
onHidden: function(popup) {
|
||||
this.notification1.remove();
|
||||
this.notification2.remove();
|
||||
}
|
||||
},
|
||||
// Showing should be able to modify the popup data
|
||||
{ id: "Test#4",
|
||||
run: function() {
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
let normalCallback = this.notifyObj.options.eventCallback;
|
||||
this.notifyObj.options.eventCallback = function (eventName) {
|
||||
if (eventName == "showing") {
|
||||
this.mainAction.label = "Alternate Label";
|
||||
}
|
||||
normalCallback.call(this, eventName);
|
||||
};
|
||||
showNotification(this.notifyObj);
|
||||
},
|
||||
onShown: function(popup) {
|
||||
// checkPopup checks for the matching label. Note that this assumes that
|
||||
// this.notifyObj.mainAction is the same as notification.mainAction,
|
||||
// which could be a problem if we ever decided to deep-copy.
|
||||
checkPopup(popup, this.notifyObj);
|
||||
triggerMainCommand(popup);
|
||||
},
|
||||
onHidden: function() { }
|
||||
},
|
||||
// Moving a tab to a new window should remove non-swappable notifications.
|
||||
{ id: "Test#5",
|
||||
run: function() {
|
||||
gBrowser.selectedTab = gBrowser.addTab("about:blank");
|
||||
let notifyObj = new BasicNotification(this.id);
|
||||
showNotification(notifyObj);
|
||||
let win = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
|
||||
whenDelayedStartupFinished(win, function() {
|
||||
let [tab] = win.gBrowser.tabs;
|
||||
let anchor = win.document.getElementById("default-notification-icon");
|
||||
win.PopupNotifications._reshowNotifications(anchor);
|
||||
ok(win.PopupNotifications.panel.childNodes.length == 0,
|
||||
"no notification displayed in new window");
|
||||
ok(notifyObj.swappingCallbackTriggered, "the swapping callback was triggered");
|
||||
ok(notifyObj.removedCallbackTriggered, "the removed callback was triggered");
|
||||
win.close();
|
||||
goNext();
|
||||
});
|
||||
}
|
||||
},
|
||||
// Moving a tab to a new window should preserve swappable notifications.
|
||||
{ id: "Test#6",
|
||||
run: function() {
|
||||
gBrowser.selectedTab = gBrowser.addTab("about:blank");
|
||||
let notifyObj = new BasicNotification(this.id);
|
||||
let originalCallback = notifyObj.options.eventCallback;
|
||||
notifyObj.options.eventCallback = function (eventName) {
|
||||
originalCallback(eventName);
|
||||
return eventName == "swapping";
|
||||
};
|
||||
|
||||
showNotification(notifyObj);
|
||||
let win = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
|
||||
whenDelayedStartupFinished(win, function() {
|
||||
let [tab] = win.gBrowser.tabs;
|
||||
let anchor = win.document.getElementById("default-notification-icon");
|
||||
win.PopupNotifications._reshowNotifications(anchor);
|
||||
checkPopup(win.PopupNotifications.panel, notifyObj);
|
||||
ok(notifyObj.swappingCallbackTriggered, "the swapping callback was triggered");
|
||||
win.close();
|
||||
goNext();
|
||||
});
|
||||
}
|
||||
},
|
||||
// the hideNotNow option
|
||||
{ id: "Test#7",
|
||||
run: function () {
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
this.notifyObj.options.hideNotNow = true;
|
||||
this.notifyObj.mainAction.dismiss = true;
|
||||
this.notification = showNotification(this.notifyObj);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
// checkPopup verifies that the Not Now item is hidden, and that no separator is added.
|
||||
checkPopup(popup, this.notifyObj);
|
||||
triggerMainCommand(popup);
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
this.notification.remove();
|
||||
}
|
||||
},
|
||||
// the main action callback can keep the notification.
|
||||
{ id: "Test#8",
|
||||
run: function () {
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
this.notifyObj.mainAction.dismiss = true;
|
||||
this.notification = showNotification(this.notifyObj);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
checkPopup(popup, this.notifyObj);
|
||||
triggerMainCommand(popup);
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback was triggered");
|
||||
ok(!this.notifyObj.removedCallbackTriggered, "removed callback wasn't triggered");
|
||||
this.notification.remove();
|
||||
}
|
||||
},
|
||||
// a secondary action callback can keep the notification.
|
||||
{ id: "Test#9",
|
||||
run: function () {
|
||||
this.notifyObj = new BasicNotification(this.id);
|
||||
this.notifyObj.secondaryActions[0].dismiss = true;
|
||||
this.notification = showNotification(this.notifyObj);
|
||||
},
|
||||
onShown: function (popup) {
|
||||
checkPopup(popup, this.notifyObj);
|
||||
triggerSecondaryCommand(popup, 0);
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback was triggered");
|
||||
ok(!this.notifyObj.removedCallbackTriggered, "removed callback wasn't triggered");
|
||||
this.notification.remove();
|
||||
}
|
||||
},
|
||||
// returning true in the showing callback should dismiss the notification.
|
||||
{ id: "Test#10",
|
||||
run: function() {
|
||||
let notifyObj = new BasicNotification(this.id);
|
||||
let originalCallback = notifyObj.options.eventCallback;
|
||||
notifyObj.options.eventCallback = function (eventName) {
|
||||
originalCallback(eventName);
|
||||
return eventName == "showing";
|
||||
};
|
||||
|
||||
let notification = showNotification(notifyObj);
|
||||
ok(notifyObj.showingCallbackTriggered, "the showing callback was triggered");
|
||||
ok(!notifyObj.shownCallbackTriggered, "the shown callback wasn't triggered");
|
||||
notification.remove();
|
||||
goNext();
|
||||
}
|
||||
}
|
||||
];
|
313
browser/base/content/test/popupNotifications/head.js
Normal file
313
browser/base/content/test/popupNotifications/head.js
Normal file
@ -0,0 +1,313 @@
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
|
||||
function whenDelayedStartupFinished(aWindow, aCallback) {
|
||||
Services.obs.addObserver(function observer(aSubject, aTopic) {
|
||||
if (aWindow == aSubject) {
|
||||
Services.obs.removeObserver(observer, aTopic);
|
||||
executeSoon(aCallback);
|
||||
}
|
||||
}, "browser-delayed-startup-finished", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows waiting for an observer notification once.
|
||||
*
|
||||
* @param topic
|
||||
* Notification topic to observe.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves The array [subject, data] from the observed notification.
|
||||
* @rejects Never.
|
||||
*/
|
||||
function promiseTopicObserved(topic)
|
||||
{
|
||||
let deferred = Promise.defer();
|
||||
info("Waiting for observer topic " + topic);
|
||||
Services.obs.addObserver(function PTO_observe(subject, topic, data) {
|
||||
Services.obs.removeObserver(PTO_observe, topic);
|
||||
deferred.resolve([subject, data]);
|
||||
}, topic, false);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Waits for a load (or custom) event to finish in a given tab. If provided
|
||||
* load an uri into the tab.
|
||||
*
|
||||
* @param tab
|
||||
* The tab to load into.
|
||||
* @param [optional] url
|
||||
* The url to load, or the current url.
|
||||
* @param [optional] event
|
||||
* The load event type to wait for. Defaults to "load".
|
||||
* @return {Promise} resolved when the event is handled.
|
||||
* @resolves to the received event
|
||||
* @rejects if a valid load event is not received within a meaningful interval
|
||||
*/
|
||||
function promiseTabLoadEvent(tab, url, eventType="load")
|
||||
{
|
||||
let deferred = Promise.defer();
|
||||
info("Wait tab event: " + eventType);
|
||||
|
||||
function handle(event) {
|
||||
if (event.originalTarget != tab.linkedBrowser.contentDocument ||
|
||||
event.target.location.href == "about:blank" ||
|
||||
(url && event.target.location.href != url)) {
|
||||
info("Skipping spurious '" + eventType + "'' event" +
|
||||
" for " + event.target.location.href);
|
||||
return;
|
||||
}
|
||||
clearTimeout(timeout);
|
||||
tab.linkedBrowser.removeEventListener(eventType, handle, true);
|
||||
info("Tab event received: " + eventType);
|
||||
deferred.resolve(event);
|
||||
}
|
||||
|
||||
let timeout = setTimeout(() => {
|
||||
if (tab.linkedBrowser)
|
||||
tab.linkedBrowser.removeEventListener(eventType, handle, true);
|
||||
deferred.reject(new Error("Timed out while waiting for a '" + eventType + "'' event"));
|
||||
}, 30000);
|
||||
|
||||
tab.linkedBrowser.addEventListener(eventType, handle, true, true);
|
||||
if (url)
|
||||
tab.linkedBrowser.loadURI(url);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
const PREF_SECURITY_DELAY_INITIAL = Services.prefs.getIntPref("security.notification_enable_delay");
|
||||
|
||||
function setup() {
|
||||
// Disable transitions as they slow the test down and we want to click the
|
||||
// mouse buttons in a predictable location.
|
||||
PopupNotifications.transitionsEnabled = false;
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
PopupNotifications.buttonDelay = PREF_SECURITY_DELAY_INITIAL;
|
||||
PopupNotifications.transitionsEnabled = true;
|
||||
});
|
||||
}
|
||||
|
||||
function goNext() {
|
||||
executeSoon(() => executeSoon(Task.async(runNextTest)));
|
||||
}
|
||||
|
||||
function* runNextTest() {
|
||||
if (tests.length == 0) {
|
||||
executeSoon(finish);
|
||||
return;
|
||||
}
|
||||
|
||||
let nextTest = tests.shift();
|
||||
if (nextTest.onShown) {
|
||||
let shownState = false;
|
||||
onPopupEvent("popupshowing", function () {
|
||||
info("[" + nextTest.id + "] popup showing");
|
||||
});
|
||||
onPopupEvent("popupshown", function () {
|
||||
shownState = true;
|
||||
info("[" + nextTest.id + "] popup shown");
|
||||
Task.spawn(() => nextTest.onShown(this))
|
||||
.then(undefined , ex => Assert.ok(false, "onShown failed: " + ex));
|
||||
});
|
||||
onPopupEvent("popuphidden", function () {
|
||||
info("[" + nextTest.id + "] popup hidden");
|
||||
nextTest.onHidden(this);
|
||||
goNext();
|
||||
}, () => shownState);
|
||||
info("[" + nextTest.id + "] added listeners; panel is open: " + PopupNotifications.isPanelOpen);
|
||||
}
|
||||
|
||||
info("[" + nextTest.id + "] running test");
|
||||
yield nextTest.run();
|
||||
}
|
||||
|
||||
function showNotification(notifyObj) {
|
||||
info("Showing notification " + notifyObj.id);
|
||||
return PopupNotifications.show(notifyObj.browser,
|
||||
notifyObj.id,
|
||||
notifyObj.message,
|
||||
notifyObj.anchorID,
|
||||
notifyObj.mainAction,
|
||||
notifyObj.secondaryActions,
|
||||
notifyObj.options);
|
||||
}
|
||||
|
||||
function dismissNotification(popup) {
|
||||
info("Dismissing notification " + popup.childNodes[0].id);
|
||||
executeSoon(() => EventUtils.synthesizeKey("VK_ESCAPE", {}));
|
||||
}
|
||||
|
||||
function BasicNotification(testId) {
|
||||
this.browser = gBrowser.selectedBrowser;
|
||||
this.id = "test-notification-" + testId;
|
||||
this.message = "This is popup notification for " + testId;
|
||||
this.anchorID = null;
|
||||
this.mainAction = {
|
||||
label: "Main Action",
|
||||
accessKey: "M",
|
||||
callback: () => this.mainActionClicked = true
|
||||
};
|
||||
this.secondaryActions = [
|
||||
{
|
||||
label: "Secondary Action",
|
||||
accessKey: "S",
|
||||
callback: () => this.secondaryActionClicked = true
|
||||
}
|
||||
];
|
||||
this.options = {
|
||||
eventCallback: eventName => {
|
||||
switch (eventName) {
|
||||
case "dismissed":
|
||||
this.dismissalCallbackTriggered = true;
|
||||
break;
|
||||
case "showing":
|
||||
this.showingCallbackTriggered = true;
|
||||
break;
|
||||
case "shown":
|
||||
this.shownCallbackTriggered = true;
|
||||
break;
|
||||
case "removed":
|
||||
this.removedCallbackTriggered = true;
|
||||
break;
|
||||
case "swapping":
|
||||
this.swappingCallbackTriggered = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
BasicNotification.prototype.addOptions = function(options) {
|
||||
for (let [name, value] in Iterator(options))
|
||||
this.options[name] = value;
|
||||
};
|
||||
|
||||
function ErrorNotification() {
|
||||
this.mainAction.callback = () => {
|
||||
this.mainActionClicked = true;
|
||||
throw new Error("Oops!");
|
||||
};
|
||||
this.secondaryActions[0].callback = () => {
|
||||
this.secondaryActionClicked = true;
|
||||
throw new Error("Oops!");
|
||||
};
|
||||
}
|
||||
|
||||
ErrorNotification.prototype = new BasicNotification();
|
||||
ErrorNotification.prototype.constructor = ErrorNotification;
|
||||
|
||||
function checkPopup(popup, notifyObj) {
|
||||
info("Checking notification " + notifyObj.id);
|
||||
|
||||
ok(notifyObj.showingCallbackTriggered, "showing callback was triggered");
|
||||
ok(notifyObj.shownCallbackTriggered, "shown callback was triggered");
|
||||
|
||||
let notifications = popup.childNodes;
|
||||
is(notifications.length, 1, "one notification displayed");
|
||||
let notification = notifications[0];
|
||||
if (!notification)
|
||||
return;
|
||||
let icon = document.getAnonymousElementByAttribute(notification, "class",
|
||||
"popup-notification-icon");
|
||||
if (notifyObj.id == "geolocation") {
|
||||
isnot(icon.boxObject.width, 0, "icon for geo displayed");
|
||||
is(popup.anchorNode.className, "notification-anchor-icon",
|
||||
"notification anchored to icon");
|
||||
}
|
||||
is(notification.getAttribute("label"), notifyObj.message, "message matches");
|
||||
is(notification.id, notifyObj.id + "-notification", "id matches");
|
||||
if (notifyObj.mainAction) {
|
||||
is(notification.getAttribute("buttonlabel"), notifyObj.mainAction.label,
|
||||
"main action label matches");
|
||||
is(notification.getAttribute("buttonaccesskey"),
|
||||
notifyObj.mainAction.accessKey, "main action accesskey matches");
|
||||
}
|
||||
let actualSecondaryActions =
|
||||
Array.filter(notification.childNodes, child => child.nodeName == "menuitem");
|
||||
let secondaryActions = notifyObj.secondaryActions || [];
|
||||
let actualSecondaryActionsCount = actualSecondaryActions.length;
|
||||
if (notifyObj.options.hideNotNow) {
|
||||
is(notification.getAttribute("hidenotnow"), "true", "'Not Now' item hidden");
|
||||
if (secondaryActions.length)
|
||||
is(notification.lastChild.tagName, "menuitem", "no menuseparator");
|
||||
}
|
||||
else if (secondaryActions.length) {
|
||||
is(notification.lastChild.tagName, "menuseparator", "menuseparator exists");
|
||||
}
|
||||
is(actualSecondaryActionsCount, secondaryActions.length,
|
||||
actualSecondaryActions.length + " secondary actions");
|
||||
secondaryActions.forEach(function (a, i) {
|
||||
is(actualSecondaryActions[i].getAttribute("label"), a.label,
|
||||
"label for secondary action " + i + " matches");
|
||||
is(actualSecondaryActions[i].getAttribute("accesskey"), a.accessKey,
|
||||
"accessKey for secondary action " + i + " matches");
|
||||
});
|
||||
}
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gActiveListeners", () => {
|
||||
let listeners = new Map();
|
||||
registerCleanupFunction(() => {
|
||||
for (let [listener, eventName] of listeners) {
|
||||
PopupNotifications.panel.removeEventListener(eventName, listener, false);
|
||||
}
|
||||
});
|
||||
return listeners;
|
||||
});
|
||||
|
||||
function onPopupEvent(eventName, callback, condition) {
|
||||
let listener = event => {
|
||||
if (event.target != PopupNotifications.panel ||
|
||||
(condition && !condition()))
|
||||
return;
|
||||
PopupNotifications.panel.removeEventListener(eventName, listener, false);
|
||||
gActiveListeners.delete(listener);
|
||||
executeSoon(() => callback.call(PopupNotifications.panel));
|
||||
}
|
||||
gActiveListeners.set(listener, eventName);
|
||||
PopupNotifications.panel.addEventListener(eventName, listener, false);
|
||||
}
|
||||
|
||||
function triggerMainCommand(popup) {
|
||||
let notifications = popup.childNodes;
|
||||
ok(notifications.length > 0, "at least one notification displayed");
|
||||
let notification = notifications[0];
|
||||
info("Triggering main command for notification " + notification.id);
|
||||
// 20, 10 so that the inner button is hit
|
||||
EventUtils.synthesizeMouse(notification.button, 20, 10, {});
|
||||
}
|
||||
|
||||
function triggerSecondaryCommand(popup, index) {
|
||||
let notifications = popup.childNodes;
|
||||
ok(notifications.length > 0, "at least one notification displayed");
|
||||
let notification = notifications[0];
|
||||
info("Triggering secondary command for notification " + notification.id);
|
||||
// Cancel the arrow panel slide-in transition (bug 767133) such that
|
||||
// it won't interfere with us interacting with the dropdown.
|
||||
document.getAnonymousNodes(popup)[0].style.transition = "none";
|
||||
|
||||
notification.button.focus();
|
||||
|
||||
popup.addEventListener("popupshown", function handle() {
|
||||
popup.removeEventListener("popupshown", handle, false);
|
||||
info("Command popup open for notification " + notification.id);
|
||||
// Press down until the desired command is selected
|
||||
for (let i = 0; i <= index; i++) {
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
}
|
||||
// Activate
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
}, false);
|
||||
|
||||
// One down event to open the popup
|
||||
info("Open the popup to trigger secondary command for notification " + notification.id);
|
||||
EventUtils.synthesizeKey("VK_DOWN", { altKey: !navigator.platform.contains("Mac") });
|
||||
}
|
@ -17,6 +17,7 @@ BROWSER_CHROME_MANIFESTS += [
|
||||
'content/test/general/browser.ini',
|
||||
'content/test/newtab/browser.ini',
|
||||
'content/test/plugins/browser.ini',
|
||||
'content/test/popupNotifications/browser.ini',
|
||||
'content/test/social/browser.ini',
|
||||
]
|
||||
|
||||
|
@ -10,6 +10,7 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
const DBG_STRINGS_URI = "chrome://browser/locale/devtools/debugger.properties";
|
||||
const NEW_SOURCE_IGNORED_URLS = ["debugger eval code", "self-hosted", "XStringBundle"];
|
||||
const NEW_SOURCE_DISPLAY_DELAY = 200; // ms
|
||||
const EDITOR_BREAKPOINTS_UPDATE_DELAY = 200; // ms
|
||||
const FETCH_SOURCE_RESPONSE_DELAY = 200; // ms
|
||||
const FETCH_EVENT_LISTENERS_DELAY = 200; // ms
|
||||
const FRAME_STEP_CLEAR_DELAY = 100; // ms
|
||||
@ -1167,8 +1168,10 @@ SourceScripts.prototype = {
|
||||
|
||||
// If there are any stored breakpoints for this source, display them again,
|
||||
// both in the editor and the breakpoints pane.
|
||||
DebuggerController.Breakpoints.updateEditorBreakpoints();
|
||||
DebuggerController.Breakpoints.updatePaneBreakpoints();
|
||||
setNamedTimeout("update-editor-bp", EDITOR_BREAKPOINTS_UPDATE_DELAY, () => {
|
||||
DebuggerController.Breakpoints.updateEditorBreakpoints();
|
||||
});
|
||||
|
||||
// Make sure the events listeners are up to date.
|
||||
if (DebuggerView.instrumentsPaneTab == "events-tab") {
|
||||
@ -1219,8 +1222,8 @@ SourceScripts.prototype = {
|
||||
|
||||
// If there are any stored breakpoints for the sources, display them again,
|
||||
// both in the editor and the breakpoints pane.
|
||||
DebuggerController.Breakpoints.updateEditorBreakpoints();
|
||||
DebuggerController.Breakpoints.updatePaneBreakpoints();
|
||||
DebuggerController.Breakpoints.updateEditorBreakpoints();
|
||||
|
||||
// Signal that sources have been added.
|
||||
window.emit(EVENTS.SOURCES_ADDED);
|
||||
@ -1711,6 +1714,10 @@ EventListeners.prototype = {
|
||||
throw "Error getting event listeners: " + aResponse.message;
|
||||
}
|
||||
|
||||
// Make sure all the listeners are sorted by the event type, since
|
||||
// they're not guaranteed to be clustered together.
|
||||
aResponse.listeners.sort((a, b) => a.type > b.type ? 1 : -1);
|
||||
|
||||
// Add all the listeners in the debugger view event linsteners container.
|
||||
for (let listener of aResponse.listeners) {
|
||||
let definitionSite = yield this._getDefinitionSite(listener.function);
|
||||
|
@ -78,6 +78,7 @@ support-files =
|
||||
doc_scope-variable-4.html
|
||||
doc_script-switching-01.html
|
||||
doc_script-switching-02.html
|
||||
doc_split-console-paused-reload.html
|
||||
doc_step-out.html
|
||||
doc_terminate-on-tab-close.html
|
||||
doc_tracing-01.html
|
||||
@ -237,6 +238,7 @@ skip-if = os == "linux" || e10s # Bug 888811 & bug 891176
|
||||
[browser_dbg_sources-cache.js]
|
||||
[browser_dbg_sources-labels.js]
|
||||
[browser_dbg_sources-sorting.js]
|
||||
[browser_dbg_split-console-paused-reload.js]
|
||||
[browser_dbg_stack-01.js]
|
||||
[browser_dbg_stack-02.js]
|
||||
[browser_dbg_stack-03.js]
|
||||
|
@ -30,16 +30,16 @@ function test() {
|
||||
is(gEvents.widget._parent.querySelectorAll(".side-menu-widget-item-checkbox").length, 4,
|
||||
"There should be a checkbox for each item shown in the view.");
|
||||
|
||||
testEventItem(0, "doc_event-listeners-02.html", "keydown", ["window", "body"], false);
|
||||
testEventItem(0, "doc_event-listeners-02.html", "change", ["body > input:nth-child(2)"], false);
|
||||
testEventItem(1, "doc_event-listeners-02.html", "click", ["body > button:nth-child(1)"], false);
|
||||
testEventItem(2, "doc_event-listeners-02.html", "change", ["body > input:nth-child(2)"], false);
|
||||
testEventItem(2, "doc_event-listeners-02.html", "keydown", ["window", "body"], false);
|
||||
testEventItem(3, "doc_event-listeners-02.html", "keyup", ["body > input:nth-child(2)"], false);
|
||||
|
||||
testEventGroup("interactionEvents", false);
|
||||
testEventGroup("keyboardEvents", false);
|
||||
testEventGroup("mouseEvents", false);
|
||||
|
||||
is(gEvents.getAllEvents().toString(), "keydown,click,change,keyup",
|
||||
is(gEvents.getAllEvents().toString(), "change,click,keydown,keyup",
|
||||
"The getAllEvents() method returns the correct stuff.");
|
||||
is(gEvents.getCheckedEvents().toString(), "",
|
||||
"The getCheckedEvents() method returns the correct stuff.");
|
||||
|
@ -30,7 +30,7 @@ function test() {
|
||||
testEventGroup("interactionEvents", false);
|
||||
testEventGroup("keyboardEvents", false);
|
||||
testEventGroup("mouseEvents", false);
|
||||
testEventArrays("keydown,click,change,keyup", "");
|
||||
testEventArrays("change,click,keydown,keyup", "");
|
||||
|
||||
let updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED);
|
||||
EventUtils.sendMouseEvent({ type: "click" }, getItemCheckboxNode(0), gDebugger);
|
||||
@ -43,7 +43,7 @@ function test() {
|
||||
testEventGroup("interactionEvents", false);
|
||||
testEventGroup("keyboardEvents", false);
|
||||
testEventGroup("mouseEvents", false);
|
||||
testEventArrays("keydown,click,change,keyup", "keydown");
|
||||
testEventArrays("change,click,keydown,keyup", "change");
|
||||
|
||||
let updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED);
|
||||
EventUtils.sendMouseEvent({ type: "click" }, getItemCheckboxNode(0), gDebugger);
|
||||
@ -56,7 +56,7 @@ function test() {
|
||||
testEventGroup("interactionEvents", false);
|
||||
testEventGroup("keyboardEvents", false);
|
||||
testEventGroup("mouseEvents", false);
|
||||
testEventArrays("keydown,click,change,keyup", "");
|
||||
testEventArrays("change,click,keydown,keyup", "");
|
||||
|
||||
yield ensureThreadClientState(aPanel, "resumed");
|
||||
yield closeDebuggerAndFinish(aPanel);
|
||||
|
@ -31,46 +31,46 @@ function test() {
|
||||
testEventGroup("interactionEvents", false);
|
||||
testEventGroup("keyboardEvents", false);
|
||||
testEventGroup("mouseEvents", false);
|
||||
testEventArrays("keydown,click,change,keyup", "");
|
||||
testEventArrays("change,click,keydown,keyup", "");
|
||||
|
||||
let updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED);
|
||||
EventUtils.sendMouseEvent({ type: "click" }, getGroupCheckboxNode("interactionEvents"), gDebugger);
|
||||
yield updated;
|
||||
|
||||
testEventItem(0, false);
|
||||
testEventItem(1, false);
|
||||
testEventItem(2, true);
|
||||
testEventItem(3, false);
|
||||
testEventGroup("interactionEvents", true);
|
||||
testEventGroup("keyboardEvents", false);
|
||||
testEventGroup("mouseEvents", false);
|
||||
testEventArrays("keydown,click,change,keyup", "change");
|
||||
|
||||
let updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED);
|
||||
EventUtils.sendMouseEvent({ type: "click" }, getGroupCheckboxNode("interactionEvents"), gDebugger);
|
||||
yield updated;
|
||||
|
||||
testEventItem(0, false);
|
||||
testEventItem(1, false);
|
||||
testEventItem(2, false);
|
||||
testEventItem(3, false);
|
||||
testEventGroup("interactionEvents", false);
|
||||
testEventGroup("keyboardEvents", false);
|
||||
testEventGroup("mouseEvents", false);
|
||||
testEventArrays("keydown,click,change,keyup", "");
|
||||
|
||||
let updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED);
|
||||
EventUtils.sendMouseEvent({ type: "click" }, getGroupCheckboxNode("keyboardEvents"), gDebugger);
|
||||
yield updated;
|
||||
|
||||
testEventItem(0, true);
|
||||
testEventItem(1, false);
|
||||
testEventItem(2, false);
|
||||
testEventItem(3, false);
|
||||
testEventGroup("interactionEvents", true);
|
||||
testEventGroup("keyboardEvents", false);
|
||||
testEventGroup("mouseEvents", false);
|
||||
testEventArrays("change,click,keydown,keyup", "change");
|
||||
|
||||
let updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED);
|
||||
EventUtils.sendMouseEvent({ type: "click" }, getGroupCheckboxNode("interactionEvents"), gDebugger);
|
||||
yield updated;
|
||||
|
||||
testEventItem(0, false);
|
||||
testEventItem(1, false);
|
||||
testEventItem(2, false);
|
||||
testEventItem(3, false);
|
||||
testEventGroup("interactionEvents", false);
|
||||
testEventGroup("keyboardEvents", false);
|
||||
testEventGroup("mouseEvents", false);
|
||||
testEventArrays("change,click,keydown,keyup", "");
|
||||
|
||||
let updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED);
|
||||
EventUtils.sendMouseEvent({ type: "click" }, getGroupCheckboxNode("keyboardEvents"), gDebugger);
|
||||
yield updated;
|
||||
|
||||
testEventItem(0, false);
|
||||
testEventItem(1, false);
|
||||
testEventItem(2, true);
|
||||
testEventItem(3, true);
|
||||
testEventGroup("interactionEvents", false);
|
||||
testEventGroup("keyboardEvents", true);
|
||||
testEventGroup("mouseEvents", false);
|
||||
testEventArrays("keydown,click,change,keyup", "keydown,keyup");
|
||||
testEventArrays("change,click,keydown,keyup", "keydown,keyup");
|
||||
|
||||
let updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED);
|
||||
EventUtils.sendMouseEvent({ type: "click" }, getGroupCheckboxNode("keyboardEvents"), gDebugger);
|
||||
@ -83,7 +83,7 @@ function test() {
|
||||
testEventGroup("interactionEvents", false);
|
||||
testEventGroup("keyboardEvents", false);
|
||||
testEventGroup("mouseEvents", false);
|
||||
testEventArrays("keydown,click,change,keyup", "");
|
||||
testEventArrays("change,click,keydown,keyup", "");
|
||||
|
||||
yield ensureThreadClientState(aPanel, "resumed");
|
||||
yield closeDebuggerAndFinish(aPanel);
|
||||
|
@ -30,7 +30,7 @@ function test() {
|
||||
testEventGroup("interactionEvents", false);
|
||||
testEventGroup("keyboardEvents", false);
|
||||
testEventGroup("mouseEvents", false);
|
||||
testEventArrays("keydown,click,change,keyup", "");
|
||||
testEventArrays("change,click,keydown,keyup", "");
|
||||
|
||||
let updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED);
|
||||
EventUtils.sendMouseEvent({ type: "click" }, getItemCheckboxNode(0), gDebugger);
|
||||
@ -45,7 +45,7 @@ function test() {
|
||||
testEventGroup("interactionEvents", false);
|
||||
testEventGroup("keyboardEvents", false);
|
||||
testEventGroup("mouseEvents", false);
|
||||
testEventArrays("keydown,click,change,keyup", "keydown,click,change");
|
||||
testEventArrays("change,click,keydown,keyup", "change,click,keydown");
|
||||
|
||||
yield reloadActiveTab(aPanel, gDebugger.EVENTS.EVENT_LISTENERS_FETCHED);
|
||||
|
||||
@ -56,7 +56,7 @@ function test() {
|
||||
testEventGroup("interactionEvents", false);
|
||||
testEventGroup("keyboardEvents", false);
|
||||
testEventGroup("mouseEvents", false);
|
||||
testEventArrays("keydown,click,change,keyup", "keydown,click,change");
|
||||
testEventArrays("change,click,keydown,keyup", "change,click,keydown");
|
||||
|
||||
let updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED);
|
||||
EventUtils.sendMouseEvent({ type: "click" }, getItemCheckboxNode(0), gDebugger);
|
||||
@ -71,7 +71,7 @@ function test() {
|
||||
testEventGroup("interactionEvents", false);
|
||||
testEventGroup("keyboardEvents", false);
|
||||
testEventGroup("mouseEvents", false);
|
||||
testEventArrays("keydown,click,change,keyup", "");
|
||||
testEventArrays("change,click,keydown,keyup", "");
|
||||
|
||||
yield reloadActiveTab(aPanel, gDebugger.EVENTS.EVENT_LISTENERS_FETCHED);
|
||||
|
||||
@ -82,7 +82,7 @@ function test() {
|
||||
testEventGroup("interactionEvents", false);
|
||||
testEventGroup("keyboardEvents", false);
|
||||
testEventGroup("mouseEvents", false);
|
||||
testEventArrays("keydown,click,change,keyup", "");
|
||||
testEventArrays("change,click,keydown,keyup", "");
|
||||
|
||||
yield ensureThreadClientState(aPanel, "resumed");
|
||||
yield closeDebuggerAndFinish(aPanel);
|
||||
|
@ -60,7 +60,13 @@ function test() {
|
||||
verify("foo = bar", e => e.name == "bar", [1, 6], [1, 9]);
|
||||
verify("\nfoo\n=\nbar\n", e => e.name == "bar", [4, 0], [4, 3]);
|
||||
|
||||
// LabeledStatement and ContinueStatement, because it's 1968 again
|
||||
// LabeledStatement, BreakStatement and ContinueStatement, because it's 1968 again
|
||||
|
||||
verify("foo: bar", e => e.name == "foo", [1, 0], [1, 3]);
|
||||
verify("\nfoo\n:\nbar\n", e => e.name == "foo", [2, 0], [2, 3]);
|
||||
|
||||
verify("foo: for(;;) break foo", e => e.name == "foo", [1, 19], [1, 22]);
|
||||
verify("\nfoo\n:\nfor(\n;\n;\n)\nbreak\nfoo\n", e => e.name == "foo", [9, 0], [9, 3]);
|
||||
|
||||
verify("foo: bar", e => e.name == "foo", [1, 0], [1, 3]);
|
||||
verify("\nfoo\n:\nbar\n", e => e.name == "foo", [2, 0], [2, 3]);
|
||||
|
@ -0,0 +1,40 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Hitting ESC to open the split console when paused on reload should not stop
|
||||
* the pending navigation.
|
||||
*/
|
||||
|
||||
function test() {
|
||||
Task.spawn(runTests);
|
||||
}
|
||||
|
||||
function* runTests() {
|
||||
const TAB_URL = EXAMPLE_URL + "doc_split-console-paused-reload.html";
|
||||
let [,, panel] = yield initDebugger(TAB_URL);
|
||||
let dbgWin = panel.panelWin;
|
||||
let frames = dbgWin.DebuggerView.StackFrames;
|
||||
let toolbox = gDevTools.getToolbox(panel.target);
|
||||
|
||||
yield panel.addBreakpoint({ url: TAB_URL, line: 16 });
|
||||
info("Breakpoint was set.");
|
||||
dbgWin.DebuggerController._target.activeTab.reload();
|
||||
info("Page reloaded.");
|
||||
yield waitForSourceAndCaretAndScopes(panel, ".html", 16);
|
||||
yield ensureThreadClientState(panel, "paused");
|
||||
info("Breakpoint was hit.");
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
frames.selectedItem.target,
|
||||
dbgWin);
|
||||
info("The breadcrumb received focus.");
|
||||
|
||||
// This is the meat of the test.
|
||||
let result = toolbox.once("webconsole-ready", () => {
|
||||
ok(toolbox.splitConsole, "Split console is shown.");
|
||||
is(dbgWin.gThreadClient.state, "paused", "Execution is still paused.");
|
||||
});
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {}, dbgWin);
|
||||
yield result;
|
||||
yield resumeDebuggerThenCloseAndFinish(panel);
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Test page for opening a split-console when execution is paused</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
function runDebuggerStatement() {
|
||||
debugger;
|
||||
}
|
||||
window.foobar = 1;
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -294,6 +294,12 @@ Toolbox.prototype = {
|
||||
let responsiveModeActive = this._isResponsiveModeActive();
|
||||
if (e.keyCode === e.DOM_VK_ESCAPE && !responsiveModeActive) {
|
||||
this.toggleSplitConsole();
|
||||
// If the debugger is paused, don't let the ESC key stop any pending
|
||||
// navigation.
|
||||
let jsdebugger = this.getPanel("jsdebugger");
|
||||
if (jsdebugger && jsdebugger.panelWin.gThreadClient.state == "paused") {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -450,8 +450,8 @@ let ParserHelpers = {
|
||||
loc.end.column = loc.start.column + aNode.name.length;
|
||||
return loc;
|
||||
}
|
||||
if (parentType == "ContinueStatement") {
|
||||
// e.g. continue label
|
||||
if (parentType == "ContinueStatement" || parentType == "BreakStatement") {
|
||||
// e.g. continue label; or break label;
|
||||
// The location is unavailable for the identifier node "label".
|
||||
let loc = Cu.cloneInto(parentLocation, {});
|
||||
loc.start.line = loc.end.line;
|
||||
|
@ -39,8 +39,8 @@ let testData = [
|
||||
["VK_ESCAPE", {}, null, -1, 0]
|
||||
];
|
||||
|
||||
let TEST_URL = "data:text/html,<h1 style='border: 1px solid red'>Filename:"+
|
||||
" browser_bug894376_css_value_completion_new_property_value_pair.js</h1>";
|
||||
let TEST_URL = "data:text/html,<style>h1{border: 1px solid red}</style>" +
|
||||
"<h1>Test element</h1>";
|
||||
|
||||
let test = asyncTest(function*() {
|
||||
yield addTab(TEST_URL);
|
||||
@ -50,7 +50,7 @@ let test = asyncTest(function*() {
|
||||
yield selectNode("h1", inspector);
|
||||
|
||||
info("Focusing a new css property editable property");
|
||||
let brace = view.doc.querySelectorAll(".ruleview-ruleclose")[0];
|
||||
let brace = view.doc.querySelectorAll(".ruleview-ruleclose")[1];
|
||||
let editor = yield focusEditableField(brace);
|
||||
|
||||
info("Starting to test for css property completion");
|
||||
@ -70,7 +70,7 @@ function* testCompletion([key, modifiers, completion, index, total], editor, vie
|
||||
|
||||
if (/tab/ig.test(key)) {
|
||||
info("Waiting for the new property or value editor to get focused");
|
||||
let brace = view.doc.querySelector(".ruleview-ruleclose");
|
||||
let brace = view.doc.querySelectorAll(".ruleview-ruleclose")[1];
|
||||
onKeyPress = once(brace.parentNode, "focus", true);
|
||||
} else if (/(right|back_space|escape|return)/ig.test(key) ||
|
||||
(modifiers.accelKey || modifiers.ctrlKey)) {
|
||||
|
@ -1,5 +1,4 @@
|
||||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
subsuite = devtools
|
||||
support-files =
|
||||
doc_simple-context.html
|
||||
|
@ -608,13 +608,10 @@
|
||||
#resume {
|
||||
list-style-image: url(debugger-pause.png);
|
||||
-moz-image-region: rect(0px,16px,16px,0px);
|
||||
transition: background 0.15s ease-in-out;
|
||||
}
|
||||
|
||||
#resume[checked] {
|
||||
background: none;
|
||||
list-style-image: url(debugger-play.png);
|
||||
-moz-image-region: rect(0px,32px,16px,16px);
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
|
@ -56,6 +56,7 @@
|
||||
border-radius: 0;
|
||||
margin: 2px 3px;
|
||||
color: inherit;
|
||||
transition: background 0.05s ease-in-out;
|
||||
}
|
||||
|
||||
.devtools-menulist:-moz-focusring,
|
||||
@ -176,24 +177,32 @@
|
||||
}
|
||||
|
||||
/* Menu type buttons and checked states */
|
||||
.theme-dark .devtools-menulist[open=true],
|
||||
.theme-dark .devtools-toolbarbutton[open=true],
|
||||
.theme-dark .devtools-toolbarbutton[open=true]:hover,
|
||||
.theme-dark .devtools-toolbarbutton[open=true]:hover:active,
|
||||
.theme-dark .devtools-toolbarbutton[checked=true],
|
||||
.theme-dark .devtools-toolbarbutton[checked=true]:hover,
|
||||
.theme-dark #toolbox-buttons .devtools-toolbarbutton[text-as-image][checked] {
|
||||
background: rgba(29, 79, 115, .7); /* Select highlight blue */
|
||||
color: #f5f7fa;
|
||||
}
|
||||
|
||||
.theme-light .devtools-toolbarbutton[checked=true],
|
||||
.theme-light #toolbox-buttons .devtools-toolbarbutton[text-as-image][checked] {
|
||||
background: rgba(76, 158, 217, .2); /* Select highlight blue */
|
||||
}
|
||||
|
||||
.theme-dark .devtools-menulist[open=true],
|
||||
.theme-dark .devtools-toolbarbutton[open=true],
|
||||
.theme-dark .devtools-toolbarbutton[open=true]:hover,
|
||||
.theme-dark .devtools-toolbarbutton[open=true]:hover:active,
|
||||
.theme-dark .devtools-toolbarbutton[checked=true]:hover {
|
||||
background: rgba(29, 79, 115, .8); /* Select highlight blue */
|
||||
color: #f5f7fa;
|
||||
}
|
||||
|
||||
.theme-light .devtools-menulist[open=true],
|
||||
.theme-light .devtools-toolbarbutton[open=true],
|
||||
.theme-light .devtools-toolbarbutton[open=true]:hover,
|
||||
.theme-light .devtools-toolbarbutton[open=true]:hover:active,
|
||||
.theme-light .devtools-toolbarbutton[checked=true],
|
||||
.theme-light .devtools-toolbarbutton[checked=true]:hover,
|
||||
.theme-light #toolbox-buttons .devtools-toolbarbutton[text-as-image][checked] {
|
||||
background: rgba(76, 158, 217, .2); /* Select highlight blue */
|
||||
.theme-light .devtools-toolbarbutton[checked=true]:hover {
|
||||
background: rgba(76, 158, 217, .4); /* Select highlight blue */
|
||||
}
|
||||
|
||||
.devtools-option-toolbarbutton {
|
||||
@ -827,7 +836,6 @@
|
||||
.theme-light .command-button-invertable[checked=true]:not(:active) > image,
|
||||
.theme-light .devtools-tab[icon-invertable][selected] > image,
|
||||
.theme-light .devtools-tab[icon-invertable][highlighted] > image,
|
||||
.theme-light #resume[checked] > image,
|
||||
.theme-light #record-snapshot[checked] > image,
|
||||
.theme-light #profiler-start[checked] > image {
|
||||
filter: none !important;
|
||||
|
@ -381,11 +381,14 @@ case "$target" in
|
||||
AC_SUBST(ANDROID_MEDIAROUTER_RES)
|
||||
fi
|
||||
|
||||
MOZ_PATH_PROG(ZIPALIGN, zipalign, :, [$ANDROID_TOOLS])
|
||||
MOZ_PATH_PROG(DX, dx, :, [$ANDROID_BUILD_TOOLS])
|
||||
MOZ_PATH_PROG(AAPT, aapt, :, [$ANDROID_BUILD_TOOLS])
|
||||
MOZ_PATH_PROG(AIDL, aidl, :, [$ANDROID_BUILD_TOOLS])
|
||||
MOZ_PATH_PROG(ADB, adb, :, [$ANDROID_PLATFORM_TOOLS])
|
||||
dnl Google has a history of moving the Android tools around. We don't
|
||||
dnl care where they are, so let's try to find them anywhere we can.
|
||||
ALL_ANDROID_TOOLS_PATHS="$ANDROID_TOOLS:$ANDROID_BUILD_TOOLS:$ANDROID_PLATFORM_TOOLS"
|
||||
MOZ_PATH_PROG(ZIPALIGN, zipalign, :, [$ALL_ANDROID_TOOLS_PATHS])
|
||||
MOZ_PATH_PROG(DX, dx, :, [$ALL_ANDROID_TOOLS_PATHS])
|
||||
MOZ_PATH_PROG(AAPT, aapt, :, [$ALL_ANDROID_TOOLS_PATHS])
|
||||
MOZ_PATH_PROG(AIDL, aidl, :, [$ALL_ANDROID_TOOLS_PATHS])
|
||||
MOZ_PATH_PROG(ADB, adb, :, [$ALL_ANDROID_TOOLS_PATHS])
|
||||
|
||||
if test -z "$ZIPALIGN" -o "$ZIPALIGN" = ":"; then
|
||||
AC_MSG_ERROR([The program zipalign was not found. Use --with-android-sdk={android-sdk-dir}.])
|
||||
|
@ -9,10 +9,12 @@ import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.GeckoEvent;
|
||||
import org.mozilla.gecko.mozglue.RobocopTarget;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
@ -21,6 +23,10 @@ public class ReferrerReceiver extends BroadcastReceiver {
|
||||
|
||||
private static final String ACTION_INSTALL_REFERRER = "com.android.vending.INSTALL_REFERRER";
|
||||
|
||||
// Sent when we're done.
|
||||
@RobocopTarget
|
||||
public static final String ACTION_REFERRER_RECEIVED = "org.mozilla.fennec.REFERRER_RECEIVED";
|
||||
|
||||
/**
|
||||
* If the install intent has this source, we'll track the campaign ID.
|
||||
*/
|
||||
@ -52,6 +58,10 @@ public class ReferrerReceiver extends BroadcastReceiver {
|
||||
if (TextUtils.equals(referrer.source, MOZILLA_UTM_SOURCE)) {
|
||||
propagateMozillaCampaign(referrer);
|
||||
}
|
||||
|
||||
// Broadcast a secondary, local intent to allow test code to respond.
|
||||
final Intent receivedIntent = new Intent(ACTION_REFERRER_RECEIVED);
|
||||
LocalBroadcastManager.getInstance(context).sendBroadcast(receivedIntent);
|
||||
}
|
||||
|
||||
|
||||
|
@ -17,13 +17,17 @@ import org.mozilla.gecko.AppConstants;
|
||||
import org.mozilla.gecko.db.BrowserContract;
|
||||
import org.mozilla.gecko.distribution.Distribution;
|
||||
import org.mozilla.gecko.distribution.ReferrerDescriptor;
|
||||
import org.mozilla.gecko.distribution.ReferrerReceiver;
|
||||
import org.mozilla.gecko.mozglue.RobocopTarget;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
@ -139,41 +143,65 @@ public class testDistribution extends ContentProviderTest {
|
||||
doTestInvalidReferrerIntent();
|
||||
}
|
||||
|
||||
private void doReferrerTest(String ref, final TestableDistribution distribution, final Runnable distributionReady) throws InterruptedException {
|
||||
final Intent intent = new Intent(ACTION_INSTALL_REFERRER);
|
||||
intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, CLASS_REFERRER_RECEIVER);
|
||||
intent.putExtra("referrer", ref);
|
||||
|
||||
final BroadcastReceiver receiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.i(LOGTAG, "Test received " + intent.getAction());
|
||||
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
distribution.addOnDistributionReadyCallback(distributionReady);
|
||||
distribution.go();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
IntentFilter intentFilter = new IntentFilter(ReferrerReceiver.ACTION_REFERRER_RECEIVED);
|
||||
final LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(mActivity);
|
||||
localBroadcastManager.registerReceiver(receiver, intentFilter);
|
||||
|
||||
Log.i(LOGTAG, "Broadcasting referrer intent.");
|
||||
try {
|
||||
mActivity.sendBroadcast(intent, null);
|
||||
synchronized (distribution) {
|
||||
distribution.wait(WAIT_TIMEOUT_MSEC);
|
||||
}
|
||||
} finally {
|
||||
localBroadcastManager.unregisterReceiver(receiver);
|
||||
}
|
||||
}
|
||||
|
||||
public void doTestValidReferrerIntent() throws Exception {
|
||||
// Send the faux-download intent.
|
||||
// Equivalent to
|
||||
// am broadcast -a com.android.vending.INSTALL_REFERRER \
|
||||
// -n org.mozilla.fennec/org.mozilla.gecko.distribution.ReferrerReceiver \
|
||||
// --es "referrer" "utm_source=mozilla&utm_medium=testmedium&utm_term=testterm&utm_content=testcontent&utm_campaign=distribution"
|
||||
final String ref = "utm_source=mozilla&utm_medium=testmedium&utm_term=testterm&utm_content=testcontent&utm_campaign=distribution";
|
||||
final Intent intent = new Intent(ACTION_INSTALL_REFERRER);
|
||||
intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, CLASS_REFERRER_RECEIVER);
|
||||
intent.putExtra("referrer", ref);
|
||||
mActivity.sendBroadcast(intent);
|
||||
|
||||
// Wait for the intent to be processed.
|
||||
final TestableDistribution distribution = new TestableDistribution(mActivity);
|
||||
|
||||
final Object wait = new Object();
|
||||
distribution.addOnDistributionReadyCallback(new Runnable() {
|
||||
final Runnable distributionReady = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.i(LOGTAG, "Test told distribution is ready.");
|
||||
mAsserter.ok(!distribution.exists(), "Not processed.", "No download because we're offline.");
|
||||
ReferrerDescriptor referrerValue = TestableDistribution.getReferrerDescriptorForTesting();
|
||||
mAsserter.dumpLog("Referrer was " + referrerValue);
|
||||
mAsserter.is(referrerValue.content, "testcontent", "Referrer content");
|
||||
mAsserter.is(referrerValue.medium, "testmedium", "Referrer medium");
|
||||
mAsserter.is(referrerValue.campaign, "distribution", "Referrer campaign");
|
||||
synchronized (wait) {
|
||||
wait.notifyAll();
|
||||
synchronized (distribution) {
|
||||
distribution.notifyAll();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
distribution.go();
|
||||
synchronized (wait) {
|
||||
wait.wait(WAIT_TIMEOUT_MSEC);
|
||||
}
|
||||
doReferrerTest(ref, distribution, distributionReady);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -182,37 +210,25 @@ public class testDistribution extends ContentProviderTest {
|
||||
* even if we *do* include it in a Campaign:Set message.
|
||||
*/
|
||||
public void doTestInvalidReferrerIntent() throws Exception {
|
||||
// Send the faux-download intent.
|
||||
// Equivalent to
|
||||
// am broadcast -a com.android.vending.INSTALL_REFERRER \
|
||||
// -n org.mozilla.fennec/org.mozilla.gecko.distribution.ReferrerReceiver \
|
||||
// --es "referrer" "utm_source=mozilla&utm_medium=testmedium&utm_term=testterm&utm_content=testcontent&utm_campaign=testname"
|
||||
final String ref = "utm_source=mozilla&utm_medium=testmedium&utm_term=testterm&utm_content=testcontent&utm_campaign=testname";
|
||||
final Intent intent = new Intent(ACTION_INSTALL_REFERRER);
|
||||
intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, CLASS_REFERRER_RECEIVER);
|
||||
intent.putExtra("referrer", ref);
|
||||
mActivity.sendBroadcast(intent);
|
||||
|
||||
// Wait for the intent to be processed.
|
||||
final TestableDistribution distribution = new TestableDistribution(mActivity);
|
||||
|
||||
final Object wait = new Object();
|
||||
distribution.addOnDistributionReadyCallback(new Runnable() {
|
||||
final Runnable distributionReady = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mAsserter.ok(!distribution.exists(), "Not processed.", "No download because campaign was wrong.");
|
||||
ReferrerDescriptor referrerValue = TestableDistribution.getReferrerDescriptorForTesting();
|
||||
mAsserter.is(referrerValue, null, "No referrer.");
|
||||
synchronized (wait) {
|
||||
wait.notifyAll();
|
||||
synchronized (distribution) {
|
||||
distribution.notifyAll();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
distribution.go();
|
||||
synchronized (wait) {
|
||||
wait.wait(WAIT_TIMEOUT_MSEC);
|
||||
}
|
||||
doReferrerTest(ref, distribution, distributionReady);
|
||||
}
|
||||
|
||||
// Initialize the distribution from the mock package.
|
||||
|
@ -154,10 +154,16 @@ public final class ThreadUtils {
|
||||
return;
|
||||
}
|
||||
|
||||
final String message = "Expected thread " +
|
||||
expectedThreadId + " (\"" + expectedThread.getName() +
|
||||
"\"), but running on thread " +
|
||||
currentThreadId + " (\"" + currentThread.getName() + ")";
|
||||
final String message;
|
||||
if (expected) {
|
||||
message = "Expected thread " + expectedThreadId +
|
||||
" (\"" + expectedThread.getName() + "\"), but running on thread " +
|
||||
currentThreadId + " (\"" + currentThread.getName() + "\")";
|
||||
} else {
|
||||
message = "Expected anything but " + expectedThreadId +
|
||||
" (\"" + expectedThread.getName() + "\"), but running there.";
|
||||
}
|
||||
|
||||
final IllegalThreadStateException e = new IllegalThreadStateException(message);
|
||||
|
||||
switch (behavior) {
|
||||
|
@ -196,6 +196,12 @@ public class GeckoSwipeRefreshLayout extends ViewGroup {
|
||||
super.onAttachedToWindow();
|
||||
removeCallbacks(mCancel);
|
||||
removeCallbacks(mReturnToStartPosition);
|
||||
|
||||
// Sometimes the inner view doesn't get a proper layout
|
||||
// pass when re-attached to the view tree (see bug 1010986).
|
||||
if (getChildCount() > 0) {
|
||||
getChildAt(0).forceLayout();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -153,7 +153,11 @@ EventEmitter.prototype = {
|
||||
if (!isWorker) {
|
||||
caller = components.stack.caller.caller;
|
||||
func = caller.name;
|
||||
path = caller.filename.split(/ -> /)[1] + ":" + caller.lineNumber;
|
||||
let file = caller.filename;
|
||||
if (file.contains(" -> ")) {
|
||||
file = caller.filename.split(/ -> /)[1];
|
||||
}
|
||||
path = file + ":" + caller.lineNumber;
|
||||
}
|
||||
|
||||
let argOut = "(";
|
||||
|
Loading…
Reference in New Issue
Block a user