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