OLD | NEW |
(Empty) | |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 /** |
| 6 * Test fixture for utility.js. |
| 7 * @constructor |
| 8 * @extends {testing.Test} |
| 9 */ |
| 10 function GoogleNowUtilityUnitTest () { |
| 11 testing.Test.call(this); |
| 12 } |
| 13 |
| 14 GoogleNowUtilityUnitTest.prototype = { |
| 15 __proto__: testing.Test.prototype, |
| 16 |
| 17 /** @override */ |
| 18 extraLibraries: [ |
| 19 'common_test_util.js', |
| 20 'utility_test_util.js', |
| 21 'utility.js' |
| 22 ] |
| 23 }; |
| 24 |
| 25 TEST_F('GoogleNowUtilityUnitTest', 'SendErrorReport1', function() { |
| 26 // Test sending report for an error with a message that can be sent to server. |
| 27 |
| 28 // Setup and expectations. |
| 29 var testStack = 'Error: TEST ERROR MESSAGE\n ' + |
| 30 'at buildErrorWithMessageForServer ' + |
| 31 '(chrome-extension://ext_id/utility.js:29:15)\n' + |
| 32 ' at <anonymous>:2:16\n ' + |
| 33 'at Object.InjectedScript._evaluateOn (<anonymous>:580:39)\n ' + |
| 34 'at Object.InjectedScript._evaluateAndWrap (<anonymous>:539:52)\n ' + |
| 35 'at Object.InjectedScript.evaluate (<anonymous>:458:21)'; |
| 36 |
| 37 var testError = { |
| 38 canSendMessageToServer: true, |
| 39 stack: testStack, |
| 40 name: 'TEST ERROR NAME' |
| 41 }; |
| 42 |
| 43 this.makeAndRegisterMockGlobals(['buildServerRequest']); |
| 44 this.makeMockLocalFunctions(['sendRequest']); |
| 45 |
| 46 var mockRequest = {send: this.mockLocalFunctions.functions().sendRequest}; |
| 47 |
| 48 var expectedRequestParameters = 'error=TEST%20ERROR%20NAME&' + |
| 49 'script=%2F%2Fext_id%2Futility.js&' + |
| 50 'line=29&' + |
| 51 'trace=Error%3A%20TEST%20ERROR%20MESSAGE%0A%20%20%20%20' + |
| 52 'at%20buildErrorWithMessageForServer%20' + |
| 53 '(chrome-extension%3A%2F%2Fext_id%2Futility.js%3A29%3A15)%0A' + |
| 54 '%20%20%20%20at%20%3Canonymous%3E%3A2%3A16%0A%20%20%20%20' + |
| 55 'at%20Object.InjectedScript._evaluateOn%20(%3Canonymous%3E%3A580%3A39)' + |
| 56 '%0A%20%20%20%20' + |
| 57 'at%20Object.InjectedScript._evaluateAndWrap%20(%3Canonymous%3E%3A539' + |
| 58 '%3A52)%0A%20%20%20%20' + |
| 59 'at%20Object.InjectedScript.evaluate%20(%3Canonymous%3E%3A458%3A21)'; |
| 60 |
| 61 this.mockGlobals.expects(once()). |
| 62 buildServerRequest('jserror', 'application/x-www-form-urlencoded'). |
| 63 will(returnValue(mockRequest)); |
| 64 this.mockLocalFunctions.expects(once()).sendRequest( |
| 65 expectedRequestParameters); |
| 66 |
| 67 // Invoking the tested function. |
| 68 sendErrorReport(testError); |
| 69 }); |
| 70 |
| 71 TEST_F('GoogleNowUtilityUnitTest', 'SendErrorReport2', function() { |
| 72 // Test sending report for an error with a message that should not be sent to |
| 73 // server, with an error generated in an anonymous function. |
| 74 |
| 75 // Setup and expectations. |
| 76 var testStack = 'TypeError: Property \'processPendingDismissals\' of ' + |
| 77 'object [object Object] is not a function\n ' + |
| 78 'at chrome-extension://ext_id/background.js:444:11\n ' + |
| 79 'at chrome-extension://ext_id/utility.js:509:7'; |
| 80 |
| 81 var testError = { |
| 82 stack: testStack, |
| 83 name: 'TypeError' |
| 84 }; |
| 85 |
| 86 this.makeAndRegisterMockGlobals(['buildServerRequest']); |
| 87 this.makeMockLocalFunctions(['sendRequest']); |
| 88 |
| 89 var mockRequest = {send: this.mockLocalFunctions.functions().sendRequest}; |
| 90 |
| 91 var expectedRequestParameters = 'error=TypeError&' + |
| 92 'script=%2F%2Fext_id%2Fbackground.js&' + |
| 93 'line=444&' + |
| 94 'trace=(message%20removed)%0A%20%20%20%20' + |
| 95 'at%20chrome-extension%3A%2F%2Fext_id%2Fbackground.js%3A444%3A11' + |
| 96 '%0A%20%20%20%20' + |
| 97 'at%20chrome-extension%3A%2F%2Fext_id%2Futility.js%3A509%3A7'; |
| 98 |
| 99 this.mockGlobals.expects(once()). |
| 100 buildServerRequest('jserror', 'application/x-www-form-urlencoded'). |
| 101 will(returnValue(mockRequest)); |
| 102 this.mockLocalFunctions.expects(once()).sendRequest( |
| 103 expectedRequestParameters); |
| 104 |
| 105 // Invoking the tested function. |
| 106 sendErrorReport(testError); |
| 107 }); |
| 108 |
| 109 TEST_F('GoogleNowUtilityUnitTest', 'WrapperCheckInWrappedCallback', function() { |
| 110 // Test generating an error when calling wrapper.checkInWrappedCallback from a |
| 111 // non-instrumented code. |
| 112 |
| 113 // Setup and expectations. |
| 114 var testError = { |
| 115 testField: 'TEST VALUE' |
| 116 }; |
| 117 |
| 118 this.makeAndRegisterMockGlobals([ |
| 119 'buildErrorWithMessageForServer', |
| 120 'reportError' |
| 121 ]); |
| 122 |
| 123 this.mockGlobals.expects(once()). |
| 124 buildErrorWithMessageForServer('Not in instrumented callback'). |
| 125 will(returnValue(testError)); |
| 126 this.mockGlobals.expects(once()). |
| 127 reportError(eqJSON(testError)); |
| 128 |
| 129 // Invoking the tested function. |
| 130 wrapper.checkInWrappedCallback(); |
| 131 }); |
| 132 |
| 133 TEST_F('GoogleNowUtilityUnitTest', 'WrapperWrapCallbackEvent', function() { |
| 134 // Tests wrapping event handler and that the handler code counts as an |
| 135 // instrumented callback. |
| 136 |
| 137 // Setup. |
| 138 var testError = { |
| 139 testField: 'TEST VALUE' |
| 140 }; |
| 141 |
| 142 this.makeAndRegisterMockGlobals([ |
| 143 'buildErrorWithMessageForServer', |
| 144 'reportError' |
| 145 ]); |
| 146 var onSuspendHandlerContainer = getMockHandlerContainer('runtime.onSuspend'); |
| 147 |
| 148 this.makeMockLocalFunctions(['callback']); |
| 149 |
| 150 // Step 1. Wrapping callback. |
| 151 var wrappedCallback = |
| 152 wrapper.wrapCallback(this.mockLocalFunctions.functions().callback, true); |
| 153 Mock4JS.verifyAllMocks(); |
| 154 |
| 155 // Step 2. Invoking wrapped callback. |
| 156 // Expectations. |
| 157 this.mockLocalFunctions.expects(once()). |
| 158 callback('test string', 239). |
| 159 will(callFunction(function() { |
| 160 wrapper.checkInWrappedCallback(); // it should succeed |
| 161 })); |
| 162 |
| 163 // Invoking tested function. |
| 164 wrappedCallback('test string', 239); |
| 165 Mock4JS.verifyAllMocks(); |
| 166 |
| 167 // Step 3. Checking that after the callback we are again in non-instrumented |
| 168 // code. |
| 169 // Expectations. |
| 170 this.mockGlobals.expects(once()). |
| 171 buildErrorWithMessageForServer('Not in instrumented callback'). |
| 172 will(returnValue(testError)); |
| 173 this.mockGlobals.expects(once()). |
| 174 reportError(eqJSON(testError)); |
| 175 |
| 176 // Invocation. |
| 177 wrapper.checkInWrappedCallback(); |
| 178 |
| 179 // Step 4. Check that there won't be errors whe the page unloads. |
| 180 assertTrue(onSuspendHandlerContainer.length == 1, |
| 181 'onSuspendHandlerContainer.length must be 1'); |
| 182 onSuspendHandlerContainer[0](); |
| 183 }); |
| 184 |
| 185 TEST_F('GoogleNowUtilityUnitTest', 'WrapperWrapCallbackPlugin', function() { |
| 186 // Tests calling plugin's prologue and epilogue. |
| 187 |
| 188 // Setup. |
| 189 this.makeMockLocalFunctions([ |
| 190 'callback', |
| 191 'pluginFactory', |
| 192 'prologue', |
| 193 'epilogue' |
| 194 ]); |
| 195 |
| 196 // Step 1. Registering plugin factory. |
| 197 wrapper.registerWrapperPluginFactory( |
| 198 this.mockLocalFunctions.functions().pluginFactory); |
| 199 Mock4JS.verifyAllMocks(); |
| 200 |
| 201 // Step 2. Wrapping callback. |
| 202 // Expectations. |
| 203 this.mockLocalFunctions.expects(once()). |
| 204 pluginFactory(). |
| 205 will(returnValue({ |
| 206 prologue: this.mockLocalFunctions.functions().prologue, |
| 207 epilogue: this.mockLocalFunctions.functions().epilogue |
| 208 })); |
| 209 |
| 210 // Invoking tested function. |
| 211 var wrappedCallback = |
| 212 wrapper.wrapCallback(this.mockLocalFunctions.functions().callback, true); |
| 213 Mock4JS.verifyAllMocks(); |
| 214 |
| 215 // Step 3. Calling the wrapped callback. |
| 216 // Expectations. |
| 217 this.mockLocalFunctions.expects(once()).prologue(); |
| 218 this.mockLocalFunctions.expects(once()).callback(); |
| 219 this.mockLocalFunctions.expects(once()).epilogue(); |
| 220 |
| 221 // Invoking wrapped callback. |
| 222 wrappedCallback(); |
| 223 }); |
| 224 |
| 225 TEST_F('GoogleNowUtilityUnitTest', 'WrapperWrapCallbackCatchError', function() { |
| 226 // Tests catching and sending errors by a wrapped callback. |
| 227 |
| 228 // Setup. |
| 229 this.makeAndRegisterMockGlobals([ |
| 230 'reportError' |
| 231 ]); |
| 232 this.makeMockLocalFunctions(['callback']); |
| 233 |
| 234 // Step 1. Wrapping callback. |
| 235 var wrappedCallback = |
| 236 wrapper.wrapCallback(this.mockLocalFunctions.functions().callback, true); |
| 237 Mock4JS.verifyAllMocks(); |
| 238 |
| 239 // Step 2. Invoking wrapped callback. |
| 240 // Expectations. |
| 241 this.mockLocalFunctions.expects(once()). |
| 242 callback(). |
| 243 will(callFunction(function() { |
| 244 undefined.x = 5; |
| 245 })); |
| 246 this.mockGlobals.expects(once()). |
| 247 reportError( |
| 248 eqToString('TypeError: Cannot set property \'x\' of undefined')); |
| 249 |
| 250 // Invoking tested function. |
| 251 wrappedCallback(); |
| 252 }); |
| 253 |
| 254 TEST_F('GoogleNowUtilityUnitTest', |
| 255 'WrapperInstrumentChromeApiFunction', |
| 256 function() { |
| 257 // Tests wrapper.instrumentChromeApiFunction(). |
| 258 |
| 259 // Setup. |
| 260 this.makeMockLocalFunctions([ |
| 261 'apiFunction1', |
| 262 'apiFunction2', |
| 263 'callback1', |
| 264 'callback2', |
| 265 'pluginFactory', |
| 266 'prologue', |
| 267 'epilogue' |
| 268 ]); |
| 269 chrome.testApi = { |
| 270 addListener: this.mockLocalFunctions.functions().apiFunction1 |
| 271 }; |
| 272 |
| 273 // Step 1. Instrumenting the listener. |
| 274 wrapper.instrumentChromeApiFunction('testApi.addListener', 1); |
| 275 Mock4JS.verifyAllMocks(); |
| 276 |
| 277 // Step 2. Invoking the instrumented API call. |
| 278 // Expectations. |
| 279 var function1SavedArgs = new SaveMockArguments(); |
| 280 this.mockLocalFunctions.expects(once()). |
| 281 apiFunction1( |
| 282 function1SavedArgs.match(eq(239)), |
| 283 function1SavedArgs.match(ANYTHING)); |
| 284 |
| 285 // Invocation. |
| 286 instrumented.testApi.addListener( |
| 287 239, this.mockLocalFunctions.functions().callback1); |
| 288 Mock4JS.verifyAllMocks(); |
| 289 |
| 290 // Step 3. Invoking the callback that was passed by the instrumented function |
| 291 // to the original one. |
| 292 // Expectations. |
| 293 this.mockLocalFunctions.expects(once()).callback1(237); |
| 294 |
| 295 // Invocation. |
| 296 function1SavedArgs.arguments[1](237); |
| 297 Mock4JS.verifyAllMocks(); |
| 298 |
| 299 // Step 4. Register plugin factory. |
| 300 wrapper.registerWrapperPluginFactory( |
| 301 this.mockLocalFunctions.functions().pluginFactory); |
| 302 Mock4JS.verifyAllMocks(); |
| 303 |
| 304 // Step 5. Binding the API to another function. |
| 305 chrome.testApi.addListener = this.mockLocalFunctions.functions().apiFunction2; |
| 306 |
| 307 // Step 6. Invoking the API with another callback. |
| 308 // Expectations. |
| 309 this.mockLocalFunctions.expects(once()). |
| 310 pluginFactory(). |
| 311 will(returnValue({ |
| 312 prologue: this.mockLocalFunctions.functions().prologue, |
| 313 epilogue: this.mockLocalFunctions.functions().epilogue |
| 314 })); |
| 315 var function2SavedArgs = new SaveMockArguments(); |
| 316 this.mockLocalFunctions.expects(once()). |
| 317 apiFunction2( |
| 318 function2SavedArgs.match(eq(239)), |
| 319 function2SavedArgs.match(ANYTHING)); |
| 320 |
| 321 // Invocation. |
| 322 instrumented.testApi.addListener( |
| 323 239, this.mockLocalFunctions.functions().callback2); |
| 324 Mock4JS.verifyAllMocks(); |
| 325 |
| 326 // Step 7. Invoking the callback that was passed by the instrumented function |
| 327 // to the original one. |
| 328 // Expectations. |
| 329 this.mockLocalFunctions.expects(once()).prologue(); |
| 330 this.mockLocalFunctions.expects(once()).callback2(237); |
| 331 this.mockLocalFunctions.expects(once()).epilogue(); |
| 332 |
| 333 // Invocation. |
| 334 function2SavedArgs.arguments[1](237); |
| 335 }); |
| 336 |
| 337 TEST_F('GoogleNowUtilityUnitTest', 'WrapperOnSuspendListenerFail', function() { |
| 338 // Tests that upon unloading event page, we get an error if there are pending |
| 339 // required callbacks. |
| 340 |
| 341 // Setup. |
| 342 var testError = { |
| 343 testField: 'TEST VALUE' |
| 344 }; |
| 345 this.makeAndRegisterMockGlobals([ |
| 346 'buildErrorWithMessageForServer', |
| 347 'reportError' |
| 348 ]); |
| 349 this.makeMockLocalFunctions(['listener', 'callback']); |
| 350 var onSuspendHandlerContainer = getMockHandlerContainer('runtime.onSuspend'); |
| 351 |
| 352 // Step 1. Wrapping event listener. |
| 353 var wrappedListener = |
| 354 wrapper.wrapCallback(this.mockLocalFunctions.functions().listener, true); |
| 355 Mock4JS.verifyAllMocks(); |
| 356 |
| 357 // Step 2. Invoking event listener, which will wrap a required callback. |
| 358 // Setup and expectations. |
| 359 var wrappedCallback; |
| 360 var testFixture = this; |
| 361 this.mockLocalFunctions.expects(once()). |
| 362 listener(). |
| 363 will(callFunction(function() { |
| 364 wrappedCallback = wrapper.wrapCallback( |
| 365 testFixture.mockLocalFunctions.functions().callback); |
| 366 })); |
| 367 |
| 368 // Invocation. |
| 369 wrappedListener(); |
| 370 Mock4JS.verifyAllMocks(); |
| 371 |
| 372 // Step 3. Firing runtime.onSuspend event. |
| 373 // Expectations. |
| 374 this.mockGlobals.expects(once()). |
| 375 buildErrorWithMessageForServer(stringContains( |
| 376 'ASSERT: Pending callbacks when unloading event page')). |
| 377 will(returnValue(testError)); |
| 378 this.mockGlobals.expects(once()). |
| 379 reportError(eqJSON(testError)); |
| 380 |
| 381 // Invocation. |
| 382 assertTrue(onSuspendHandlerContainer.length == 1, |
| 383 'onSuspendHandlerContainer.length must be 1'); |
| 384 onSuspendHandlerContainer[0](); |
| 385 }); |
| 386 |
| 387 TEST_F('GoogleNowUtilityUnitTest', |
| 388 'WrapperOnSuspendListenerSuccess', |
| 389 function() { |
| 390 // Tests that upon unloading event page, we don't get an error if there are no |
| 391 // pending required callbacks. |
| 392 |
| 393 // Setup. |
| 394 this.makeMockLocalFunctions(['listener', 'callback']); |
| 395 var onSuspendHandlerContainer = getMockHandlerContainer('runtime.onSuspend'); |
| 396 |
| 397 // Step 1. Wrapping event listener. |
| 398 var wrappedListener = |
| 399 wrapper.wrapCallback(this.mockLocalFunctions.functions().listener, true); |
| 400 Mock4JS.verifyAllMocks(); |
| 401 |
| 402 // Step 2. Invoking event listener, which will wrap a required callback. |
| 403 // Setup and expectations. |
| 404 var wrappedCallback; |
| 405 var testFixture = this; |
| 406 this.mockLocalFunctions.expects(once()). |
| 407 listener(). |
| 408 will(callFunction(function() { |
| 409 wrappedCallback = wrapper.wrapCallback( |
| 410 testFixture.mockLocalFunctions.functions().callback); |
| 411 })); |
| 412 |
| 413 // Invocation. |
| 414 wrappedListener(); |
| 415 Mock4JS.verifyAllMocks(); |
| 416 |
| 417 // Step 3. Calling wrapped callback. |
| 418 // Expectations. |
| 419 this.mockLocalFunctions.expects(once()).callback(); |
| 420 |
| 421 // Invocation. |
| 422 wrappedCallback(); |
| 423 |
| 424 // Step 4. Firing runtime.onSuspend event. |
| 425 assertTrue(onSuspendHandlerContainer.length == 1, |
| 426 'onSuspendHandlerContainer.length must be 1'); |
| 427 onSuspendHandlerContainer[0](); |
| 428 }); |
OLD | NEW |