|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 function sendNotifyRequest(name) { |
|
6 let ns = {}; |
|
7 Components.utils.import("resource://gre/modules/services/datareporting/policy.jsm", ns); |
|
8 Components.utils.import("resource://gre/modules/Preferences.jsm", ns); |
|
9 |
|
10 let service = Components.classes["@mozilla.org/datareporting/service;1"] |
|
11 .getService(Components.interfaces.nsISupports) |
|
12 .wrappedJSObject; |
|
13 ok(service.healthReporter, "Health Reporter instance is available."); |
|
14 |
|
15 let policyPrefs = new ns.Preferences("testing." + name + "."); |
|
16 ok(service._prefs, "Health Reporter prefs are available."); |
|
17 let hrPrefs = service._prefs; |
|
18 |
|
19 let policy = new ns.DataReportingPolicy(policyPrefs, hrPrefs, service); |
|
20 policy.firstRunDate = new Date(Date.now() - 24 * 60 * 60 * 1000); |
|
21 |
|
22 is(policy.notifyState, policy.STATE_NOTIFY_UNNOTIFIED, "Policy is in unnotified state."); |
|
23 |
|
24 service.healthReporter.onInit().then(function onInit() { |
|
25 is(policy.ensureNotifyResponse(new Date()), false, "User has not responded to policy."); |
|
26 }); |
|
27 |
|
28 return policy; |
|
29 } |
|
30 |
|
31 /** |
|
32 * Wait for a <notification> to be closed then call the specified callback. |
|
33 */ |
|
34 function waitForNotificationClose(notification, cb) { |
|
35 let parent = notification.parentNode; |
|
36 |
|
37 let observer = new MutationObserver(function onMutatations(mutations) { |
|
38 for (let mutation of mutations) { |
|
39 for (let i = 0; i < mutation.removedNodes.length; i++) { |
|
40 let node = mutation.removedNodes.item(i); |
|
41 |
|
42 if (node != notification) { |
|
43 continue; |
|
44 } |
|
45 |
|
46 observer.disconnect(); |
|
47 cb(); |
|
48 } |
|
49 } |
|
50 }); |
|
51 |
|
52 observer.observe(parent, {childList: true}); |
|
53 } |
|
54 |
|
55 let dumpAppender, rootLogger; |
|
56 |
|
57 function test() { |
|
58 waitForExplicitFinish(); |
|
59 |
|
60 let ns = {}; |
|
61 Components.utils.import("resource://gre/modules/Log.jsm", ns); |
|
62 rootLogger = ns.Log.repository.rootLogger; |
|
63 dumpAppender = new ns.Log.DumpAppender(); |
|
64 dumpAppender.level = ns.Log.Level.All; |
|
65 rootLogger.addAppender(dumpAppender); |
|
66 |
|
67 let notification = document.getElementById("global-notificationbox"); |
|
68 let policy; |
|
69 |
|
70 notification.addEventListener("AlertActive", function active() { |
|
71 notification.removeEventListener("AlertActive", active, true); |
|
72 |
|
73 executeSoon(function afterNotification() { |
|
74 is(policy.notifyState, policy.STATE_NOTIFY_WAIT, "Policy is waiting for user response."); |
|
75 ok(!policy.dataSubmissionPolicyAccepted, "Data submission policy not yet accepted."); |
|
76 |
|
77 waitForNotificationClose(notification.currentNotification, function onClose() { |
|
78 is(policy.notifyState, policy.STATE_NOTIFY_COMPLETE, "Closing info bar completes user notification."); |
|
79 ok(policy.dataSubmissionPolicyAccepted, "Data submission policy accepted."); |
|
80 is(policy.dataSubmissionPolicyResponseType, "accepted-info-bar-dismissed", |
|
81 "Reason for acceptance was info bar dismissal."); |
|
82 is(notification.allNotifications.length, 0, "No notifications remain."); |
|
83 test_multiple_windows(); |
|
84 }); |
|
85 notification.currentNotification.close(); |
|
86 }); |
|
87 }, true); |
|
88 |
|
89 policy = sendNotifyRequest("single_window_notified"); |
|
90 } |
|
91 |
|
92 function test_multiple_windows() { |
|
93 // Ensure we see the notification on all windows and that action on one window |
|
94 // results in dismiss on every window. |
|
95 let window2 = OpenBrowserWindow(); |
|
96 whenDelayedStartupFinished(window2, function onWindow() { |
|
97 let notification1 = document.getElementById("global-notificationbox"); |
|
98 let notification2 = window2.document.getElementById("global-notificationbox"); |
|
99 ok(notification2, "2nd window has a global notification box."); |
|
100 |
|
101 let policy; |
|
102 |
|
103 let displayCount = 0; |
|
104 let prefPaneClosed = false; |
|
105 let childWindowClosed = false; |
|
106 |
|
107 function onAlertDisplayed() { |
|
108 displayCount++; |
|
109 |
|
110 if (displayCount != 2) { |
|
111 return; |
|
112 } |
|
113 |
|
114 ok(true, "Data reporting info bar displayed on all open windows."); |
|
115 |
|
116 // We register two independent observers and we need both to clean up |
|
117 // properly. This handles gating for test completion. |
|
118 function maybeFinish() { |
|
119 if (!prefPaneClosed) { |
|
120 dump("Not finishing test yet because pref pane isn't closed.\n"); |
|
121 return; |
|
122 } |
|
123 |
|
124 if (!childWindowClosed) { |
|
125 dump("Not finishing test yet because child window isn't closed.\n"); |
|
126 return; |
|
127 } |
|
128 |
|
129 dump("Finishing multiple window test.\n"); |
|
130 rootLogger.removeAppender(dumpAppender); |
|
131 delete dumpAppender; |
|
132 delete rootLogger; |
|
133 finish(); |
|
134 } |
|
135 |
|
136 let closeCount = 0; |
|
137 function onAlertClose() { |
|
138 closeCount++; |
|
139 |
|
140 if (closeCount != 2) { |
|
141 return; |
|
142 } |
|
143 |
|
144 ok(true, "Closing info bar on one window closed them on all."); |
|
145 |
|
146 is(policy.notifyState, policy.STATE_NOTIFY_COMPLETE, |
|
147 "Closing info bar with multiple windows completes notification."); |
|
148 ok(policy.dataSubmissionPolicyAccepted, "Data submission policy accepted."); |
|
149 is(policy.dataSubmissionPolicyResponseType, "accepted-info-bar-button-pressed", |
|
150 "Policy records reason for acceptance was button press."); |
|
151 is(notification1.allNotifications.length, 0, "No notifications remain on main window."); |
|
152 is(notification2.allNotifications.length, 0, "No notifications remain on 2nd window."); |
|
153 |
|
154 window2.close(); |
|
155 childWindowClosed = true; |
|
156 maybeFinish(); |
|
157 } |
|
158 |
|
159 waitForNotificationClose(notification1.currentNotification, onAlertClose); |
|
160 waitForNotificationClose(notification2.currentNotification, onAlertClose); |
|
161 |
|
162 // While we're here, we dual purpose this test to check that pressing the |
|
163 // button does the right thing. |
|
164 let buttons = notification2.currentNotification.getElementsByTagName("button"); |
|
165 is(buttons.length, 1, "There is 1 button in the data reporting notification."); |
|
166 let button = buttons[0]; |
|
167 |
|
168 // Automatically close preferences window when it is opened as part of |
|
169 // button press. |
|
170 Services.obs.addObserver(function observer(prefWin, topic, data) { |
|
171 Services.obs.removeObserver(observer, "advanced-pane-loaded"); |
|
172 |
|
173 ok(true, "Pref pane opened on info bar button press."); |
|
174 executeSoon(function soon() { |
|
175 dump("Closing pref pane.\n"); |
|
176 prefWin.close(); |
|
177 prefPaneClosed = true; |
|
178 maybeFinish(); |
|
179 }); |
|
180 }, "advanced-pane-loaded", false); |
|
181 |
|
182 button.click(); |
|
183 } |
|
184 |
|
185 notification1.addEventListener("AlertActive", function active1() { |
|
186 notification1.removeEventListener("AlertActive", active1, true); |
|
187 executeSoon(onAlertDisplayed); |
|
188 }, true); |
|
189 |
|
190 notification2.addEventListener("AlertActive", function active2() { |
|
191 notification2.removeEventListener("AlertActive", active2, true); |
|
192 executeSoon(onAlertDisplayed); |
|
193 }, true); |
|
194 |
|
195 policy = sendNotifyRequest("multiple_window_behavior"); |
|
196 }); |
|
197 } |
|
198 |