| OLD | NEW |
| 1 /* | 1 /* |
| 2 * This file is part of Adblock Plus <https://adblockplus.org/>, | 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
| 3 * Copyright (C) 2006-present eyeo GmbH | 3 * Copyright (C) 2006-present eyeo GmbH |
| 4 * | 4 * |
| 5 * Adblock Plus is free software: you can redistribute it and/or modify | 5 * Adblock Plus is free software: you can redistribute it and/or modify |
| 6 * it under the terms of the GNU General Public License version 3 as | 6 * it under the terms of the GNU General Public License version 3 as |
| 7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
| 8 * | 8 * |
| 9 * Adblock Plus is distributed in the hope that it will be useful, | 9 * Adblock Plus is distributed in the hope that it will be useful, |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 * GNU General Public License for more details. | 12 * GNU General Public License for more details. |
| 13 * | 13 * |
| 14 * You should have received a copy of the GNU General Public License | 14 * You should have received a copy of the GNU General Public License |
| 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. | 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
| 16 */ | 16 */ |
| 17 | 17 |
| 18 "use strict"; | 18 "use strict"; |
| 19 | 19 |
| 20 const assert = require("assert"); |
| 21 |
| 20 let { | 22 let { |
| 21 createSandbox, setupTimerAndXMLHttp, setupRandomResult, unexpectedError, Cr | 23 createSandbox, setupTimerAndXMLHttp, setupRandomResult, Cr |
| 22 } = require("./_common"); | 24 } = require("./_common"); |
| 23 | 25 |
| 24 let Prefs = null; | 26 let Prefs = null; |
| 25 let Utils = null; | 27 let Utils = null; |
| 26 let Notification = null; | 28 let Notification = null; |
| 27 | 29 |
| 28 exports.setUp = function(callback) | 30 describe("Notifications", () => |
| 29 { | 31 { |
| 30 // Inject our Array and JSON to make sure that instanceof checks on arrays | 32 let runner = {}; |
| 31 // within the sandbox succeed even with data passed in from outside. | 33 |
| 32 let globals = Object.assign({Array, JSON}, | 34 beforeEach(() => |
| 33 setupTimerAndXMLHttp.call(this), setupRandomResult.call(this)); | 35 { |
| 34 | 36 runner = {}; |
| 35 let sandboxedRequire = createSandbox({globals}); | 37 // Inject our Array and JSON to make sure that instanceof checks on arrays |
| 36 ( | 38 // within the sandbox succeed even with data passed in from outside. |
| 37 {Prefs} = sandboxedRequire("./stub-modules/prefs"), | 39 let globals = Object.assign({Array, JSON}, |
| 38 {Utils} = sandboxedRequire("./stub-modules/utils"), | 40 setupTimerAndXMLHttp.call(runner), setupRandomResult.call(runner)); |
| 39 {Notification} = sandboxedRequire("../lib/notification") | 41 |
| 40 ); | 42 let sandboxedRequire = createSandbox({globals}); |
| 41 | 43 ( |
| 42 callback(); | 44 {Prefs} = sandboxedRequire("./stub-modules/prefs"), |
| 43 }; | 45 {Utils} = sandboxedRequire("./stub-modules/utils"), |
| 44 | 46 {Notification} = sandboxedRequire("../lib/notification") |
| 45 function showNotifications(url) | 47 ); |
| 46 { | 48 }); |
| 47 let shownNotifications = []; | 49 |
| 48 function showListener(notification) | 50 function showNotifications(url) |
| 49 { | 51 { |
| 50 shownNotifications.push(notification); | 52 let shownNotifications = []; |
| 51 Notification.markAsShown(notification.id); | 53 function showListener(notification) |
| 54 { |
| 55 shownNotifications.push(notification); |
| 56 Notification.markAsShown(notification.id); |
| 57 } |
| 58 Notification.addShowListener(showListener); |
| 59 Notification.showNext(url); |
| 60 Notification.removeShowListener(showListener); |
| 61 return shownNotifications; |
| 52 } | 62 } |
| 53 Notification.addShowListener(showListener); | 63 |
| 54 Notification.showNext(url); | 64 function* pairs(array) |
| 55 Notification.removeShowListener(showListener); | 65 { |
| 56 return shownNotifications; | 66 for (let element1 of array) |
| 57 } | 67 { |
| 58 | 68 for (let element2 of array) |
| 59 function* pairs(array) | 69 { |
| 60 { | 70 if (element1 != element2) |
| 61 for (let element1 of array) | 71 yield [element1, element2]; |
| 62 { | 72 } |
| 63 for (let element2 of array) | |
| 64 { | |
| 65 if (element1 != element2) | |
| 66 yield [element1, element2]; | |
| 67 } | 73 } |
| 68 } | 74 } |
| 69 } | 75 |
| 70 | 76 function registerHandler(notifications, checkCallback) |
| 71 function registerHandler(notifications, checkCallback) | 77 { |
| 72 { | 78 runner.registerHandler("/notification.json", metadata => |
| 73 this.registerHandler("/notification.json", metadata => | 79 { |
| 74 { | 80 if (checkCallback) |
| 75 if (checkCallback) | 81 checkCallback(metadata); |
| 76 checkCallback(metadata); | 82 |
| 77 | 83 let notification = { |
| 78 let notification = { | 84 version: 55, |
| 79 version: 55, | 85 notifications |
| 80 notifications | 86 }; |
| 81 }; | 87 |
| 82 | 88 return [Cr.NS_OK, 200, JSON.stringify(notification)]; |
| 83 return [Cr.NS_OK, 200, JSON.stringify(notification)]; | 89 }); |
| 84 }); | 90 } |
| 85 } | 91 |
| 86 | 92 it("No Data", () => |
| 87 exports.testNoData = function(test) | 93 { |
| 88 { | 94 assert.deepEqual(showNotifications(), [], "No notifications should be return
ed if there is no data"); |
| 89 test.deepEqual(showNotifications(), [], "No notifications should be returned i
f there is no data"); | 95 }); |
| 90 test.done(); | 96 |
| 91 }; | 97 it("Single Notificaion", () => |
| 92 | 98 { |
| 93 exports.testSingleNotification = function(test) | |
| 94 { | |
| 95 let information = { | |
| 96 id: 1, | |
| 97 type: "information", | |
| 98 message: {"en-US": "Information"} | |
| 99 }; | |
| 100 | |
| 101 registerHandler.call(this, [information]); | |
| 102 this.runScheduledTasks(1).then(() => | |
| 103 { | |
| 104 test.deepEqual(showNotifications(), [information], "The notification is show
n"); | |
| 105 test.deepEqual(showNotifications(), [], "Informational notifications aren't
shown more than once"); | |
| 106 }).catch(unexpectedError.bind(test)).then(() => test.done()); | |
| 107 }; | |
| 108 | |
| 109 exports.testInformationAndCritical = function(test) | |
| 110 { | |
| 111 let information = { | |
| 112 id: 1, | |
| 113 type: "information", | |
| 114 message: {"en-US": "Information"} | |
| 115 }; | |
| 116 let critical = { | |
| 117 id: 2, | |
| 118 type: "critical", | |
| 119 message: {"en-US": "Critical"} | |
| 120 }; | |
| 121 | |
| 122 registerHandler.call(this, [information, critical]); | |
| 123 this.runScheduledTasks(1).then(() => | |
| 124 { | |
| 125 test.deepEqual(showNotifications(), [critical], "The critical notification i
s given priority"); | |
| 126 test.deepEqual(showNotifications(), [critical], "Critical notifications can
be shown multiple times"); | |
| 127 }).catch(unexpectedError.bind(test)).then(() => test.done()); | |
| 128 }; | |
| 129 | |
| 130 exports.testNoType = function(test) | |
| 131 { | |
| 132 let information = { | |
| 133 id: 1, | |
| 134 message: {"en-US": "Information"} | |
| 135 }; | |
| 136 | |
| 137 registerHandler.call(this, [information]); | |
| 138 this.runScheduledTasks(1).then(() => | |
| 139 { | |
| 140 test.deepEqual(showNotifications(), [information], "The notification is show
n"); | |
| 141 test.deepEqual(showNotifications(), [], "Notification is treated as type inf
ormation"); | |
| 142 }).catch(unexpectedError.bind(test)).then(() => test.done()); | |
| 143 }; | |
| 144 | |
| 145 function testTargetSelectionFunc(propName, value, result) | |
| 146 { | |
| 147 return function(test) | |
| 148 { | |
| 149 let targetInfo = {}; | |
| 150 targetInfo[propName] = value; | |
| 151 | |
| 152 let information = { | 99 let information = { |
| 153 id: 1, | 100 id: 1, |
| 154 type: "information", | 101 type: "information", |
| 155 message: {"en-US": "Information"}, | 102 message: {"en-US": "Information"} |
| 156 targets: [targetInfo] | 103 }; |
| 157 }; | 104 |
| 158 | 105 registerHandler.call(runner, [information]); |
| 159 registerHandler.call(this, [information]); | 106 return runner.runScheduledTasks(1).then(() => |
| 160 this.runScheduledTasks(1).then(() => | 107 { |
| 161 { | 108 assert.deepEqual(showNotifications(), [information], "The notification is
shown"); |
| 162 let expected = (result ? [information] : []); | 109 assert.deepEqual(showNotifications(), [], "Informational notifications are
n't shown more than once"); |
| 163 test.deepEqual(showNotifications(), expected, "Selected notification for "
+ JSON.stringify(information.targets)); | 110 }); |
| 164 test.deepEqual(showNotifications(), [], "No notification on second call"); | 111 }); |
| 165 }).catch(unexpectedError.bind(test)).then(() => test.done()); | 112 |
| 166 }; | 113 it("Information and Critical", () => |
| 167 } | 114 { |
| 168 | |
| 169 exports.testTargetSelection = {}; | |
| 170 | |
| 171 for (let [propName, value, result] of [ | |
| 172 ["extension", "adblockpluschrome", true], | |
| 173 ["extension", "adblockplus", false], | |
| 174 ["extension", "adblockpluschrome2", false], | |
| 175 ["extensionMinVersion", "1.4", true], | |
| 176 ["extensionMinVersion", "1.4.1", true], | |
| 177 ["extensionMinVersion", "1.5", false], | |
| 178 ["extensionMaxVersion", "1.5", true], | |
| 179 ["extensionMaxVersion", "1.4.1", true], | |
| 180 ["extensionMaxVersion", "1.4.*", true], | |
| 181 ["extensionMaxVersion", "1.4", false], | |
| 182 ["application", "chrome", true], | |
| 183 ["application", "firefox", false], | |
| 184 ["applicationMinVersion", "27.0", true], | |
| 185 ["applicationMinVersion", "27", true], | |
| 186 ["applicationMinVersion", "26", true], | |
| 187 ["applicationMinVersion", "28", false], | |
| 188 ["applicationMinVersion", "27.1", false], | |
| 189 ["applicationMinVersion", "27.0b1", true], | |
| 190 ["applicationMaxVersion", "27.0", true], | |
| 191 ["applicationMaxVersion", "27", true], | |
| 192 ["applicationMaxVersion", "28", true], | |
| 193 ["applicationMaxVersion", "26", false], | |
| 194 ["applicationMaxVersion", "27.0b1", false], | |
| 195 ["platform", "chromium", true], | |
| 196 ["platform", "gecko", false], | |
| 197 ["platformMinVersion", "12.0", true], | |
| 198 ["platformMinVersion", "12", true], | |
| 199 ["platformMinVersion", "11", true], | |
| 200 ["platformMinVersion", "13", false], | |
| 201 ["platformMinVersion", "12.1", false], | |
| 202 ["platformMinVersion", "12.0b1", true], | |
| 203 ["platformMaxVersion", "12.0", true], | |
| 204 ["platformMaxVersion", "12", true], | |
| 205 ["platformMaxVersion", "13", true], | |
| 206 ["platformMaxVersion", "11", false], | |
| 207 ["platformMaxVersion", "12.0b1", false], | |
| 208 ["blockedTotalMin", "11", false], | |
| 209 ["blockedTotalMin", "10", true], | |
| 210 ["blockedTotalMax", "10", true], | |
| 211 ["blockedTotalMax", "1", false], | |
| 212 ["locales", ["en-US"], true], | |
| 213 ["locales", ["en-US", "de-DE"], true], | |
| 214 ["locales", ["de-DE"], false], | |
| 215 ["locales", ["en-GB", "de-DE"], false] | |
| 216 ]) | |
| 217 { | |
| 218 exports.testTargetSelection[`${propName}=${value}`] = testTargetSelectionFunc(
propName, value, result); | |
| 219 } | |
| 220 | |
| 221 exports.testTargetSelectionNoShowStats = { | |
| 222 | |
| 223 setUp(callback) | |
| 224 { | |
| 225 this.show_statsinpopup_orig = Prefs.show_statsinpopup; | |
| 226 Prefs.show_statsinpopup = false; | |
| 227 callback(); | |
| 228 }, | |
| 229 tearDown(callback) | |
| 230 { | |
| 231 Prefs.show_statsinpopup = this.show_statsinpopup_orig; | |
| 232 callback(); | |
| 233 } | |
| 234 }; | |
| 235 for (let [propName, value, result] of [ | |
| 236 ["blockedTotalMin", "10", false], | |
| 237 ["blockedTotalMax", "10", false] | |
| 238 ]) | |
| 239 { | |
| 240 exports.testTargetSelectionNoShowStats[`${propName}=${value}`] = testTargetSel
ectionFunc(propName, value, result); | |
| 241 } | |
| 242 | |
| 243 exports.testMultipleTargets = {}; | |
| 244 | |
| 245 for (let [[propName1, value1, result1], [propName2, value2, result2]] of pairs([ | |
| 246 ["extension", "adblockpluschrome", true], | |
| 247 ["extension", "adblockplus", false], | |
| 248 ["extensionMinVersion", "1.4", true], | |
| 249 ["extensionMinVersion", "1.5", false], | |
| 250 ["application", "chrome", true], | |
| 251 ["application", "firefox", false], | |
| 252 ["applicationMinVersion", "27", true], | |
| 253 ["applicationMinVersion", "28", false], | |
| 254 ["platform", "chromium", true], | |
| 255 ["platform", "gecko", false], | |
| 256 ["platformMinVersion", "12", true], | |
| 257 ["platformMinVersion", "13", false], | |
| 258 ["unknown", "unknown", false] | |
| 259 ])) | |
| 260 { | |
| 261 exports.testMultipleTargets[`${propName1}=${value1},${propName2}=${value2}`] =
function(test) | |
| 262 { | |
| 263 let targetInfo1 = {}; | |
| 264 targetInfo1[propName1] = value1; | |
| 265 let targetInfo2 = {}; | |
| 266 targetInfo2[propName2] = value2; | |
| 267 | |
| 268 let information = { | 115 let information = { |
| 269 id: 1, | 116 id: 1, |
| 270 type: "information", | 117 type: "information", |
| 271 message: {"en-US": "Information"}, | 118 message: {"en-US": "Information"} |
| 272 targets: [targetInfo1, targetInfo2] | 119 }; |
| 120 let critical = { |
| 121 id: 2, |
| 122 type: "critical", |
| 123 message: {"en-US": "Critical"} |
| 124 }; |
| 125 |
| 126 registerHandler.call(this, [information, critical]); |
| 127 return runner.runScheduledTasks(1).then(() => |
| 128 { |
| 129 assert.deepEqual(showNotifications(), [critical], "The critical notificati
on is given priority"); |
| 130 assert.deepEqual(showNotifications(), [critical], "Critical notifications
can be shown multiple times"); |
| 131 }); |
| 132 }); |
| 133 |
| 134 it("No Type", () => |
| 135 { |
| 136 let information = { |
| 137 id: 1, |
| 138 message: {"en-US": "Information"} |
| 273 }; | 139 }; |
| 274 | 140 |
| 275 registerHandler.call(this, [information]); | 141 registerHandler.call(this, [information]); |
| 276 this.runScheduledTasks(1).then(() => | 142 return runner.runScheduledTasks(1).then(() => |
| 277 { | 143 { |
| 278 let expected = (result1 || result2 ? [information] : []); | 144 assert.deepEqual(showNotifications(), [information], "The notification is
shown"); |
| 279 test.deepEqual(showNotifications(), expected, "Selected notification for "
+ JSON.stringify(information.targets)); | 145 assert.deepEqual(showNotifications(), [], "Notification is treated as type
information"); |
| 280 }).catch(unexpectedError.bind(test)).then(() => test.done()); | 146 }); |
| 281 }; | 147 }); |
| 282 } | 148 |
| 283 | 149 function testTargetSelectionFunc(propName, value, result) |
| 284 exports.testParametersSent = function(test) | 150 { |
| 285 { | 151 return function() |
| 286 Prefs.notificationdata = { | 152 { |
| 287 data: { | 153 let targetInfo = {}; |
| 288 version: "3" | 154 targetInfo[propName] = value; |
| 289 } | 155 |
| 290 }; | 156 let information = { |
| 291 | 157 id: 1, |
| 292 let parameters = null; | 158 type: "information", |
| 293 registerHandler.call(this, [], metadata => | 159 message: {"en-US": "Information"}, |
| 294 { | 160 targets: [targetInfo] |
| 295 parameters = decodeURI(metadata.queryString); | 161 }; |
| 296 }); | 162 |
| 297 this.runScheduledTasks(1).then(() => | 163 registerHandler.call(this, [information]); |
| 298 { | 164 return runner.runScheduledTasks(1).then(() => |
| 299 test.equal(parameters, | 165 { |
| 300 "addonName=adblockpluschrome&addonVersion=1.4.1&application=chrome&app
licationVersion=27.0&platform=chromium&platformVersion=12.0&lastVersion=3&downlo
adCount=0", | 166 let expected = (result ? [information] : []); |
| 301 "The correct parameters are sent to the server"); | 167 assert.deepEqual(showNotifications(), expected, "Selected notification f
or " + JSON.stringify(information.targets)); |
| 302 }).catch(unexpectedError.bind(test)).then(() => test.done()); | 168 assert.deepEqual(showNotifications(), [], "No notification on second cal
l"); |
| 303 }; | 169 }); |
| 304 | 170 }; |
| 305 exports.testExpirationInterval = {}; | |
| 306 | |
| 307 let initialDelay = 1 / 60; | |
| 308 for (let currentTest of [ | |
| 309 { | |
| 310 randomResult: 0.5, | |
| 311 requests: [initialDelay, initialDelay + 24, initialDelay + 48] | |
| 312 }, | |
| 313 { | |
| 314 randomResult: 0, // Changes interval by factor 0.8 (19.2 hours) | |
| 315 requests: [initialDelay, initialDelay + 20, initialDelay + 40] | |
| 316 }, | |
| 317 { | |
| 318 randomResult: 1, // Changes interval by factor 1.2 (28.8 hours) | |
| 319 requests: [initialDelay, initialDelay + 29, initialDelay + 58] | |
| 320 }, | |
| 321 { | |
| 322 randomResult: 0.25, // Changes interval by factor 0.9 (21.6 hours) | |
| 323 requests: [initialDelay, initialDelay + 22, initialDelay + 44] | |
| 324 }, | |
| 325 { | |
| 326 randomResult: 0.5, | |
| 327 skipAfter: initialDelay + 5, | |
| 328 skip: 10, // Short break should not increase soft expiration | |
| 329 requests: [initialDelay, initialDelay + 24] | |
| 330 }, | |
| 331 { | |
| 332 randomResult: 0.5, | |
| 333 skipAfter: initialDelay + 5, | |
| 334 skip: 30, // Long break should increase soft expiration, hitti
ng hard expiration | |
| 335 requests: [initialDelay, initialDelay + 48] | |
| 336 } | 171 } |
| 337 ]) | 172 |
| 338 { | 173 describe("Target selection", () => |
| 339 let testId = "Math.random() returning " + currentTest.randomResult; | 174 { |
| 340 if (typeof currentTest.skip != "number") | 175 for (let [propName, value, result] of [ |
| 341 testId += " skipping " + currentTest.skip + " hours after " + currentTest.sk
ipAfter + " hours"; | 176 ["extension", "adblockpluschrome", true], |
| 342 exports.testExpirationInterval[testId] = function(test) | 177 ["extension", "adblockplus", false], |
| 343 { | 178 ["extension", "adblockpluschrome2", false], |
| 344 let requests = []; | 179 ["extensionMinVersion", "1.4", true], |
| 345 registerHandler.call(this, [], metadata => requests.push(this.getTimeOffset(
))); | 180 ["extensionMinVersion", "1.4.1", true], |
| 346 | 181 ["extensionMinVersion", "1.5", false], |
| 347 this.randomResult = currentTest.randomResult; | 182 ["extensionMaxVersion", "1.5", true], |
| 348 | 183 ["extensionMaxVersion", "1.4.1", true], |
| 349 let maxHours = Math.round(Math.max.apply(null, currentTest.requests)) + 1; | 184 ["extensionMaxVersion", "1.4.*", true], |
| 350 this.runScheduledTasks(maxHours, currentTest.skipAfter, currentTest.skip).th
en(() => | 185 ["extensionMaxVersion", "1.4", false], |
| 351 { | 186 ["application", "chrome", true], |
| 352 test.deepEqual(requests, currentTest.requests, "Requests"); | 187 ["application", "firefox", false], |
| 353 }).catch(unexpectedError.bind(test)).then(() => test.done()); | 188 ["applicationMinVersion", "27.0", true], |
| 354 }; | 189 ["applicationMinVersion", "27", true], |
| 355 } | 190 ["applicationMinVersion", "26", true], |
| 356 | 191 ["applicationMinVersion", "28", false], |
| 357 exports.testUsingSeverityInsteadOfType = function(test) | 192 ["applicationMinVersion", "27.1", false], |
| 358 { | 193 ["applicationMinVersion", "27.0b1", true], |
| 359 let severityNotification = { | 194 ["applicationMaxVersion", "27.0", true], |
| 360 id: 1, | 195 ["applicationMaxVersion", "27", true], |
| 361 severity: "information", | 196 ["applicationMaxVersion", "28", true], |
| 362 message: {"en-US": "Information"} | 197 ["applicationMaxVersion", "26", false], |
| 363 }; | 198 ["applicationMaxVersion", "27.0b1", false], |
| 364 | 199 ["platform", "chromium", true], |
| 365 function listener(name) | 200 ["platform", "gecko", false], |
| 366 { | 201 ["platformMinVersion", "12.0", true], |
| 367 if (name !== "notificationdata") | 202 ["platformMinVersion", "12", true], |
| 368 return; | 203 ["platformMinVersion", "11", true], |
| 369 | 204 ["platformMinVersion", "13", false], |
| 370 Prefs.removeListener(listener); | 205 ["platformMinVersion", "12.1", false], |
| 371 let notification = Prefs.notificationdata.data.notifications[0]; | 206 ["platformMinVersion", "12.0b1", true], |
| 372 test.ok(!("severity" in notification), "Severity property was removed"); | 207 ["platformMaxVersion", "12.0", true], |
| 373 test.ok("type" in notification, "Type property was added"); | 208 ["platformMaxVersion", "12", true], |
| 374 test.equal(notification.type, severityNotification.severity, "Type property
has correct value"); | 209 ["platformMaxVersion", "13", true], |
| 375 test.done(); | 210 ["platformMaxVersion", "11", false], |
| 376 } | 211 ["platformMaxVersion", "12.0b1", false], |
| 377 Prefs.addListener(listener); | 212 ["blockedTotalMin", "11", false], |
| 378 | 213 ["blockedTotalMin", "10", true], |
| 379 let responseText = JSON.stringify({ | 214 ["blockedTotalMax", "10", true], |
| 380 notifications: [severityNotification] | 215 ["blockedTotalMax", "1", false], |
| 381 }); | 216 ["locales", ["en-US"], true], |
| 382 Notification._onDownloadSuccess({}, responseText, () => {}, () => {}); | 217 ["locales", ["en-US", "de-DE"], true], |
| 383 }; | 218 ["locales", ["de-DE"], false], |
| 384 | 219 ["locales", ["en-GB", "de-DE"], false] |
| 385 exports.testURLSpecificNotification = function(test) | 220 ]) |
| 386 { | 221 { |
| 387 let withURLFilterFoo = { | 222 it(`Target ${propName}=${value}`, testTargetSelectionFunc(propName, value,
result)); |
| 388 id: 1, | 223 } |
| 389 urlFilters: ["foo.com$document"] | 224 }); |
| 390 }; | 225 |
| 391 let withoutURLFilter = { | 226 describe("No show stats", () => |
| 392 id: 2 | 227 { |
| 393 }; | 228 beforeEach(() => |
| 394 let withURLFilterBar = { | 229 { |
| 395 id: 3, | 230 runner.show_statsinpopup_orig = Prefs.show_statsinpopup; |
| 396 urlFilters: ["bar.com$document"] | 231 Prefs.show_statsinpopup = false; |
| 397 }; | 232 }); |
| 398 let subdomainURLFilter = { | 233 |
| 399 id: 4, | 234 afterEach(() => |
| 400 urlFilters: ["||example.com$document"] | 235 { |
| 401 }; | 236 Prefs.show_statsinpopup = runner.show_statsinpopup_orig; |
| 402 | 237 }); |
| 403 registerHandler.call(this, [ | 238 |
| 404 withURLFilterFoo, | 239 for (let [propName, value, result] of [ |
| 405 withoutURLFilter, | 240 ["blockedTotalMin", "10", false], |
| 406 withURLFilterBar, | 241 ["blockedTotalMax", "10", false] |
| 407 subdomainURLFilter | 242 ]) |
| 408 ]); | 243 { |
| 409 this.runScheduledTasks(1).then(() => | 244 it(`Target ${propName}=${value}`, testTargetSelectionFunc(propName, value,
result)); |
| 410 { | 245 } |
| 411 test.deepEqual(showNotifications(), [withoutURLFilter], "URL-specific notifi
cations are skipped"); | 246 }); |
| 412 test.deepEqual(showNotifications("http://foo.com"), [withURLFilterFoo], "URL
-specific notification is retrieved"); | 247 |
| 413 test.deepEqual(showNotifications("http://foo.com"), [], "URL-specific notifi
cation is not retrieved"); | 248 describe("Multiple Targets", () => |
| 414 test.deepEqual(showNotifications("http://www.example.com"), [subdomainURLFil
ter], "URL-specific notification matches subdomain"); | 249 { |
| 415 }).catch(unexpectedError.bind(test)).then(() => test.done()); | 250 for (let [[propName1, value1, result1], [propName2, value2, result2]] of pai
rs([ |
| 416 }; | 251 ["extension", "adblockpluschrome", true], |
| 417 | 252 ["extension", "adblockplus", false], |
| 418 exports.testInterval = function(test) | 253 ["extensionMinVersion", "1.4", true], |
| 419 { | 254 ["extensionMinVersion", "1.5", false], |
| 420 let relentless = { | 255 ["application", "chrome", true], |
| 421 id: 3, | 256 ["application", "firefox", false], |
| 422 type: "relentless", | 257 ["applicationMinVersion", "27", true], |
| 423 interval: 100 | 258 ["applicationMinVersion", "28", false], |
| 424 }; | 259 ["platform", "chromium", true], |
| 425 | 260 ["platform", "gecko", false], |
| 426 registerHandler.call(this, [relentless]); | 261 ["platformMinVersion", "12", true], |
| 427 this.runScheduledTasks(1).then(() => | 262 ["platformMinVersion", "13", false], |
| 428 { | 263 ["unknown", "unknown", false] |
| 429 test.deepEqual(showNotifications(), [relentless], "Relentless notifications
are shown initially"); | 264 ])) |
| 430 }).then(() => | 265 { |
| 431 { | 266 it(`Targets ${propName1}=${value1},${propName2}=${value2}`, () => |
| 432 test.deepEqual(showNotifications(), [], "Relentless notifications are not sh
own before the interval"); | 267 { |
| 433 }).then(() => | 268 let targetInfo1 = {}; |
| 434 { | 269 targetInfo1[propName1] = value1; |
| 435 // Date always returns a fixed time (see setupTimerAndXMLHttp) so we | 270 let targetInfo2 = {}; |
| 436 // manipulate the shown data manually. | 271 targetInfo2[propName2] = value2; |
| 437 Prefs.notificationdata.shown[relentless.id] -= relentless.interval; | 272 |
| 438 test.deepEqual(showNotifications(), [relentless], "Relentless notifications
are shown after the interval"); | 273 let information = { |
| 439 }).catch(unexpectedError.bind(test)).then(() => test.done()); | 274 id: 1, |
| 440 }; | 275 type: "information", |
| 441 | 276 message: {"en-US": "Information"}, |
| 442 exports.testRelentlessNotification = function(test) | 277 targets: [targetInfo1, targetInfo2] |
| 443 { | 278 }; |
| 444 let relentless = { | 279 |
| 445 id: 3, | 280 registerHandler.call(this, [information]); |
| 446 type: "relentless", | 281 return runner.runScheduledTasks(1).then(() => |
| 447 interval: 100, | 282 { |
| 448 urlFilters: ["foo.com$document", "bar.foo$document"] | 283 let expected = (result1 || result2 ? [information] : []); |
| 449 }; | 284 assert.deepEqual(showNotifications(), expected, "Selected notification
for " + JSON.stringify(information.targets)); |
| 450 | 285 }); |
| 451 registerHandler.call(this, [relentless]); | 286 }); |
| 452 this.runScheduledTasks(1).then(() => | 287 } |
| 453 { | 288 }); |
| 454 test.deepEqual(showNotifications(), [], "Relentless notification is not show
n without URL"); | 289 |
| 455 test.deepEqual(showNotifications("http://bar.com"), [], "Relentless notifica
tion is not shown for a non-matching URL"); | 290 it("Parameters Sent", () => |
| 456 test.deepEqual(showNotifications("http://foo.com"), [relentless], "Relentles
s notification is shown for a matching URL"); | 291 { |
| 457 }).then(() => | 292 Prefs.notificationdata = { |
| 458 { | 293 data: { |
| 459 test.deepEqual(showNotifications("http://foo.com"), [], "Relentless notifica
tions are not shown before the interval"); | 294 version: "3" |
| 460 }).then(() => | 295 } |
| 461 { | 296 }; |
| 462 // Date always returns a fixed time (see setupTimerAndXMLHttp) so we | 297 |
| 463 // manipulate the shown data manually. | 298 let parameters = null; |
| 464 Prefs.notificationdata.shown[relentless.id] -= relentless.interval; | 299 registerHandler.call(this, [], metadata => |
| 465 test.deepEqual(showNotifications(), [], "Relentless notifications are not sh
own after the interval without URL"); | 300 { |
| 466 test.deepEqual(showNotifications("http://bar.com"), [], "Relentless notifica
tions are not shown after the interval for a non-matching URL"); | 301 parameters = decodeURI(metadata.queryString); |
| 467 test.deepEqual(showNotifications("http://bar.foo.com"), [relentless], "Relen
tless notifications are shown after the interval for a matching URL"); | 302 }); |
| 468 }).catch(unexpectedError.bind(test)).then(() => test.done()); | 303 return runner.runScheduledTasks(1).then(() => |
| 469 }; | 304 { |
| 470 | 305 assert.equal(parameters, |
| 471 exports.testGlobalOptOut = function(test) | 306 "addonName=adblockpluschrome&addonVersion=1.4.1&application=chr
ome&applicationVersion=27.0&platform=chromium&platformVersion=12.0&lastVersion=3
&downloadCount=0", |
| 472 { | 307 "The correct parameters are sent to the server"); |
| 473 Notification.toggleIgnoreCategory("*", true); | 308 }); |
| 474 test.ok(Prefs.notifications_ignoredcategories.indexOf("*") != -1, "Force enabl
e global opt-out"); | 309 }); |
| 475 Notification.toggleIgnoreCategory("*", true); | 310 |
| 476 test.ok(Prefs.notifications_ignoredcategories.indexOf("*") != -1, "Force enabl
e global opt-out (again)"); | 311 describe("Expiration Interval", () => |
| 477 Notification.toggleIgnoreCategory("*", false); | 312 { |
| 478 test.ok(Prefs.notifications_ignoredcategories.indexOf("*") == -1, "Force disab
le global opt-out"); | 313 let initialDelay = 1 / 60; |
| 479 Notification.toggleIgnoreCategory("*", false); | 314 for (let currentTest of [ |
| 480 test.ok(Prefs.notifications_ignoredcategories.indexOf("*") == -1, "Force disab
le global opt-out (again)"); | 315 { |
| 481 Notification.toggleIgnoreCategory("*"); | 316 randomResult: 0.5, |
| 482 test.ok(Prefs.notifications_ignoredcategories.indexOf("*") != -1, "Toggle enab
le global opt-out"); | 317 requests: [initialDelay, initialDelay + 24, initialDelay + 48] |
| 483 Notification.toggleIgnoreCategory("*"); | 318 }, |
| 484 test.ok(Prefs.notifications_ignoredcategories.indexOf("*") == -1, "Toggle disa
ble global opt-out"); | 319 { |
| 485 | 320 randomResult: 0, // Changes interval by factor 0.8 (19.2 hours) |
| 486 Prefs.notifications_showui = false; | 321 requests: [initialDelay, initialDelay + 20, initialDelay + 40] |
| 487 Notification.toggleIgnoreCategory("*", false); | 322 }, |
| 488 test.ok(!Prefs.notifications_showui, "Opt-out UI will not be shown if global o
pt-out hasn't been enabled yet"); | 323 { |
| 489 Notification.toggleIgnoreCategory("*", true); | 324 randomResult: 1, // Changes interval by factor 1.2 (28.8 hours) |
| 490 test.ok(Prefs.notifications_showui, "Opt-out UI will be shown after enabling g
lobal opt-out"); | 325 requests: [initialDelay, initialDelay + 29, initialDelay + 58] |
| 491 Notification.toggleIgnoreCategory("*", false); | 326 }, |
| 492 test.ok(Prefs.notifications_showui, "Opt-out UI will be shown after enabling g
lobal opt-out even if it got disabled again"); | 327 { |
| 493 | 328 randomResult: 0.25, // Changes interval by factor 0.9 (21.6 hours) |
| 494 let information = { | 329 requests: [initialDelay, initialDelay + 22, initialDelay + 44] |
| 495 id: 1, | 330 }, |
| 496 type: "information" | 331 { |
| 497 }; | 332 randomResult: 0.5, |
| 498 let critical = { | 333 skipAfter: initialDelay + 5, |
| 499 id: 2, | 334 skip: 10, // Short break should not increase soft expirati
on |
| 500 type: "critical" | 335 requests: [initialDelay, initialDelay + 24] |
| 501 }; | 336 }, |
| 502 let relentless = { | 337 { |
| 503 id: 3, | 338 randomResult: 0.5, |
| 504 type: "relentless" | 339 skipAfter: initialDelay + 5, |
| 505 }; | 340 skip: 30, // Long break should increase soft expiration, h
itting hard expiration |
| 506 | 341 requests: [initialDelay, initialDelay + 48] |
| 507 Notification.toggleIgnoreCategory("*", true); | 342 } |
| 508 registerHandler.call(this, [information]); | 343 ]) |
| 509 this.runScheduledTasks(1).then(() => | 344 { |
| 510 { | 345 let testId = `Math.random() returning ${currentTest.randomResult}`; |
| 511 test.deepEqual(showNotifications(), [], "Information notifications are ignor
ed after enabling global opt-out"); | 346 if (typeof currentTest.skip == "number") |
| 347 testId += ` skipping ${currentTest.skip} hours after ${currentTest.skipA
fter} hours`; |
| 348 |
| 349 it(testId, () => |
| 350 { |
| 351 let requests = []; |
| 352 registerHandler.call(this, [], metadata => requests.push(runner.getTimeO
ffset())); |
| 353 |
| 354 runner.randomResult = currentTest.randomResult; |
| 355 |
| 356 let maxHours = Math.round(Math.max.apply(null, currentTest.requests)) +
1; |
| 357 return runner.runScheduledTasks(maxHours, currentTest.skipAfter, current
Test.skip).then(() => |
| 358 { |
| 359 assert.deepEqual(requests, currentTest.requests, "Requests"); |
| 360 }); |
| 361 }); |
| 362 } |
| 363 }); |
| 364 |
| 365 it("Using severity instead of type", done => |
| 366 { |
| 367 let severityNotification = { |
| 368 id: 1, |
| 369 severity: "information", |
| 370 message: {"en-US": "Information"} |
| 371 }; |
| 372 |
| 373 function listener(name) |
| 374 { |
| 375 if (name !== "notificationdata") |
| 376 return; |
| 377 |
| 378 Prefs.removeListener(listener); |
| 379 let notification = Prefs.notificationdata.data.notifications[0]; |
| 380 assert.ok(!("severity" in notification), "Severity property was removed"); |
| 381 assert.ok("type" in notification, "Type property was added"); |
| 382 assert.equal(notification.type, severityNotification.severity, "Type prope
rty has correct value"); |
| 383 done(); |
| 384 } |
| 385 Prefs.addListener(listener); |
| 386 |
| 387 let responseText = JSON.stringify({ |
| 388 notifications: [severityNotification] |
| 389 }); |
| 390 Notification._onDownloadSuccess({}, responseText, () => {}, () => {}); |
| 391 }); |
| 392 |
| 393 it("URL Specific Notification", () => |
| 394 { |
| 395 let withURLFilterFoo = { |
| 396 id: 1, |
| 397 urlFilters: ["foo.com$document"] |
| 398 }; |
| 399 let withoutURLFilter = { |
| 400 id: 2 |
| 401 }; |
| 402 let withURLFilterBar = { |
| 403 id: 3, |
| 404 urlFilters: ["bar.com$document"] |
| 405 }; |
| 406 let subdomainURLFilter = { |
| 407 id: 4, |
| 408 urlFilters: ["||example.com$document"] |
| 409 }; |
| 410 |
| 411 registerHandler.call(this, [ |
| 412 withURLFilterFoo, |
| 413 withoutURLFilter, |
| 414 withURLFilterBar, |
| 415 subdomainURLFilter |
| 416 ]); |
| 417 return runner.runScheduledTasks(1).then(() => |
| 418 { |
| 419 assert.deepEqual(showNotifications(), [withoutURLFilter], "URL-specific no
tifications are skipped"); |
| 420 assert.deepEqual(showNotifications("http://foo.com"), [withURLFilterFoo],
"URL-specific notification is retrieved"); |
| 421 assert.deepEqual(showNotifications("http://foo.com"), [], "URL-specific no
tification is not retrieved"); |
| 422 assert.deepEqual(showNotifications("http://www.example.com"), [subdomainUR
LFilter], "URL-specific notification matches subdomain"); |
| 423 }); |
| 424 }); |
| 425 |
| 426 it("Interval", () => |
| 427 { |
| 428 let relentless = { |
| 429 id: 3, |
| 430 type: "relentless", |
| 431 interval: 100 |
| 432 }; |
| 433 |
| 434 registerHandler.call(this, [relentless]); |
| 435 return runner.runScheduledTasks(1).then(() => |
| 436 { |
| 437 assert.deepEqual(showNotifications(), [relentless], "Relentless notificati
ons are shown initially"); |
| 438 }).then(() => |
| 439 { |
| 440 assert.deepEqual(showNotifications(), [], "Relentless notifications are no
t shown before the interval"); |
| 441 }).then(() => |
| 442 { |
| 443 // Date always returns a fixed time (see setupTimerAndXMLHttp) so we |
| 444 // manipulate the shown data manually. |
| 445 Prefs.notificationdata.shown[relentless.id] -= relentless.interval; |
| 446 assert.deepEqual(showNotifications(), [relentless], "Relentless notificati
ons are shown after the interval"); |
| 447 }); |
| 448 }); |
| 449 |
| 450 it("Relentless notification", () => |
| 451 { |
| 452 let relentless = { |
| 453 id: 3, |
| 454 type: "relentless", |
| 455 interval: 100, |
| 456 urlFilters: ["foo.com$document", "bar.foo$document"] |
| 457 }; |
| 458 |
| 459 registerHandler.call(this, [relentless]); |
| 460 return runner.runScheduledTasks(1).then(() => |
| 461 { |
| 462 assert.deepEqual(showNotifications(), [], "Relentless notification is not
shown without URL"); |
| 463 assert.deepEqual(showNotifications("http://bar.com"), [], "Relentless noti
fication is not shown for a non-matching URL"); |
| 464 assert.deepEqual(showNotifications("http://foo.com"), [relentless], "Relen
tless notification is shown for a matching URL"); |
| 465 }).then(() => |
| 466 { |
| 467 assert.deepEqual(showNotifications("http://foo.com"), [], "Relentless noti
fications are not shown before the interval"); |
| 468 }).then(() => |
| 469 { |
| 470 // Date always returns a fixed time (see setupTimerAndXMLHttp) so we |
| 471 // manipulate the shown data manually. |
| 472 Prefs.notificationdata.shown[relentless.id] -= relentless.interval; |
| 473 assert.deepEqual(showNotifications(), [], "Relentless notifications are no
t shown after the interval without URL"); |
| 474 assert.deepEqual(showNotifications("http://bar.com"), [], "Relentless noti
fications are not shown after the interval for a non-matching URL"); |
| 475 assert.deepEqual(showNotifications("http://bar.foo.com"), [relentless], "R
elentless notifications are shown after the interval for a matching URL"); |
| 476 }); |
| 477 }); |
| 478 |
| 479 it("Global opt-out", () => |
| 480 { |
| 481 Notification.toggleIgnoreCategory("*", true); |
| 482 assert.ok(Prefs.notifications_ignoredcategories.indexOf("*") != -1, "Force e
nable global opt-out"); |
| 483 Notification.toggleIgnoreCategory("*", true); |
| 484 assert.ok(Prefs.notifications_ignoredcategories.indexOf("*") != -1, "Force e
nable global opt-out (again)"); |
| 512 Notification.toggleIgnoreCategory("*", false); | 485 Notification.toggleIgnoreCategory("*", false); |
| 513 test.deepEqual(showNotifications(), [information], "Information notification
s are shown after disabling global opt-out"); | 486 assert.ok(Prefs.notifications_ignoredcategories.indexOf("*") == -1, "Force d
isable global opt-out"); |
| 514 | 487 Notification.toggleIgnoreCategory("*", false); |
| 488 assert.ok(Prefs.notifications_ignoredcategories.indexOf("*") == -1, "Force d
isable global opt-out (again)"); |
| 489 Notification.toggleIgnoreCategory("*"); |
| 490 assert.ok(Prefs.notifications_ignoredcategories.indexOf("*") != -1, "Toggle
enable global opt-out"); |
| 491 Notification.toggleIgnoreCategory("*"); |
| 492 assert.ok(Prefs.notifications_ignoredcategories.indexOf("*") == -1, "Toggle
disable global opt-out"); |
| 493 |
| 494 Prefs.notifications_showui = false; |
| 495 Notification.toggleIgnoreCategory("*", false); |
| 496 assert.ok(!Prefs.notifications_showui, "Opt-out UI will not be shown if glob
al opt-out hasn't been enabled yet"); |
| 515 Notification.toggleIgnoreCategory("*", true); | 497 Notification.toggleIgnoreCategory("*", true); |
| 516 Prefs.notificationdata = {}; | 498 assert.ok(Prefs.notifications_showui, "Opt-out UI will be shown after enabli
ng global opt-out"); |
| 517 registerHandler.call(this, [critical]); | 499 Notification.toggleIgnoreCategory("*", false); |
| 518 return this.runScheduledTasks(1); | 500 assert.ok(Prefs.notifications_showui, "Opt-out UI will be shown after enabli
ng global opt-out even if it got disabled again"); |
| 519 }).then(() => | 501 |
| 520 { | 502 let information = { |
| 521 test.deepEqual(showNotifications(), [critical], "Critical notifications are
not ignored"); | 503 id: 1, |
| 522 | 504 type: "information" |
| 523 Prefs.notificationdata = {}; | 505 }; |
| 524 registerHandler.call(this, [relentless]); | 506 let critical = { |
| 525 return this.runScheduledTasks(1); | 507 id: 2, |
| 526 }).then(() => | 508 type: "critical" |
| 527 { | 509 }; |
| 528 test.deepEqual(showNotifications(), [relentless], "Relentless notifications
are not ignored"); | 510 let relentless = { |
| 529 }).catch(unexpectedError.bind(test)).then(() => test.done()); | 511 id: 3, |
| 530 }; | 512 type: "relentless" |
| 531 | 513 }; |
| 532 exports.testMessageWithoutLocalization = function(test) | 514 |
| 533 { | 515 Notification.toggleIgnoreCategory("*", true); |
| 534 let notification = {message: "non-localized"}; | 516 registerHandler.call(this, [information]); |
| 535 let texts = Notification.getLocalizedTexts(notification); | 517 return runner.runScheduledTasks(1).then(() => |
| 536 test.equal(texts.message, "non-localized"); | 518 { |
| 537 test.done(); | 519 assert.deepEqual(showNotifications(), [], "Information notifications are i
gnored after enabling global opt-out"); |
| 538 }; | 520 Notification.toggleIgnoreCategory("*", false); |
| 539 | 521 assert.deepEqual(showNotifications(), [information], "Information notifica
tions are shown after disabling global opt-out"); |
| 540 exports.testLanguageOnly = function(test) | 522 |
| 541 { | 523 Notification.toggleIgnoreCategory("*", true); |
| 542 let notification = {message: {fr: "fr"}}; | 524 Prefs.notificationdata = {}; |
| 543 Utils.appLocale = "fr"; | 525 registerHandler.call(this, [critical]); |
| 544 let texts = Notification.getLocalizedTexts(notification); | 526 return runner.runScheduledTasks(1); |
| 545 test.equal(texts.message, "fr"); | 527 }).then(() => |
| 546 Utils.appLocale = "fr-CA"; | 528 { |
| 547 texts = Notification.getLocalizedTexts(notification); | 529 assert.deepEqual(showNotifications(), [critical], "Critical notifications
are not ignored"); |
| 548 test.equal(texts.message, "fr"); | 530 |
| 549 test.done(); | 531 Prefs.notificationdata = {}; |
| 550 }; | 532 registerHandler.call(this, [relentless]); |
| 551 | 533 return runner.runScheduledTasks(1); |
| 552 exports.testLanguageAndCountry = function(test) | 534 }).then(() => |
| 553 { | 535 { |
| 554 let notification = {message: {"fr": "fr", "fr-CA": "fr-CA"}}; | 536 assert.deepEqual(showNotifications(), [relentless], "Relentless notificati
ons are not ignored"); |
| 555 Utils.appLocale = "fr-CA"; | 537 }); |
| 556 let texts = Notification.getLocalizedTexts(notification); | 538 }); |
| 557 test.equal(texts.message, "fr-CA"); | 539 |
| 558 Utils.appLocale = "fr"; | 540 it("Message without localization", () => |
| 559 texts = Notification.getLocalizedTexts(notification); | 541 { |
| 560 test.equal(texts.message, "fr"); | 542 let notification = {message: "non-localized"}; |
| 561 test.done(); | 543 let texts = Notification.getLocalizedTexts(notification); |
| 562 }; | 544 assert.equal(texts.message, "non-localized"); |
| 563 | 545 }); |
| 564 exports.testMissingTranslation = function(test) | 546 |
| 565 { | 547 it("Language only", () => |
| 566 let notification = {message: {"en-US": "en-US"}}; | 548 { |
| 567 Utils.appLocale = "fr"; | 549 let notification = {message: {fr: "fr"}}; |
| 568 let texts = Notification.getLocalizedTexts(notification); | 550 Utils.appLocale = "fr"; |
| 569 test.equal(texts.message, "en-US"); | 551 let texts = Notification.getLocalizedTexts(notification); |
| 570 test.done(); | 552 assert.equal(texts.message, "fr"); |
| 571 }; | 553 Utils.appLocale = "fr-CA"; |
| 554 texts = Notification.getLocalizedTexts(notification); |
| 555 assert.equal(texts.message, "fr"); |
| 556 }); |
| 557 |
| 558 it("Language and Country", () => |
| 559 { |
| 560 let notification = {message: {"fr": "fr", "fr-CA": "fr-CA"}}; |
| 561 Utils.appLocale = "fr-CA"; |
| 562 let texts = Notification.getLocalizedTexts(notification); |
| 563 assert.equal(texts.message, "fr-CA"); |
| 564 Utils.appLocale = "fr"; |
| 565 texts = Notification.getLocalizedTexts(notification); |
| 566 assert.equal(texts.message, "fr"); |
| 567 }); |
| 568 |
| 569 it("Missing translation", () => |
| 570 { |
| 571 let notification = {message: {"en-US": "en-US"}}; |
| 572 Utils.appLocale = "fr"; |
| 573 let texts = Notification.getLocalizedTexts(notification); |
| 574 assert.equal(texts.message, "en-US"); |
| 575 }); |
| 576 }); |
| OLD | NEW |