michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: function sendNotifyRequest(name) { michael@0: let ns = {}; michael@0: Components.utils.import("resource://gre/modules/services/datareporting/policy.jsm", ns); michael@0: Components.utils.import("resource://gre/modules/Preferences.jsm", ns); michael@0: michael@0: let service = Components.classes["@mozilla.org/datareporting/service;1"] michael@0: .getService(Components.interfaces.nsISupports) michael@0: .wrappedJSObject; michael@0: ok(service.healthReporter, "Health Reporter instance is available."); michael@0: michael@0: let policyPrefs = new ns.Preferences("testing." + name + "."); michael@0: ok(service._prefs, "Health Reporter prefs are available."); michael@0: let hrPrefs = service._prefs; michael@0: michael@0: let policy = new ns.DataReportingPolicy(policyPrefs, hrPrefs, service); michael@0: policy.firstRunDate = new Date(Date.now() - 24 * 60 * 60 * 1000); michael@0: michael@0: is(policy.notifyState, policy.STATE_NOTIFY_UNNOTIFIED, "Policy is in unnotified state."); michael@0: michael@0: service.healthReporter.onInit().then(function onInit() { michael@0: is(policy.ensureNotifyResponse(new Date()), false, "User has not responded to policy."); michael@0: }); michael@0: michael@0: return policy; michael@0: } michael@0: michael@0: /** michael@0: * Wait for a to be closed then call the specified callback. michael@0: */ michael@0: function waitForNotificationClose(notification, cb) { michael@0: let parent = notification.parentNode; michael@0: michael@0: let observer = new MutationObserver(function onMutatations(mutations) { michael@0: for (let mutation of mutations) { michael@0: for (let i = 0; i < mutation.removedNodes.length; i++) { michael@0: let node = mutation.removedNodes.item(i); michael@0: michael@0: if (node != notification) { michael@0: continue; michael@0: } michael@0: michael@0: observer.disconnect(); michael@0: cb(); michael@0: } michael@0: } michael@0: }); michael@0: michael@0: observer.observe(parent, {childList: true}); michael@0: } michael@0: michael@0: let dumpAppender, rootLogger; michael@0: michael@0: function test() { michael@0: waitForExplicitFinish(); michael@0: michael@0: let ns = {}; michael@0: Components.utils.import("resource://gre/modules/Log.jsm", ns); michael@0: rootLogger = ns.Log.repository.rootLogger; michael@0: dumpAppender = new ns.Log.DumpAppender(); michael@0: dumpAppender.level = ns.Log.Level.All; michael@0: rootLogger.addAppender(dumpAppender); michael@0: michael@0: let notification = document.getElementById("global-notificationbox"); michael@0: let policy; michael@0: michael@0: notification.addEventListener("AlertActive", function active() { michael@0: notification.removeEventListener("AlertActive", active, true); michael@0: michael@0: executeSoon(function afterNotification() { michael@0: is(policy.notifyState, policy.STATE_NOTIFY_WAIT, "Policy is waiting for user response."); michael@0: ok(!policy.dataSubmissionPolicyAccepted, "Data submission policy not yet accepted."); michael@0: michael@0: waitForNotificationClose(notification.currentNotification, function onClose() { michael@0: is(policy.notifyState, policy.STATE_NOTIFY_COMPLETE, "Closing info bar completes user notification."); michael@0: ok(policy.dataSubmissionPolicyAccepted, "Data submission policy accepted."); michael@0: is(policy.dataSubmissionPolicyResponseType, "accepted-info-bar-dismissed", michael@0: "Reason for acceptance was info bar dismissal."); michael@0: is(notification.allNotifications.length, 0, "No notifications remain."); michael@0: test_multiple_windows(); michael@0: }); michael@0: notification.currentNotification.close(); michael@0: }); michael@0: }, true); michael@0: michael@0: policy = sendNotifyRequest("single_window_notified"); michael@0: } michael@0: michael@0: function test_multiple_windows() { michael@0: // Ensure we see the notification on all windows and that action on one window michael@0: // results in dismiss on every window. michael@0: let window2 = OpenBrowserWindow(); michael@0: whenDelayedStartupFinished(window2, function onWindow() { michael@0: let notification1 = document.getElementById("global-notificationbox"); michael@0: let notification2 = window2.document.getElementById("global-notificationbox"); michael@0: ok(notification2, "2nd window has a global notification box."); michael@0: michael@0: let policy; michael@0: michael@0: let displayCount = 0; michael@0: let prefPaneClosed = false; michael@0: let childWindowClosed = false; michael@0: michael@0: function onAlertDisplayed() { michael@0: displayCount++; michael@0: michael@0: if (displayCount != 2) { michael@0: return; michael@0: } michael@0: michael@0: ok(true, "Data reporting info bar displayed on all open windows."); michael@0: michael@0: // We register two independent observers and we need both to clean up michael@0: // properly. This handles gating for test completion. michael@0: function maybeFinish() { michael@0: if (!prefPaneClosed) { michael@0: dump("Not finishing test yet because pref pane isn't closed.\n"); michael@0: return; michael@0: } michael@0: michael@0: if (!childWindowClosed) { michael@0: dump("Not finishing test yet because child window isn't closed.\n"); michael@0: return; michael@0: } michael@0: michael@0: dump("Finishing multiple window test.\n"); michael@0: rootLogger.removeAppender(dumpAppender); michael@0: delete dumpAppender; michael@0: delete rootLogger; michael@0: finish(); michael@0: } michael@0: michael@0: let closeCount = 0; michael@0: function onAlertClose() { michael@0: closeCount++; michael@0: michael@0: if (closeCount != 2) { michael@0: return; michael@0: } michael@0: michael@0: ok(true, "Closing info bar on one window closed them on all."); michael@0: michael@0: is(policy.notifyState, policy.STATE_NOTIFY_COMPLETE, michael@0: "Closing info bar with multiple windows completes notification."); michael@0: ok(policy.dataSubmissionPolicyAccepted, "Data submission policy accepted."); michael@0: is(policy.dataSubmissionPolicyResponseType, "accepted-info-bar-button-pressed", michael@0: "Policy records reason for acceptance was button press."); michael@0: is(notification1.allNotifications.length, 0, "No notifications remain on main window."); michael@0: is(notification2.allNotifications.length, 0, "No notifications remain on 2nd window."); michael@0: michael@0: window2.close(); michael@0: childWindowClosed = true; michael@0: maybeFinish(); michael@0: } michael@0: michael@0: waitForNotificationClose(notification1.currentNotification, onAlertClose); michael@0: waitForNotificationClose(notification2.currentNotification, onAlertClose); michael@0: michael@0: // While we're here, we dual purpose this test to check that pressing the michael@0: // button does the right thing. michael@0: let buttons = notification2.currentNotification.getElementsByTagName("button"); michael@0: is(buttons.length, 1, "There is 1 button in the data reporting notification."); michael@0: let button = buttons[0]; michael@0: michael@0: // Automatically close preferences window when it is opened as part of michael@0: // button press. michael@0: Services.obs.addObserver(function observer(prefWin, topic, data) { michael@0: Services.obs.removeObserver(observer, "advanced-pane-loaded"); michael@0: michael@0: ok(true, "Pref pane opened on info bar button press."); michael@0: executeSoon(function soon() { michael@0: dump("Closing pref pane.\n"); michael@0: prefWin.close(); michael@0: prefPaneClosed = true; michael@0: maybeFinish(); michael@0: }); michael@0: }, "advanced-pane-loaded", false); michael@0: michael@0: button.click(); michael@0: } michael@0: michael@0: notification1.addEventListener("AlertActive", function active1() { michael@0: notification1.removeEventListener("AlertActive", active1, true); michael@0: executeSoon(onAlertDisplayed); michael@0: }, true); michael@0: michael@0: notification2.addEventListener("AlertActive", function active2() { michael@0: notification2.removeEventListener("AlertActive", active2, true); michael@0: executeSoon(onAlertDisplayed); michael@0: }, true); michael@0: michael@0: policy = sendNotifyRequest("multiple_window_behavior"); michael@0: }); michael@0: } michael@0: