|
1 /* Any copyright is dedicated to the Public Domain. |
|
2 * http://creativecommons.org/publicdomain/zero/1.0/ |
|
3 */ |
|
4 |
|
5 // Tests the selection part of the post-app-update dialog |
|
6 |
|
7 var gProvider; |
|
8 var gWin; |
|
9 |
|
10 const PROFILE = AddonManager.SCOPE_PROFILE; |
|
11 const USER = AddonManager.SCOPE_USER; |
|
12 const APP = AddonManager.SCOPE_APPLICATION; |
|
13 const SYSTEM = AddonManager.SCOPE_SYSTEM; |
|
14 const DIST = -1; |
|
15 |
|
16 // The matrix of testcases for the selection part of the UI |
|
17 // Note that the isActive flag has the value it had when the previous version |
|
18 // of the application ran with this add-on. |
|
19 var ADDONS = [ |
|
20 //userDisabled wasAppDisabled isAppDisabled isActive hasUpdate autoUpdate scope defaultKeep position keepString disableString |
|
21 [false, true, false, false, false, true, PROFILE, true, 42, "enabled", ""], // 0 |
|
22 [false, true, false, false, true, true, PROFILE, true, 43, "enabled", ""], // 1 |
|
23 [false, true, false, false, true, false, PROFILE, true, 52, "unneededupdate", ""], // 2 |
|
24 [false, false, false, true, false, true, PROFILE, true, 53, "", "disabled"], // 3 |
|
25 [false, false, false, true, true, true, PROFILE, true, 54, "", "disabled"], // 4 |
|
26 [false, false, false, true, true, false, PROFILE, true, 55, "unneededupdate", "disabled"], // 5 |
|
27 [false, true, true, false, false, true, PROFILE, true, 56, "incompatible", ""], // 6 |
|
28 [false, true, true, false, true, true, PROFILE, true, 57, "autoupdate", ""], // 7 |
|
29 [false, true, true, false, true, false, PROFILE, true, 58, "neededupdate", ""], // 8 |
|
30 [false, false, true, true, false, true, PROFILE, true, 59, "incompatible", "disabled"], // 9 |
|
31 [false, true, true, true, true, true, PROFILE, true, 44, "autoupdate", "disabled"], // 10 |
|
32 [false, true, true, true, true, false, PROFILE, true, 45, "neededupdate", "disabled"], // 11 |
|
33 [true, false, false, false, false, true, PROFILE, false, 46, "enabled", ""], // 12 |
|
34 [true, false, false, false, true, true, PROFILE, false, 47, "enabled", ""], // 13 |
|
35 [true, false, false, false, true, false, PROFILE, false, 48, "unneededupdate", ""], // 14 |
|
36 |
|
37 // userDisabled and isActive cannot be true on startup |
|
38 |
|
39 [true, true, true, false, false, true, PROFILE, false, 49, "incompatible", ""], // 15 |
|
40 [true, true, true, false, true, true, PROFILE, false, 50, "autoupdate", ""], // 16 |
|
41 [true, true, true, false, true, false, PROFILE, false, 51, "neededupdate", ""], // 17 |
|
42 |
|
43 // userDisabled and isActive cannot be true on startup |
|
44 |
|
45 // Being in a different scope should make little difference except no updates are possible so don't exhaustively test each |
|
46 [false, false, false, true, true, false, USER, false, 0, "", "disabled"], // 18 |
|
47 [true, true, false, false, true, false, USER, false, 1, "enabled", ""], // 19 |
|
48 [false, true, true, true, true, false, USER, false, 2, "incompatible", "disabled"], // 20 |
|
49 [true, true, true, false, true, false, USER, false, 3, "incompatible", ""], // 21 |
|
50 [false, false, false, true, true, false, SYSTEM, false, 4, "", "disabled"], // 22 |
|
51 [true, true, false, false, true, false, SYSTEM, false, 5, "enabled", ""], // 23 |
|
52 [false, true, true, true, true, false, SYSTEM, false, 6, "incompatible", "disabled"], // 24 |
|
53 [true, true, true, false, true, false, SYSTEM, false, 7, "incompatible", ""], // 25 |
|
54 [false, false, false, true, true, false, APP, false, 8, "", "disabled"], // 26 |
|
55 [true, true, false, false, true, false, APP, false, 9, "enabled", ""], // 27 |
|
56 [false, true, true, true, true, false, APP, false, 10, "incompatible", "disabled"], // 28 |
|
57 [true, true, true, false, true, false, APP, false, 11, "incompatible", ""], // 29 |
|
58 ]; |
|
59 |
|
60 function waitForView(aView, aCallback) { |
|
61 var view = gWin.document.getElementById(aView); |
|
62 if (view.parentNode.selectedPanel == view) { |
|
63 aCallback(); |
|
64 return; |
|
65 } |
|
66 |
|
67 view.addEventListener("ViewChanged", function() { |
|
68 view.removeEventListener("ViewChanged", arguments.callee, false); |
|
69 aCallback(); |
|
70 }, false); |
|
71 } |
|
72 |
|
73 function getString(aName) { |
|
74 if (!aName) |
|
75 return ""; |
|
76 |
|
77 var strings = Services.strings.createBundle("chrome://mozapps/locale/extensions/selectAddons.properties"); |
|
78 return strings.GetStringFromName("action." + aName); |
|
79 } |
|
80 |
|
81 function getSourceString(aSource) { |
|
82 if (!aSource) |
|
83 return ""; |
|
84 |
|
85 var strings = Services.strings.createBundle("chrome://mozapps/locale/extensions/selectAddons.properties"); |
|
86 switch (aSource) { |
|
87 case PROFILE: |
|
88 return strings.GetStringFromName("source.profile"); |
|
89 case DIST: |
|
90 return strings.GetStringFromName("source.bundled"); |
|
91 default: |
|
92 return strings.GetStringFromName("source.other"); |
|
93 } |
|
94 } |
|
95 |
|
96 function test() { |
|
97 waitForExplicitFinish(); |
|
98 |
|
99 gProvider = new MockProvider(); |
|
100 |
|
101 // Set prefs for Distributed Extension Source tests. |
|
102 Services.prefs.setBoolPref("extensions.installedDistroAddon.test3@tests.mozilla.org", true); |
|
103 Services.prefs.setBoolPref("extensions.installedDistroAddon.test12@tests.mozilla.org", true); |
|
104 Services.prefs.setBoolPref("extensions.installedDistroAddon.test15@tests.mozilla.org", true); |
|
105 |
|
106 for (let pos in ADDONS) { |
|
107 let addonItem = ADDONS[pos]; |
|
108 let addon = new MockAddon("test" + pos + "@tests.mozilla.org", |
|
109 "Test Add-on " + pos, "extension"); |
|
110 addon.version = "1.0"; |
|
111 addon.userDisabled = addonItem[0]; |
|
112 addon.appDisabled = addonItem[1]; |
|
113 addon.isActive = addonItem[3]; |
|
114 addon.applyBackgroundUpdates = addonItem[5] ? AddonManager.AUTOUPDATE_ENABLE |
|
115 : AddonManager.AUTOUPDATE_DISABLE; |
|
116 addon.scope = addonItem[6]; |
|
117 |
|
118 // Remove the upgrade permission from non-profile add-ons |
|
119 if (addon.scope != AddonManager.SCOPE_PROFILE) |
|
120 addon._permissions -= AddonManager.PERM_CAN_UPGRADE; |
|
121 |
|
122 addon.findUpdates = function(aListener, aReason, aAppVersion, aPlatformVersion) { |
|
123 addon.appDisabled = addonItem[2]; |
|
124 addon.isActive = addon.shouldBeActive; |
|
125 |
|
126 if (addonItem[4]) { |
|
127 var newAddon = new MockAddon(this.id, this.name, "extension"); |
|
128 newAddon.version = "2.0"; |
|
129 var install = new MockInstall(this.name, this.type, newAddon); |
|
130 install.existingAddon = this; |
|
131 aListener.onUpdateAvailable(this, install); |
|
132 } |
|
133 |
|
134 aListener.onUpdateFinished(this, AddonManager.UPDATE_STATUS_NO_ERROR); |
|
135 }; |
|
136 |
|
137 gProvider.addAddon(addon); |
|
138 } |
|
139 |
|
140 gWin = Services.ww.openWindow(null, |
|
141 "chrome://mozapps/content/extensions/selectAddons.xul", |
|
142 "", |
|
143 "chrome,centerscreen,dialog,titlebar", |
|
144 null); |
|
145 waitForFocus(function() { |
|
146 waitForView("select", run_next_test); |
|
147 }, gWin); |
|
148 } |
|
149 |
|
150 function end_test() { |
|
151 gWin.close(); |
|
152 finish(); |
|
153 } |
|
154 |
|
155 // Minimal test for the checking UI |
|
156 add_test(function checking_test() { |
|
157 // By the time we're here the progress bar should be full |
|
158 var progress = gWin.document.getElementById("checking-progress"); |
|
159 is(progress.mode, "determined", "Should be a determined progress bar"); |
|
160 is(progress.value, progress.max, "Should be at full progress"); |
|
161 |
|
162 run_next_test(); |
|
163 }); |
|
164 |
|
165 // Tests that the selection UI behaves correctly |
|
166 add_test(function selection_test() { |
|
167 function check_state() { |
|
168 var str = addon[keep.checked ? 9 : 10]; |
|
169 var expected = getString(str); |
|
170 var showCheckbox = str == "neededupdate" || str == "unneededupdate"; |
|
171 is(action.textContent, expected, "Action message should have the right text"); |
|
172 is(!is_hidden(update), showCheckbox, "Checkbox should have the right visibility"); |
|
173 is(is_hidden(action), showCheckbox, "Message should have the right visibility"); |
|
174 if (showCheckbox) |
|
175 ok(update.checked, "Optional update checkbox should be checked"); |
|
176 |
|
177 if (keep.checked) { |
|
178 is(row.hasAttribute("active"), !addon[2] || hasUpdate, |
|
179 "Add-on will be active if it isn't appDisabled or an update is available"); |
|
180 |
|
181 if (showCheckbox) { |
|
182 info("Flipping update checkbox"); |
|
183 EventUtils.synthesizeMouseAtCenter(update, { }, gWin); |
|
184 is(row.hasAttribute("active"), str == "unneededupdate", |
|
185 "If the optional update isn't needed then the add-on will still be active"); |
|
186 |
|
187 info("Flipping update checkbox"); |
|
188 EventUtils.synthesizeMouseAtCenter(update, { }, gWin); |
|
189 is(row.hasAttribute("active"), !addon[2] || hasUpdate, |
|
190 "Add-on will be active if it isn't appDisabled or an update is available"); |
|
191 } |
|
192 } |
|
193 else { |
|
194 ok(!row.hasAttribute("active"), "Add-on won't be active when not keeping"); |
|
195 |
|
196 if (showCheckbox) { |
|
197 info("Flipping update checkbox"); |
|
198 EventUtils.synthesizeMouseAtCenter(update, { }, gWin); |
|
199 ok(!row.hasAttribute("active"), |
|
200 "Unchecking the update checkbox shouldn't make the add-on active"); |
|
201 |
|
202 info("Flipping update checkbox"); |
|
203 EventUtils.synthesizeMouseAtCenter(update, { }, gWin); |
|
204 ok(!row.hasAttribute("active"), |
|
205 "Re-checking the update checkbox shouldn't make the add-on active"); |
|
206 } |
|
207 } |
|
208 } |
|
209 |
|
210 is(gWin.document.getElementById("view-deck").selectedPanel.id, "select", |
|
211 "Should be on the right view"); |
|
212 |
|
213 var pos = 0; |
|
214 var scrollbox = gWin.document.getElementById("select-scrollbox"); |
|
215 var scrollBoxObject = scrollbox.boxObject.QueryInterface(Ci.nsIScrollBoxObject); |
|
216 for (var row = gWin.document.getElementById("select-rows").firstChild; row; row = row.nextSibling) { |
|
217 // Ignore separators but increase the position by a large amount so we |
|
218 // can verify they were in the right place |
|
219 if (row.localName == "separator") { |
|
220 pos += 30; |
|
221 continue; |
|
222 } |
|
223 |
|
224 is(row._addon.type, "extension", "Should only be listing extensions"); |
|
225 |
|
226 // Ignore non-test add-ons that may be present |
|
227 if (row.id.substr(-18) != "@tests.mozilla.org") |
|
228 continue; |
|
229 |
|
230 var id = parseInt(row.id.substring(4, row.id.length - 18)); |
|
231 var addon = ADDONS[id]; |
|
232 |
|
233 info("Testing add-on " + id); |
|
234 scrollBoxObject.ensureElementIsVisible(row); |
|
235 var keep = gWin.document.getAnonymousElementByAttribute(row, "anonid", "keep"); |
|
236 var action = gWin.document.getAnonymousElementByAttribute(row, "class", "addon-action-message"); |
|
237 var update = gWin.document.getAnonymousElementByAttribute(row, "anonid", "update"); |
|
238 var source = gWin.document.getAnonymousElementByAttribute(row, "class", "addon-source"); |
|
239 |
|
240 if (id == 3 || id == 12 || id == 15) { |
|
241 // Distro Installed To Profile |
|
242 is(source.textContent, getSourceString(DIST), "Source message should have the right text for Distributed Addons"); |
|
243 } else { |
|
244 is(source.textContent, getSourceString(addon[6]), "Source message should have the right text"); |
|
245 } |
|
246 |
|
247 // Non-profile add-ons don't appear to have updates since we won't install |
|
248 // them |
|
249 var hasUpdate = addon[4] && addon[6] == PROFILE; |
|
250 |
|
251 is(pos, addon[8], "Should have been in the right position"); |
|
252 is(keep.checked, addon[7], "Keep checkbox should be in the right state"); |
|
253 |
|
254 check_state(); |
|
255 |
|
256 info("Flipping keep"); |
|
257 EventUtils.synthesizeMouseAtCenter(keep, { }, gWin); |
|
258 is(keep.checked, !addon[7], "Keep checkbox should be in the right state"); |
|
259 |
|
260 check_state(); |
|
261 |
|
262 pos++; |
|
263 } |
|
264 |
|
265 is(pos, 60, "Should have seen the right number of add-ons"); |
|
266 |
|
267 run_next_test(); |
|
268 }); |