| OLD | NEW |
| 1 (function() | 1 /* |
| 2 { | 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
| 3 let testRunner = null; | 3 * Copyright (C) 2006-2016 Eyeo GmbH |
| 4 let randomResult = 0.5; | 4 * |
| 5 | 5 * Adblock Plus is free software: you can redistribute it and/or modify |
| 6 let originalInfo; | 6 * it under the terms of the GNU General Public License version 3 as |
| 7 let info = require("info"); | 7 * published by the Free Software Foundation. |
| 8 | 8 * |
| 9 function showNotifications(url) | 9 * Adblock Plus is distributed in the hope that it will be useful, |
| 10 { | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 let shownNotifications = []; | 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 function showListener(notification) | 12 * GNU General Public License for more details. |
| 13 { | 13 * |
| 14 shownNotifications.push(notification); | 14 * You should have received a copy of the GNU General Public License |
| 15 Notification.markAsShown(notification.id); | 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
| 16 } | 16 */ |
| 17 Notification.addShowListener(showListener); | 17 |
| 18 Notification.showNext(url); | 18 "use strict"; |
| 19 Notification.removeShowListener(showListener); | 19 |
| 20 return shownNotifications; | 20 let { |
| 21 createSandbox, setupTimerAndXMLHttp, setupRandomResult, unexpectedError, Cr |
| 22 } = require("./_common"); |
| 23 |
| 24 let info = null; |
| 25 let Prefs = null; |
| 26 let Notification = null; |
| 27 |
| 28 exports.setUp = function(callback) |
| 29 { |
| 30 // Inject our Array and JSON to make sure that instanceof checks on arrays |
| 31 // within the sandbox succeed even with data passed in from outside. |
| 32 let globals = Object.assign({Array, JSON}, |
| 33 setupTimerAndXMLHttp.call(this), setupRandomResult.call(this)); |
| 34 |
| 35 let sandboxedRequire = createSandbox({globals}); |
| 36 ( |
| 37 info = sandboxedRequire("./stub-modules/info"), |
| 38 {Prefs} = sandboxedRequire("./stub-modules/prefs"), |
| 39 {Notification} = sandboxedRequire("../lib/notification") |
| 40 ); |
| 41 |
| 42 callback(); |
| 43 }; |
| 44 |
| 45 function showNotifications(url) |
| 46 { |
| 47 let shownNotifications = []; |
| 48 function showListener(notification) |
| 49 { |
| 50 shownNotifications.push(notification); |
| 51 Notification.markAsShown(notification.id); |
| 21 } | 52 } |
| 22 | 53 Notification.addShowListener(showListener); |
| 23 module("Notification handling", | 54 Notification.showNext(url); |
| 24 { | 55 Notification.removeShowListener(showListener); |
| 25 setup: function() | 56 return shownNotifications; |
| 26 { | 57 } |
| 27 testRunner = this; | 58 |
| 28 | 59 function* pairs(array) |
| 29 preparePrefs.call(this); | 60 { |
| 30 setupVirtualTime.call(this, function(wrapTimer) | 61 for (let element1 of array) |
| 31 { | 62 for (let element2 of array) |
| 32 let NotificationModule = getModuleGlobal("notification"); | 63 if (element1 != element2) |
| 33 NotificationModule.downloader._timer = wrapTimer(NotificationModule.down
loader._timer); | 64 yield [element1, element2]; |
| 34 }, "notification", "downloader"); | 65 } |
| 35 setupVirtualXMLHttp.call(this, "notification", "downloader"); | 66 |
| 36 | 67 function registerHandler(notifications, checkCallback) |
| 37 originalInfo = {}; | 68 { |
| 38 for (let key in info) | 69 this.registerHandler("/notification.json", metadata => |
| 39 originalInfo[key] = info[key]; | 70 { |
| 40 | 71 if (checkCallback) |
| 41 info.addonName = "adblockpluschrome"; | 72 checkCallback(metadata); |
| 42 info.addonVersion = "1.4.1"; | 73 |
| 43 info.application = "chrome"; | 74 let notification = { |
| 44 info.applicationVersion = "27.0"; | 75 version: 55, |
| 45 info.platform = "chromium"; | 76 notifications |
| 46 info.platformVersion = "12.0"; | 77 }; |
| 47 | 78 |
| 48 Prefs.notificationurl = "http://example.com/notification.json"; | 79 return [Cr.NS_OK, 200, JSON.stringify(notification)]; |
| 49 Prefs.notificationdata = {}; | |
| 50 Prefs.notifications_ignoredcategories = []; | |
| 51 | |
| 52 // Replace Math.random() function | |
| 53 let DownloaderGlobal = Cu.getGlobalForObject(getModuleGlobal("downloader")
); | |
| 54 this._origRandom = DownloaderGlobal.Math.random; | |
| 55 DownloaderGlobal.Math.random = () => randomResult; | |
| 56 randomResult = 0.5; | |
| 57 | |
| 58 let NotificationGlobal = getModuleGlobal("notification"); | |
| 59 this._origShowListeners = NotificationGlobal.showListeners; | |
| 60 NotificationGlobal.showListeners = []; | |
| 61 }, | |
| 62 | |
| 63 teardown: function() | |
| 64 { | |
| 65 restorePrefs.call(this); | |
| 66 restoreVirtualTime.call(this); | |
| 67 restoreVirtualXMLHttp.call(this); | |
| 68 | |
| 69 for (let key in originalInfo) | |
| 70 info[key] = originalInfo[key]; | |
| 71 | |
| 72 if (this._origRandom) | |
| 73 { | |
| 74 let DownloaderGlobal = Cu.getGlobalForObject(getModuleGlobal("downloader
")); | |
| 75 DownloaderGlobal.Math.random = this._origRandom; | |
| 76 delete this._origRandom; | |
| 77 } | |
| 78 | |
| 79 if (this._origShowListeners) | |
| 80 { | |
| 81 let NotificationGlobal = getModuleGlobal("notification"); | |
| 82 NotificationGlobal.showListeners = this._origShowListeners; | |
| 83 delete this._origShowListeners; | |
| 84 } | |
| 85 | |
| 86 Notification.init(); | |
| 87 } | |
| 88 }); | 80 }); |
| 89 | 81 } |
| 90 function registerHandler(notifications, checkCallback) | 82 |
| 91 { | 83 exports.testNoData = function(test) |
| 92 testRunner.registerHandler("/notification.json", function(metadata) | 84 { |
| 93 { | 85 test.deepEqual(showNotifications(), [], "No notifications should be returned i
f there is no data"); |
| 94 if (checkCallback) | 86 test.done(); |
| 95 checkCallback(metadata); | 87 }; |
| 96 | 88 |
| 97 let notification = { | 89 exports.testSingleNotification = function(test) |
| 98 version: 55, | 90 { |
| 99 notifications: notifications | 91 let information = { |
| 100 }; | 92 id: 1, |
| 101 | 93 type: "information", |
| 102 return [Cr.NS_OK, 200, JSON.stringify(notification)]; | 94 message: {"en-US": "Information"} |
| 103 }); | 95 }; |
| 104 } | 96 |
| 105 | 97 registerHandler.call(this, [information]); |
| 106 function fixConstructors(object) | 98 this.runScheduledTasks(1).then(() => |
| 107 { | 99 { |
| 108 // deepEqual() expects that the constructors used in expected objects and | 100 test.deepEqual(showNotifications(), [information], "The notification is show
n"); |
| 109 // the ones in the actual results are the same. That means that we actually | 101 test.deepEqual(showNotifications(), [], "Informational notifications aren't
shown more than once"); |
| 110 // have to construct our objects in the context of the notification module. | 102 }).catch(unexpectedError.bind(test)).then(() => test.done()); |
| 111 let JSON = Cu.getGlobalForObject(Notification).JSON; | 103 }; |
| 112 return JSON.parse(JSON.stringify(object)); | 104 |
| 113 } | 105 exports.testInformationAndCritical = function(test) |
| 114 | 106 { |
| 115 test("No data", function() | 107 let information = { |
| 116 { | 108 id: 1, |
| 117 deepEqual(showNotifications(), [], "No notifications should be returned if t
here is no data"); | 109 type: "information", |
| 118 }); | 110 message: {"en-US": "Information"} |
| 119 | 111 }; |
| 120 test("Single notification", function() | 112 let critical = { |
| 121 { | 113 id: 2, |
| 122 let information = fixConstructors({ | 114 type: "critical", |
| 115 message: {"en-US": "Critical"} |
| 116 }; |
| 117 |
| 118 registerHandler.call(this, [information, critical]); |
| 119 this.runScheduledTasks(1).then(() => |
| 120 { |
| 121 test.deepEqual(showNotifications(), [critical], "The critical notification i
s given priority"); |
| 122 test.deepEqual(showNotifications(), [critical], "Critical notifications can
be shown multiple times"); |
| 123 }).catch(unexpectedError.bind(test)).then(() => test.done()); |
| 124 }; |
| 125 |
| 126 exports.testNoType = function(test) |
| 127 { |
| 128 let information = { |
| 129 id: 1, |
| 130 message: {"en-US": "Information"} |
| 131 }; |
| 132 |
| 133 registerHandler.call(this, [information]); |
| 134 this.runScheduledTasks(1).then(() => |
| 135 { |
| 136 test.deepEqual(showNotifications(), [information], "The notification is show
n"); |
| 137 test.deepEqual(showNotifications(), [], "Notification is treated as type inf
ormation"); |
| 138 }).catch(unexpectedError.bind(test)).then(() => test.done()); |
| 139 }; |
| 140 |
| 141 exports.testTargetSelection = {}; |
| 142 |
| 143 for (let [propName, value, result] of [ |
| 144 ["extension", "adblockpluschrome", true], |
| 145 ["extension", "adblockplus", false], |
| 146 ["extension", "adblockpluschrome2", false], |
| 147 ["extensionMinVersion", "1.4", true], |
| 148 ["extensionMinVersion", "1.4.1", true], |
| 149 ["extensionMinVersion", "1.5", false], |
| 150 ["extensionMaxVersion", "1.5", true], |
| 151 ["extensionMaxVersion", "1.4.1", true], |
| 152 ["extensionMaxVersion", "1.4.*", true], |
| 153 ["extensionMaxVersion", "1.4", false], |
| 154 ["application", "chrome", true], |
| 155 ["application", "firefox", false], |
| 156 ["applicationMinVersion", "27.0", true], |
| 157 ["applicationMinVersion", "27", true], |
| 158 ["applicationMinVersion", "26", true], |
| 159 ["applicationMinVersion", "28", false], |
| 160 ["applicationMinVersion", "27.1", false], |
| 161 ["applicationMaxVersion", "27.0", true], |
| 162 ["applicationMaxVersion", "27", true], |
| 163 ["applicationMaxVersion", "28", true], |
| 164 ["applicationMaxVersion", "26", false], |
| 165 ["platform", "chromium", true], |
| 166 ["platform", "gecko", false], |
| 167 ["platformMinVersion", "12.0", true], |
| 168 ["platformMinVersion", "12", true], |
| 169 ["platformMinVersion", "11", true], |
| 170 ["platformMinVersion", "13", false], |
| 171 ["platformMinVersion", "12.1", false], |
| 172 ["platformMaxVersion", "12.0", true], |
| 173 ["platformMaxVersion", "12", true], |
| 174 ["platformMaxVersion", "13", true], |
| 175 ["platformMaxVersion", "11", false], |
| 176 ]) |
| 177 { |
| 178 exports.testTargetSelection[`${propName}=${value}`] = function(test) |
| 179 { |
| 180 let targetInfo = {}; |
| 181 targetInfo[propName] = value; |
| 182 |
| 183 let information = { |
| 123 id: 1, | 184 id: 1, |
| 124 type: "information", | 185 type: "information", |
| 125 message: {"en-US": "Information"} | 186 message: {"en-US": "Information"}, |
| 126 }); | 187 targets: [targetInfo] |
| 127 | 188 }; |
| 128 registerHandler([information]); | 189 |
| 129 testRunner.runScheduledTasks(1); | 190 registerHandler.call(this, [information]); |
| 130 | 191 this.runScheduledTasks(1).then(() => |
| 131 deepEqual(showNotifications(), [information], "The notification is shown"); | 192 { |
| 132 deepEqual(showNotifications(), [], "Informational notifications aren't shown
more than once"); | 193 let expected = (result ? [information] : []); |
| 133 }); | 194 test.deepEqual(showNotifications(), expected, "Selected notification for "
+ JSON.stringify(information.targets)); |
| 134 | 195 test.deepEqual(showNotifications(), [], "No notification on second call"); |
| 135 test("Information and critical", function() | 196 }).catch(unexpectedError.bind(test)).then(() => test.done()); |
| 136 { | 197 }; |
| 137 let information = fixConstructors({ | 198 } |
| 199 |
| 200 exports.testMultipleTargets = {}; |
| 201 |
| 202 for (let [[propName1, value1, result1], [propName2, value2, result2]] of pairs([ |
| 203 ["extension", "adblockpluschrome", true], |
| 204 ["extension", "adblockplus", false], |
| 205 ["extensionMinVersion", "1.4", true], |
| 206 ["extensionMinVersion", "1.5", false], |
| 207 ["application", "chrome", true], |
| 208 ["application", "firefox", false], |
| 209 ["applicationMinVersion", "27", true], |
| 210 ["applicationMinVersion", "28", false], |
| 211 ["platform", "chromium", true], |
| 212 ["platform", "gecko", false], |
| 213 ["platformMinVersion", "12", true], |
| 214 ["platformMinVersion", "13", false], |
| 215 ])) |
| 216 { |
| 217 exports.testMultipleTargets[`${propName1}=${value1},${propName2}=${value2}`] =
function(test) |
| 218 { |
| 219 let targetInfo1 = {}; |
| 220 targetInfo1[propName1] = value1; |
| 221 let targetInfo2 = {}; |
| 222 targetInfo2[propName2] = value2; |
| 223 |
| 224 let information = { |
| 138 id: 1, | 225 id: 1, |
| 139 type: "information", | 226 type: "information", |
| 140 message: {"en-US": "Information"} | 227 message: {"en-US": "Information"}, |
| 141 }); | 228 targets: [targetInfo1, targetInfo2] |
| 142 let critical = fixConstructors({ | 229 }; |
| 143 id: 2, | 230 |
| 144 type: "critical", | 231 registerHandler.call(this, [information]); |
| 145 message: {"en-US": "Critical"} | 232 this.runScheduledTasks(1).then(() => |
| 146 }); | 233 { |
| 147 | 234 let expected = (result1 || result2 ? [information] : []) |
| 148 registerHandler([information, critical]); | 235 test.deepEqual(showNotifications(), expected, "Selected notification for "
+ JSON.stringify(information.targets)); |
| 149 testRunner.runScheduledTasks(1); | 236 }).catch(unexpectedError.bind(test)).then(() => test.done()); |
| 150 | 237 } |
| 151 deepEqual(showNotifications(), [critical], "The critical notification is giv
en priority"); | 238 } |
| 152 deepEqual(showNotifications(), [critical], "Critical notifications can be sh
own multiple times"); | 239 |
| 240 exports.testParametersSent = function(test) |
| 241 { |
| 242 Prefs.notificationdata = { |
| 243 data: { |
| 244 version: "3" |
| 245 }, |
| 246 }; |
| 247 |
| 248 let parameters = null; |
| 249 registerHandler.call(this, [], function(metadata) |
| 250 { |
| 251 parameters = decodeURI(metadata.queryString); |
| 153 }); | 252 }); |
| 154 | 253 this.runScheduledTasks(1).then(() => |
| 155 test("No type", function() | 254 { |
| 156 { | 255 test.equal(parameters, |
| 157 let information = fixConstructors({ | |
| 158 id: 1, | |
| 159 message: {"en-US": "Information"} | |
| 160 }); | |
| 161 | |
| 162 registerHandler([information]); | |
| 163 testRunner.runScheduledTasks(1); | |
| 164 | |
| 165 deepEqual(showNotifications(), [information], "The notification is shown"); | |
| 166 deepEqual(showNotifications(), [], "Notification is treated as type informat
ion"); | |
| 167 }); | |
| 168 | |
| 169 test("Target selection", function() | |
| 170 { | |
| 171 let targets = [ | |
| 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 ["applicationMaxVersion", "27.0", true], | |
| 190 ["applicationMaxVersion", "27", true], | |
| 191 ["applicationMaxVersion", "28", true], | |
| 192 ["applicationMaxVersion", "26", false], | |
| 193 ["platform", "chromium", true], | |
| 194 ["platform", "gecko", false], | |
| 195 ["platformMinVersion", "12.0", true], | |
| 196 ["platformMinVersion", "12", true], | |
| 197 ["platformMinVersion", "11", true], | |
| 198 ["platformMinVersion", "13", false], | |
| 199 ["platformMinVersion", "12.1", false], | |
| 200 ["platformMaxVersion", "12.0", true], | |
| 201 ["platformMaxVersion", "12", true], | |
| 202 ["platformMaxVersion", "13", true], | |
| 203 ["platformMaxVersion", "11", false], | |
| 204 ]; | |
| 205 | |
| 206 for (let [propName, value, result] of targets) | |
| 207 { | |
| 208 let targetInfo = {}; | |
| 209 targetInfo[propName] = value; | |
| 210 | |
| 211 let information = fixConstructors({ | |
| 212 id: 1, | |
| 213 type: "information", | |
| 214 message: {"en-US": "Information"}, | |
| 215 targets: [targetInfo] | |
| 216 }); | |
| 217 | |
| 218 Prefs.notificationdata = {}; | |
| 219 registerHandler([information]); | |
| 220 testRunner.runScheduledTasks(1); | |
| 221 | |
| 222 let expected = (result ? [information] : []); | |
| 223 deepEqual(showNotifications(), expected, "Selected notification for " + JS
ON.stringify(information.targets)); | |
| 224 deepEqual(showNotifications(), [], "No notification on second call"); | |
| 225 } | |
| 226 }); | |
| 227 | |
| 228 test("Multiple targets", function() | |
| 229 { | |
| 230 let targets = [ | |
| 231 ["extension", "adblockpluschrome", true], | |
| 232 ["extension", "adblockplus", false], | |
| 233 ["extensionMinVersion", "1.4", true], | |
| 234 ["extensionMinVersion", "1.5", false], | |
| 235 ["application", "chrome", true], | |
| 236 ["application", "firefox", false], | |
| 237 ["applicationMinVersion", "27", true], | |
| 238 ["applicationMinVersion", "28", false], | |
| 239 ["platform", "chromium", true], | |
| 240 ["platform", "gecko", false], | |
| 241 ["platformMinVersion", "12", true], | |
| 242 ["platformMinVersion", "13", false], | |
| 243 ]; | |
| 244 | |
| 245 function pairs(array) | |
| 246 { | |
| 247 for (let element1 of array) | |
| 248 for (let element2 of array) | |
| 249 if (element1 != element2) | |
| 250 yield [element1, element2]; | |
| 251 } | |
| 252 | |
| 253 for (let [[propName1, value1, result1], [propName2, value2, result2]] in pai
rs(targets)) | |
| 254 { | |
| 255 let targetInfo1 = {}; | |
| 256 targetInfo1[propName1] = value1; | |
| 257 let targetInfo2 = {}; | |
| 258 targetInfo2[propName2] = value2; | |
| 259 | |
| 260 let information = fixConstructors({ | |
| 261 id: 1, | |
| 262 type: "information", | |
| 263 message: {"en-US": "Information"}, | |
| 264 targets: [targetInfo1, targetInfo2] | |
| 265 }); | |
| 266 | |
| 267 Prefs.notificationdata = {}; | |
| 268 registerHandler([information]); | |
| 269 testRunner.runScheduledTasks(1); | |
| 270 | |
| 271 let expected = (result1 || result2 ? [information] : []) | |
| 272 deepEqual(showNotifications(), expected, "Selected notification for " + JS
ON.stringify(information.targets)); | |
| 273 } | |
| 274 }); | |
| 275 | |
| 276 test("Parameters sent", function() | |
| 277 { | |
| 278 Prefs.notificationdata = { | |
| 279 data: { | |
| 280 version: "3" | |
| 281 }, | |
| 282 }; | |
| 283 | |
| 284 let parameters = null; | |
| 285 registerHandler([], function(metadata) | |
| 286 { | |
| 287 parameters = decodeURI(metadata.queryString); | |
| 288 }); | |
| 289 testRunner.runScheduledTasks(1); | |
| 290 | |
| 291 equal(parameters, | |
| 292 "addonName=adblockpluschrome&addonVersion=1.4.1&application=chrome&app
licationVersion=27.0&platform=chromium&platformVersion=12.0&lastVersion=3&downlo
adCount=0", | 256 "addonName=adblockpluschrome&addonVersion=1.4.1&application=chrome&app
licationVersion=27.0&platform=chromium&platformVersion=12.0&lastVersion=3&downlo
adCount=0", |
| 293 "The correct parameters are sent to the server"); | 257 "The correct parameters are sent to the server"); |
| 258 }).catch(unexpectedError.bind(test)).then(() => test.done()); |
| 259 }; |
| 260 |
| 261 exports.testExpirationInterval = {}; |
| 262 |
| 263 let initialDelay = 1 / 60; |
| 264 for (let currentTest of [ |
| 265 { |
| 266 randomResult: 0.5, |
| 267 requests: [initialDelay, initialDelay + 24, initialDelay + 48] |
| 268 }, |
| 269 { |
| 270 randomResult: 0, // Changes interval by factor 0.8 (19.2 hours) |
| 271 requests: [initialDelay, initialDelay + 20, initialDelay + 40] |
| 272 }, |
| 273 { |
| 274 randomResult: 1, // Changes interval by factor 1.2 (28.8 hours) |
| 275 requests: [initialDelay, initialDelay + 29, initialDelay + 58] |
| 276 }, |
| 277 { |
| 278 randomResult: 0.25, // Changes interval by factor 0.9 (21.6 hours) |
| 279 requests: [initialDelay, initialDelay + 22, initialDelay + 44] |
| 280 }, |
| 281 { |
| 282 randomResult: 0.5, |
| 283 skipAfter: initialDelay + 5, |
| 284 skip: 10, // Short break should not increase soft expiration |
| 285 requests: [initialDelay, initialDelay + 24] |
| 286 }, |
| 287 { |
| 288 randomResult: 0.5, |
| 289 skipAfter: initialDelay + 5, |
| 290 skip: 30, // Long break should increase soft expiration, hitti
ng hard expiration |
| 291 requests: [initialDelay, initialDelay + 48] |
| 292 } |
| 293 ]) |
| 294 { |
| 295 let testId = "Math.random() returning " + currentTest.randomResult; |
| 296 if (typeof currentTest.skip != "number") |
| 297 testId += " skipping " + currentTest.skip + " hours after " + currentTest.sk
ipAfter + " hours"; |
| 298 exports.testExpirationInterval[testId] = function(test) |
| 299 { |
| 300 let requests = []; |
| 301 registerHandler.call(this, [], metadata => requests.push(this.getTimeOffset(
))); |
| 302 |
| 303 this.randomResult = currentTest.randomResult; |
| 304 |
| 305 let maxHours = Math.round(Math.max.apply(null, currentTest.requests)) + 1; |
| 306 this.runScheduledTasks(maxHours, currentTest.skipAfter, currentTest.skip).th
en(() => |
| 307 { |
| 308 test.deepEqual(requests, currentTest.requests, "Requests"); |
| 309 }).catch(unexpectedError.bind(test)).then(() => test.done()); |
| 310 }; |
| 311 } |
| 312 |
| 313 exports.testUsingSeverityInsteadOfType = function(test) |
| 314 { |
| 315 let severityNotification = { |
| 316 id: 1, |
| 317 severity: "information", |
| 318 message: {"en-US": "Information"} |
| 319 }; |
| 320 |
| 321 function listener(name) |
| 322 { |
| 323 if (name !== "notificationdata") |
| 324 return; |
| 325 |
| 326 Prefs.removeListener(listener); |
| 327 let notification = Prefs.notificationdata.data.notifications[0]; |
| 328 test.ok(!("severity" in notification), "Severity property was removed"); |
| 329 test.ok("type" in notification, "Type property was added"); |
| 330 test.equal(notification.type, severityNotification.severity, "Type property
has correct value"); |
| 331 test.done(); |
| 332 } |
| 333 Prefs.addListener(listener); |
| 334 |
| 335 let responseText = JSON.stringify({ |
| 336 notifications: [severityNotification] |
| 294 }); | 337 }); |
| 295 | 338 Notification._onDownloadSuccess({}, responseText, function() {}, function() {}
); |
| 296 test("Expiration interval", function() | 339 }; |
| 297 { | 340 |
| 298 let initialDelay = 1 / 60; | 341 exports.testURLSpecificNotification = function(test) |
| 299 let tests = [ | 342 { |
| 300 { | 343 let withURLFilterFoo = { |
| 301 randomResult: 0.5, | 344 id: 1, |
| 302 requests: [initialDelay, initialDelay + 24, initialDelay + 48] | 345 urlFilters: ["foo.com$document"] |
| 303 }, | 346 }; |
| 304 { | 347 let withoutURLFilter = { |
| 305 randomResult: 0, // Changes interval by factor 0.8 (19.2 hours) | 348 id: 2 |
| 306 requests: [initialDelay, initialDelay + 20, initialDelay + 40] | 349 }; |
| 307 }, | 350 let withURLFilterBar = { |
| 308 { | 351 id: 3, |
| 309 randomResult: 1, // Changes interval by factor 1.2 (28.8 hours) | 352 urlFilters: ["bar.com$document"] |
| 310 requests: [initialDelay, initialDelay + 29, initialDelay + 58] | 353 }; |
| 311 }, | 354 let subdomainURLFilter = { |
| 312 { | 355 id: 4, |
| 313 randomResult: 0.25, // Changes interval by factor 0.9 (21.6 hours) | 356 urlFilters: ["||example.com$document"] |
| 314 requests: [initialDelay, initialDelay + 22, initialDelay + 44] | 357 }; |
| 315 }, | 358 |
| 316 { | 359 registerHandler.call(this, [ |
| 317 randomResult: 0.5, | 360 withURLFilterFoo, |
| 318 skipAfter: initialDelay + 5, | 361 withoutURLFilter, |
| 319 skip: 10, // Short break should not increase soft expirati
on | 362 withURLFilterBar, |
| 320 requests: [initialDelay, initialDelay + 24] | 363 subdomainURLFilter |
| 321 }, | 364 ]); |
| 322 { | 365 this.runScheduledTasks(1).then(() => |
| 323 randomResult: 0.5, | 366 { |
| 324 skipAfter: initialDelay + 5, | 367 test.deepEqual(showNotifications(), [withoutURLFilter], "URL-specific notifi
cations are skipped"); |
| 325 skip: 30, // Long break should increase soft expiration, h
itting hard expiration | 368 test.deepEqual(showNotifications("http://foo.com"), [withURLFilterFoo], "URL
-specific notification is retrieved"); |
| 326 requests: [initialDelay, initialDelay + 48] | 369 test.deepEqual(showNotifications("http://foo.com"), [], "URL-specific notifi
cation is not retrieved"); |
| 327 } | 370 test.deepEqual(showNotifications("http://www.example.com"), [subdomainURLFil
ter], "URL-specific notification matches subdomain"); |
| 328 ]; | 371 }).catch(unexpectedError.bind(test)).then(() => test.done()); |
| 329 | 372 }; |
| 330 let requests = []; | 373 |
| 331 registerHandler([], (metadata) => requests.push(testRunner.getTimeOffset()))
; | 374 exports.testGlobalOptOut = function(test) |
| 332 for (let test of tests) | 375 { |
| 333 { | 376 Notification.toggleIgnoreCategory("*", true); |
| 334 Prefs.notificationdata = {}; | 377 test.ok(Prefs.notifications_ignoredcategories.indexOf("*") != -1, "Force enabl
e global opt-out"); |
| 335 requests = []; | 378 Notification.toggleIgnoreCategory("*", true); |
| 336 randomResult = test.randomResult; | 379 test.ok(Prefs.notifications_ignoredcategories.indexOf("*") != -1, "Force enabl
e global opt-out (again)"); |
| 337 | 380 Notification.toggleIgnoreCategory("*", false); |
| 338 let maxHours = Math.round(Math.max.apply(null, test.requests)) + 1; | 381 test.ok(Prefs.notifications_ignoredcategories.indexOf("*") == -1, "Force disab
le global opt-out"); |
| 339 testRunner.runScheduledTasks(maxHours, test.skipAfter, test.skip); | 382 Notification.toggleIgnoreCategory("*", false); |
| 340 | 383 test.ok(Prefs.notifications_ignoredcategories.indexOf("*") == -1, "Force disab
le global opt-out (again)"); |
| 341 let skipAddendum = (typeof test.skip != "number" ? "" : " skipping " + tes
t.skip + " hours after " + test.skipAfter + " hours"); | 384 Notification.toggleIgnoreCategory("*"); |
| 342 deepEqual(requests, test.requests, "Requests with Math.random() returning
" + randomResult + skipAddendum); | 385 test.ok(Prefs.notifications_ignoredcategories.indexOf("*") != -1, "Toggle enab
le global opt-out"); |
| 343 } | 386 Notification.toggleIgnoreCategory("*"); |
| 344 }); | 387 test.ok(Prefs.notifications_ignoredcategories.indexOf("*") == -1, "Toggle disa
ble global opt-out"); |
| 345 | 388 |
| 346 test("Uses severity instead of type", 3, function() | 389 Prefs.notifications_showui = false; |
| 347 { | 390 Notification.toggleIgnoreCategory("*", false); |
| 348 let severityNotification = { | 391 test.ok(!Prefs.notifications_showui, "Opt-out UI will not be shown if global o
pt-out hasn't been enabled yet"); |
| 349 id: 1, | 392 Notification.toggleIgnoreCategory("*", true); |
| 350 severity: "information", | 393 test.ok(Prefs.notifications_showui, "Opt-out UI will be shown after enabling g
lobal opt-out"); |
| 351 message: {"en-US": "Information"} | 394 Notification.toggleIgnoreCategory("*", false); |
| 352 }; | 395 test.ok(Prefs.notifications_showui, "Opt-out UI will be shown after enabling g
lobal opt-out even if it got disabled again"); |
| 353 | 396 |
| 354 function listener(name) | 397 let information = { |
| 355 { | 398 id: 1, |
| 356 if (name !== "notificationdata") | 399 type: "information" |
| 357 return; | 400 }; |
| 358 | 401 let critical = { |
| 359 Prefs.removeListener(listener); | 402 id: 2, |
| 360 let notification = Prefs.notificationdata.data.notifications[0]; | 403 type: "critical" |
| 361 ok(!("severity" in notification), "Severity property was removed"); | 404 }; |
| 362 ok("type" in notification, "Type property was added"); | 405 |
| 363 equal(notification.type, severityNotification.severity, "Type property has
correct value"); | 406 Notification.toggleIgnoreCategory("*", true); |
| 364 } | 407 registerHandler.call(this, [information]); |
| 365 Prefs.addListener(listener); | 408 this.runScheduledTasks(1).then(() => |
| 366 | 409 { |
| 367 let responseText = JSON.stringify({ | 410 test.deepEqual(showNotifications(), [], "Information notifications are ignor
ed after enabling global opt-out"); |
| 368 notifications: [severityNotification] | |
| 369 }); | |
| 370 Notification._onDownloadSuccess({}, responseText, function() {}, function()
{}); | |
| 371 }); | |
| 372 | |
| 373 test("URL-specific notification", function() | |
| 374 { | |
| 375 let withURLFilterFoo = fixConstructors({ | |
| 376 id: 1, | |
| 377 urlFilters: ["foo.com$document"] | |
| 378 }); | |
| 379 let withoutURLFilter = fixConstructors({ | |
| 380 id: 2 | |
| 381 }); | |
| 382 let withURLFilterBar = fixConstructors({ | |
| 383 id: 3, | |
| 384 urlFilters: ["bar.com$document"] | |
| 385 }); | |
| 386 let subdomainURLFilter = fixConstructors({ | |
| 387 id: 4, | |
| 388 urlFilters: ["||example.com$document"] | |
| 389 }); | |
| 390 | |
| 391 registerHandler([ | |
| 392 withURLFilterFoo, | |
| 393 withoutURLFilter, | |
| 394 withURLFilterBar, | |
| 395 subdomainURLFilter | |
| 396 ]); | |
| 397 testRunner.runScheduledTasks(1); | |
| 398 | |
| 399 deepEqual(showNotifications(), [withoutURLFilter], "URL-specific notificatio
ns are skipped"); | |
| 400 deepEqual(showNotifications("http://foo.com"), [withURLFilterFoo], "URL-spec
ific notification is retrieved"); | |
| 401 deepEqual(showNotifications("http://foo.com"), [], "URL-specific notificatio
n is not retrieved"); | |
| 402 deepEqual(showNotifications("http://www.example.com"), [subdomainURLFilter],
"URL-specific notification matches subdomain"); | |
| 403 }); | |
| 404 | |
| 405 test("Global opt-out", function() | |
| 406 { | |
| 407 Notification.toggleIgnoreCategory("*", true); | |
| 408 ok(Prefs.notifications_ignoredcategories.indexOf("*") != -1, "Force enable g
lobal opt-out"); | |
| 409 Notification.toggleIgnoreCategory("*", true); | |
| 410 ok(Prefs.notifications_ignoredcategories.indexOf("*") != -1, "Force enable g
lobal opt-out (again)"); | |
| 411 Notification.toggleIgnoreCategory("*", false); | 411 Notification.toggleIgnoreCategory("*", false); |
| 412 ok(Prefs.notifications_ignoredcategories.indexOf("*") == -1, "Force disable
global opt-out"); | 412 test.deepEqual(showNotifications(), [information], "Information notification
s are shown after disabling global opt-out"); |
| 413 Notification.toggleIgnoreCategory("*", false); | |
| 414 ok(Prefs.notifications_ignoredcategories.indexOf("*") == -1, "Force disable
global opt-out (again)"); | |
| 415 Notification.toggleIgnoreCategory("*"); | |
| 416 ok(Prefs.notifications_ignoredcategories.indexOf("*") != -1, "Toggle enable
global opt-out"); | |
| 417 Notification.toggleIgnoreCategory("*"); | |
| 418 ok(Prefs.notifications_ignoredcategories.indexOf("*") == -1, "Toggle disable
global opt-out"); | |
| 419 | |
| 420 Prefs.notifications_showui = false; | |
| 421 Notification.toggleIgnoreCategory("*", false); | |
| 422 ok(!Prefs.notifications_showui, "Opt-out UI will not be shown if global opt-
out hasn't been enabled yet"); | |
| 423 Notification.toggleIgnoreCategory("*", true); | |
| 424 ok(Prefs.notifications_showui, "Opt-out UI will be shown after enabling glob
al opt-out"); | |
| 425 Notification.toggleIgnoreCategory("*", false); | |
| 426 ok(Prefs.notifications_showui, "Opt-out UI will be shown after enabling glob
al opt-out even if it got disabled again"); | |
| 427 | |
| 428 let information = fixConstructors({ | |
| 429 id: 1, | |
| 430 type: "information" | |
| 431 }); | |
| 432 let critical = fixConstructors({ | |
| 433 id: 2, | |
| 434 type: "critical" | |
| 435 }); | |
| 436 | |
| 437 Notification.toggleIgnoreCategory("*", true); | |
| 438 registerHandler([information]); | |
| 439 testRunner.runScheduledTasks(1); | |
| 440 | |
| 441 deepEqual(showNotifications(), [], "Information notifications are ignored af
ter enabling global opt-out"); | |
| 442 Notification.toggleIgnoreCategory("*", false); | |
| 443 deepEqual(showNotifications(), [information], "Information notifications are
shown after disabling global opt-out"); | |
| 444 | 413 |
| 445 Notification.toggleIgnoreCategory("*", true); | 414 Notification.toggleIgnoreCategory("*", true); |
| 446 Prefs.notificationdata = {}; | 415 Prefs.notificationdata = {}; |
| 447 registerHandler([critical]); | 416 registerHandler.call(this, [critical]); |
| 448 testRunner.runScheduledTasks(1); | 417 return this.runScheduledTasks(1); |
| 449 | 418 }).then(() => |
| 450 deepEqual(showNotifications(), [critical], "Critical notifications are not i
gnored"); | 419 { |
| 451 }); | 420 test.deepEqual(showNotifications(), [critical], "Critical notifications are
not ignored"); |
| 452 | 421 }).catch(unexpectedError.bind(test)).then(() => test.done()); |
| 453 module("Notification localization"); | 422 }; |
| 454 | 423 |
| 455 test("Message without localization", function() | 424 exports.testMessageWithoutLocalization = function(test) |
| 456 { | 425 { |
| 457 let notification = {message: "non-localized"}; | 426 let notification = {message: "non-localized"}; |
| 458 let texts = Notification.getLocalizedTexts(notification, "en-US"); | 427 let texts = Notification.getLocalizedTexts(notification, "en-US"); |
| 459 equal(texts.message, "non-localized"); | 428 test.equal(texts.message, "non-localized"); |
| 460 }); | 429 test.done(); |
| 461 | 430 }; |
| 462 test("Language only", function() | 431 |
| 463 { | 432 exports.testLanguageOnly = function(test) |
| 464 let notification = {message: {fr: "fr"}}; | 433 { |
| 465 let texts = Notification.getLocalizedTexts(notification, "fr"); | 434 let notification = {message: {fr: "fr"}}; |
| 466 equal(texts.message, "fr"); | 435 let texts = Notification.getLocalizedTexts(notification, "fr"); |
| 467 texts = Notification.getLocalizedTexts(notification, "fr-CA"); | 436 test.equal(texts.message, "fr"); |
| 468 equal(texts.message, "fr"); | 437 texts = Notification.getLocalizedTexts(notification, "fr-CA"); |
| 469 }); | 438 test.equal(texts.message, "fr"); |
| 470 | 439 test.done(); |
| 471 test("Language and country", function() | 440 }; |
| 472 { | 441 |
| 473 let notification = {message: {fr: "fr", "fr-CA": "fr-CA"}}; | 442 exports.testLanguageAndCountry = function(test) |
| 474 let texts = Notification.getLocalizedTexts(notification, "fr-CA"); | 443 { |
| 475 equal(texts.message, "fr-CA"); | 444 let notification = {message: {fr: "fr", "fr-CA": "fr-CA"}}; |
| 476 texts = Notification.getLocalizedTexts(notification, "fr"); | 445 let texts = Notification.getLocalizedTexts(notification, "fr-CA"); |
| 477 equal(texts.message, "fr"); | 446 test.equal(texts.message, "fr-CA"); |
| 478 }); | 447 texts = Notification.getLocalizedTexts(notification, "fr"); |
| 479 | 448 test.equal(texts.message, "fr"); |
| 480 test("Missing translation", function() | 449 test.done(); |
| 481 { | 450 }; |
| 482 let notification = {message: {"en-US": "en-US"}}; | 451 |
| 483 let texts = Notification.getLocalizedTexts(notification, "fr"); | 452 exports.testMissingTranslation = function(test) |
| 484 equal(texts.message, "en-US"); | 453 { |
| 485 }); | 454 let notification = {message: {"en-US": "en-US"}}; |
| 486 })(); | 455 let texts = Notification.getLocalizedTexts(notification, "fr"); |
| 456 test.equal(texts.message, "en-US"); |
| 457 test.done(); |
| 458 }; |
| OLD | NEW |