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 // TODO(robliao,vadimt): Determine the granularity of testing to perform. 6 7 /** 8 * Test fixture for background.js. 9 * @constructor 10 * @extends {testing.Test} 11 */ 12 function GoogleNowBackgroundUnitTest () { 13 testing.Test.call(this); 14 } 15 16 GoogleNowBackgroundUnitTest.prototype = { 17 __proto__: testing.Test.prototype, 18 19 /** @override */ 20 extraLibraries: [ 21 'common_test_util.js', 22 'background_test_util.js', 23 'background.js' 24 ] 25 }; 26 27 var TEST_NAME = 'GoogleNowBackgroundUnitTest'; 28 29 /** 30 * Tasks Conflict Test 31 */ 32 TEST_F(TEST_NAME, 'AreTasksConflicting', function() { 33 function testTaskPair(newTaskName, scheduledTaskName, expected) { 34 assertTrue(areTasksConflicting(newTaskName, scheduledTaskName) == expected, 35 '(' + newTaskName + ', ' + scheduledTaskName + ')'); 36 } 37 38 testTaskPair(UPDATE_CARDS_TASK_NAME, UPDATE_CARDS_TASK_NAME, true); 39 testTaskPair(UPDATE_CARDS_TASK_NAME, DISMISS_CARD_TASK_NAME, false); 40 testTaskPair(UPDATE_CARDS_TASK_NAME, RETRY_DISMISS_TASK_NAME, false); 41 testTaskPair(UPDATE_CARDS_TASK_NAME, STATE_CHANGED_TASK_NAME, false); 42 43 testTaskPair(DISMISS_CARD_TASK_NAME, UPDATE_CARDS_TASK_NAME, false); 44 testTaskPair(DISMISS_CARD_TASK_NAME, DISMISS_CARD_TASK_NAME, false); 45 testTaskPair(DISMISS_CARD_TASK_NAME, RETRY_DISMISS_TASK_NAME, false); 46 testTaskPair(DISMISS_CARD_TASK_NAME, STATE_CHANGED_TASK_NAME, false); 47 48 testTaskPair(RETRY_DISMISS_TASK_NAME, UPDATE_CARDS_TASK_NAME, true); 49 testTaskPair(RETRY_DISMISS_TASK_NAME, DISMISS_CARD_TASK_NAME, true); 50 testTaskPair(RETRY_DISMISS_TASK_NAME, RETRY_DISMISS_TASK_NAME, true); 51 testTaskPair(RETRY_DISMISS_TASK_NAME, STATE_CHANGED_TASK_NAME, false); 52 53 testTaskPair(STATE_CHANGED_TASK_NAME, UPDATE_CARDS_TASK_NAME, false); 54 testTaskPair(STATE_CHANGED_TASK_NAME, DISMISS_CARD_TASK_NAME, false); 55 testTaskPair(STATE_CHANGED_TASK_NAME, RETRY_DISMISS_TASK_NAME, false); 56 testTaskPair(STATE_CHANGED_TASK_NAME, STATE_CHANGED_TASK_NAME, false); 57 }); 58 59 /** 60 * Server Request Tests 61 */ 62 TEST_F(TEST_NAME, 'AuthServerRequestSuccess', function() { 63 expectServerRequests(this, 200, '{}'); 64 var callbackCalled = false; 65 requestFromServer('GET', 'test/target').then(function(request) { 66 callbackCalled = true; 67 assertTrue(request.status === 200); 68 assertTrue(request.responseText === '{}'); 69 }); 70 assertTrue(callbackCalled); 71 }); 72 73 TEST_F(TEST_NAME, 'AuthServerRequestForbidden', function() { 74 this.makeAndRegisterMockApis(['authenticationManager.removeToken']); 75 this.mockApis.expects(once()).authenticationManager_removeToken(ANYTHING); 76 77 expectServerRequests(this, 403, ''); 78 79 var thenCalled = false; 80 var catchCalled = false; 81 requestFromServer('GET', 'test/target').then(function(request) { 82 thenCalled = true; 83 }).catch(function(request) { 84 // The promise is rejected on HTTP failures. 85 catchCalled = true; 86 assertTrue(request.status === 403); 87 }); 88 assertFalse(thenCalled); 89 assertTrue(catchCalled); 90 }); 91 92 TEST_F(TEST_NAME, 'AuthServerRequestNoAuth', function() { 93 this.makeAndRegisterMockApis(['authenticationManager.removeToken']); 94 this.mockApis.expects(once()).authenticationManager_removeToken(ANYTHING); 95 96 expectServerRequests(this, 401, ''); 97 98 var thenCalled = false; 99 var catchCalled = false; 100 requestFromServer('GET', 'test/target').then(function(request) { 101 thenCalled = true; 102 }).catch(function(request) { 103 // The promise is rejected on HTTP failures. 104 catchCalled = true; 105 assertTrue(request.status === 401); 106 }); 107 assertFalse(thenCalled); 108 assertTrue(catchCalled); 109 }); 110 111 function expectServerRequests(fixture, httpStatus, responseText) { 112 fixture.makeAndRegisterMockApis([ 113 'authenticationManager.getAuthToken', 114 'buildServerRequest' 115 ]); 116 117 function XMLHttpRequest() {} 118 119 XMLHttpRequest.prototype = { 120 addEventListener: function(type, listener, wantsUntrusted) {}, 121 setRequestHeader: function(header, value) {}, 122 send: function() {} 123 } 124 125 fixture.mockApis.expects(once()).authenticationManager_getAuthToken() 126 .will(returnValue(Promise.resolve('token'))); 127 128 var mockXMLHttpRequest = mock(XMLHttpRequest); 129 var mockXMLHttpRequestProxy = mockXMLHttpRequest.proxy(); 130 fixture.mockApis.expects(once()) 131 .buildServerRequest(ANYTHING, ANYTHING, ANYTHING) 132 .will(returnValue(mockXMLHttpRequestProxy)); 133 134 mockXMLHttpRequest.expects(once()) 135 .setRequestHeader('Authorization', 'Bearer token'); 136 137 var loadEndSavedArgs = new SaveMockArguments(); 138 mockXMLHttpRequest.expects(once()) 139 .addEventListener( 140 loadEndSavedArgs.match(eq('loadend')), 141 loadEndSavedArgs.match(ANYTHING), 142 loadEndSavedArgs.match(eq(false))); 143 144 mockXMLHttpRequestProxy.status = httpStatus; 145 mockXMLHttpRequestProxy.response = responseText; 146 mockXMLHttpRequestProxy.responseText = responseText; 147 148 mockXMLHttpRequest.expects(once()).send() 149 .will(invokeCallback(loadEndSavedArgs, 1, mockXMLHttpRequestProxy)); 150 } 151 152 TEST_F(TEST_NAME, 'AuthServerRequestNoToken', function() { 153 this.makeAndRegisterMockApis([ 154 'authenticationManager.getAuthToken', 155 'buildServerRequest' 156 ]); 157 158 this.mockApis.expects(once()).authenticationManager_getAuthToken() 159 .will(returnValue(Promise.reject())); 160 this.mockApis.expects(never()).buildServerRequest() 161 162 var thenCalled = false; 163 var catchCalled = false; 164 requestFromServer('GET', 'test/target').then(function(request) { 165 thenCalled = true; 166 }).catch(function() { 167 catchCalled = true; 168 }); 169 assertFalse(thenCalled); 170 assertTrue(catchCalled); 171 }) 172 173 /** 174 * requestNotificationGroupsFromServer Tests 175 */ 176 TEST_F(TEST_NAME, 'RequestNotificationGroupsFromServerEmpty', function() { 177 this.makeAndRegisterMockGlobals([ 178 'shouldShowExplanatoryCard', 179 'recordEvent', 180 'requestFromServer' 181 ]); 182 183 this.mockGlobals.expects(once()).shouldShowExplanatoryCard() 184 .will(returnValue(false)); 185 186 this.mockGlobals.expects(once()).recordEvent( 187 GoogleNowEvent.REQUEST_FOR_CARDS_TOTAL); 188 189 this.mockGlobals.expects(once()).recordEvent( 190 GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS); 191 192 var requestFromServerArgs = new SaveMockArguments(); 193 this.mockGlobals.expects(once()).requestFromServer( 194 requestFromServerArgs.match(eq('GET')), 195 requestFromServerArgs.match(ANYTHING)) 196 .will(returnValue( 197 Promise.resolve({status: 200, responseText: "{}"}))); 198 199 var thenCalled = false; 200 var catchCalled = false; 201 requestNotificationGroupsFromServer([]).then(function() { 202 thenCalled = true; 203 }).catch(function() { 204 catchCalled = true; 205 }); 206 assertTrue(thenCalled); 207 assertFalse(catchCalled); 208 209 var pathAndQuery = requestFromServerArgs.arguments[1]; 210 var query = pathAndQuery.split('?')[1]; 211 assertTrue(query.search('timeZoneOffsetMs') >= 0); 212 assertTrue(query.search('uiLocale') >= 0); 213 assertFalse(query.search('cardExplanation') >= 0); 214 }); 215 216 TEST_F(TEST_NAME, 'RequestNotificationGroupsFromServerWithGroups', function() { 217 this.makeAndRegisterMockGlobals([ 218 'shouldShowExplanatoryCard', 219 'recordEvent', 220 'requestFromServer' 221 ]); 222 223 this.mockGlobals.expects(once()).shouldShowExplanatoryCard() 224 .will(returnValue(false)); 225 226 this.mockGlobals.expects(once()).recordEvent( 227 GoogleNowEvent.REQUEST_FOR_CARDS_TOTAL); 228 229 this.mockGlobals.expects(once()).recordEvent( 230 GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS); 231 232 var requestFromServerArgs = new SaveMockArguments(); 233 this.mockGlobals.expects(once()).requestFromServer( 234 requestFromServerArgs.match(eq('GET')), 235 requestFromServerArgs.match(ANYTHING)) 236 .will(returnValue( 237 Promise.resolve({status: 200, responseText: "{}"}))); 238 239 var thenCalled = false; 240 var catchCalled = false; 241 requestNotificationGroupsFromServer(['A', 'B', 'C']).then(function() { 242 thenCalled = true; 243 }).catch(function() { 244 catchCalled = true; 245 }); 246 assertTrue(thenCalled); 247 assertFalse(catchCalled); 248 249 var pathAndQuery = requestFromServerArgs.arguments[1]; 250 var query = pathAndQuery.split('?')[1]; 251 assertTrue(query.search('timeZoneOffsetMs') >= 0); 252 assertTrue(query.search('uiLocale') >= 0); 253 assertFalse(query.search('cardExplanation') >= 0); 254 assertTrue(query.search('requestTypes=A') >= 0); 255 assertTrue(query.search('requestTypes=B') >= 0); 256 assertTrue(query.search('requestTypes=C') >= 0); 257 }); 258 259 TEST_F(TEST_NAME, 'RequestNotificationGroupsFromServerExplanatory', function() { 260 this.makeAndRegisterMockGlobals([ 261 'shouldShowExplanatoryCard', 262 'recordEvent', 263 'requestFromServer' 264 ]); 265 266 this.mockGlobals.expects(once()).shouldShowExplanatoryCard() 267 .will(returnValue(true)); 268 269 this.mockGlobals.expects(once()).recordEvent( 270 GoogleNowEvent.REQUEST_FOR_CARDS_TOTAL); 271 272 this.mockGlobals.expects(once()).recordEvent( 273 GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS); 274 275 var requestFromServerArgs = new SaveMockArguments(); 276 this.mockGlobals.expects(once()).requestFromServer( 277 requestFromServerArgs.match(eq('GET')), 278 requestFromServerArgs.match(ANYTHING)) 279 .will(returnValue( 280 Promise.resolve({status: 200, responseText: "{}"}))); 281 282 var thenCalled = false; 283 var catchCalled = false; 284 requestNotificationGroupsFromServer([]).then(function() { 285 thenCalled = true; 286 }).catch(function() { 287 catchCalled = true; 288 }); 289 assertTrue(thenCalled); 290 assertFalse(catchCalled); 291 292 var pathAndQuery = requestFromServerArgs.arguments[1]; 293 var query = pathAndQuery.split('?')[1]; 294 assertTrue(query.search('timeZoneOffsetMs') >= 0); 295 assertTrue(query.search('uiLocale') >= 0); 296 assertTrue(query.search('cardExplanation=true') >= 0); 297 }); 298 299 TEST_F(TEST_NAME, 'RequestNotificationGroupsFromServerFailure', function() { 300 this.makeAndRegisterMockGlobals([ 301 'shouldShowExplanatoryCard', 302 'recordEvent', 303 'requestFromServer' 304 ]); 305 306 this.mockGlobals.expects(once()).shouldShowExplanatoryCard() 307 .will(returnValue(false)); 308 309 this.mockGlobals.expects(once()).recordEvent( 310 GoogleNowEvent.REQUEST_FOR_CARDS_TOTAL); 311 312 this.mockGlobals.expects(never()).recordEvent( 313 GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS); 314 315 var requestFromServerArgs = new SaveMockArguments(); 316 this.mockGlobals.expects(once()).requestFromServer( 317 requestFromServerArgs.match(eq('GET')), 318 requestFromServerArgs.match(ANYTHING)) 319 .will(returnValue( 320 Promise.reject({status: 401}))); 321 322 var thenCalled = false; 323 var catchCalled = false; 324 requestNotificationGroupsFromServer([]).then(function() { 325 thenCalled = true; 326 }).catch(function() { 327 catchCalled = true; 328 }); 329 assertFalse(thenCalled); 330 assertTrue(catchCalled); 331 }); 332 333 /** 334 * shouldScheduleRetryFromGroupList Tests 335 */ 336 TEST_F(TEST_NAME, 'ShouldScheduleRetryEmptyGroupList', function() { 337 assertTrue(shouldScheduleRetryFromGroupList([])); 338 }); 339 340 TEST_F(TEST_NAME, 'ShouldScheduleRetryNorOnlyGroupList', function() { 341 assertFalse(shouldScheduleRetryFromGroupList(['NOR'])); 342 }); 343 344 TEST_F(TEST_NAME, 'ShouldScheduleRetryNotOnlyGroupList', function() { 345 assertTrue(shouldScheduleRetryFromGroupList(['NOT'])); 346 }); 347 348 TEST_F(TEST_NAME, 'ShouldScheduleRetryMultipleGroupsList', function() { 349 assertTrue(shouldScheduleRetryFromGroupList(['NOR', 'NOT'])); 350 }); 351 352 /** 353 * requestAndUpdateOptIn Tests 354 */ 355 TEST_F(TEST_NAME, 'RequestAndUpdateOptInOptedIn', function() { 356 this.makeAndRegisterMockApis([ 357 'chrome.storage.local.set', 358 'requestFromServer' 359 ]); 360 361 this.mockApis.expects(once()).requestFromServer('GET', 'settings/optin') 362 .will(returnValue(Promise.resolve({ 363 status: 200, 364 responseText: '{"value": true}'}))); 365 366 this.mockApis.expects(once()) 367 .chrome_storage_local_set(eqJSON({googleNowEnabled: true})); 368 369 var thenCalled = false; 370 var catchCalled = false; 371 requestAndUpdateOptedIn().then(function(optedIn) { 372 thenCalled = true; 373 assertTrue(optedIn); 374 }).catch(function() { 375 catchCalled = true; 376 }); 377 assertTrue(thenCalled); 378 assertFalse(catchCalled); 379 }); 380 381 TEST_F(TEST_NAME, 'RequestAndUpdateOptInOptedOut', function() { 382 this.makeAndRegisterMockApis([ 383 'chrome.storage.local.set', 384 'requestFromServer' 385 ]); 386 387 this.mockApis.expects(once()).requestFromServer('GET', 'settings/optin') 388 .will(returnValue(Promise.resolve({ 389 status: 200, 390 responseText: '{"value": false}'}))); 391 392 this.mockApis.expects(once()) 393 .chrome_storage_local_set(eqJSON({googleNowEnabled: false})); 394 395 var thenCalled = false; 396 var catchCalled = false; 397 requestAndUpdateOptedIn().then(function(optedIn) { 398 thenCalled = true; 399 assertFalse(optedIn); 400 }).catch(function() { 401 catchCalled = true; 402 }); 403 assertTrue(thenCalled); 404 assertFalse(catchCalled); 405 }); 406 407 TEST_F(TEST_NAME, 'RequestAndUpdateOptInFailure', function() { 408 this.makeAndRegisterMockApis([ 409 'chrome.storage.local.set', 410 'requestFromServer' 411 ]); 412 413 this.mockApis.expects(once()).requestFromServer('GET', 'settings/optin') 414 .will(returnValue(Promise.reject({status: 404}))); 415 416 this.mockApis.expects(never()).chrome_storage_local_set(); 417 418 var thenCalled = false; 419 var catchCalled = false; 420 requestAndUpdateOptedIn().then(function() { 421 thenCalled = true; 422 }).catch(function() { 423 catchCalled = true; 424 }); 425 assertFalse(thenCalled); 426 assertTrue(catchCalled); 427 }); 428 429 /** 430 * pollOptedInNoImmediateRecheck Tests 431 */ 432 TEST_F(TEST_NAME, 'pollOptedInNoImmediateRecheckOptedIn', function() { 433 this.makeAndRegisterMockApis([ 434 'requestAndUpdateOptedIn', 435 'instrumented.metricsPrivate.getVariationParams', 436 'optInPollAttempts.start' 437 ]); 438 439 this.mockApis.expects(once()).requestAndUpdateOptedIn() 440 .will(returnValue(Promise.resolve(true))); 441 442 this.mockApis.expects(never()) 443 .instrumented_metricsPrivate_getVariationParams(); 444 445 this.mockApis.expects(never()).optInPollAttempts_start(); 446 447 pollOptedInNoImmediateRecheck(); 448 }); 449 450 TEST_F(TEST_NAME, 'pollOptedInNoImmediateRecheckOptedOut', function() { 451 this.makeAndRegisterMockApis([ 452 'requestAndUpdateOptedIn', 453 'instrumented.metricsPrivate.getVariationParams', 454 'optInPollAttempts.start' 455 ]); 456 457 this.mockApis.expects(once()).requestAndUpdateOptedIn() 458 .will(returnValue(Promise.resolve(false))); 459 460 var getVariationParamsSavedArgs = new SaveMockArguments(); 461 this.mockApis.expects(once()) 462 .instrumented_metricsPrivate_getVariationParams( 463 getVariationParamsSavedArgs.match(eq('GoogleNow')), 464 getVariationParamsSavedArgs.match(ANYTHING)) 465 .will(invokeCallback(getVariationParamsSavedArgs, 1, {})); 466 467 this.mockApis.expects(once()) 468 .optInPollAttempts_start(DEFAULT_OPTIN_CHECK_PERIOD_SECONDS); 469 470 pollOptedInNoImmediateRecheck(); 471 }); 472 473 TEST_F(TEST_NAME, 'pollOptedInNoImmediateRecheckFailure', function() { 474 this.makeAndRegisterMockApis([ 475 'requestAndUpdateOptedIn', 476 'instrumented.metricsPrivate.getVariationParams', 477 'optInPollAttempts.start' 478 ]); 479 480 this.mockApis.expects(once()).requestAndUpdateOptedIn() 481 .will(returnValue(Promise.reject())); 482 483 var getVariationParamsSavedArgs = new SaveMockArguments(); 484 this.mockApis.expects(once()) 485 .instrumented_metricsPrivate_getVariationParams( 486 getVariationParamsSavedArgs.match(eq('GoogleNow')), 487 getVariationParamsSavedArgs.match(ANYTHING)) 488 .will(invokeCallback(getVariationParamsSavedArgs, 1, {})); 489 490 this.mockApis.expects(once()) 491 .optInPollAttempts_start(DEFAULT_OPTIN_CHECK_PERIOD_SECONDS); 492 493 pollOptedInNoImmediateRecheck(); 494 }); 495 496 /** 497 * getGroupsToRequest Tests 498 */ 499 TEST_F(TEST_NAME, 'GetGroupsToRequestNone', function() { 500 this.makeAndRegisterMockApis([ 501 'fillFromChromeLocalStorage', 502 'Date.now' 503 ]); 504 505 this.mockApis.expects(once()) 506 .fillFromChromeLocalStorage(eqJSON({notificationGroups: {}})) 507 .will(returnValue(Promise.resolve({notificationGroups: {}}))); 508 509 this.mockApis.expects(once()).Date_now().will(returnValue(20)); 510 511 getGroupsToRequest().then(function(groupsToRequest) { 512 assertTrue(JSON.stringify(groupsToRequest) === '[]'); 513 }); 514 }); 515 516 TEST_F(TEST_NAME, 'GetGroupsToRequestWithGroups', function() { 517 this.makeAndRegisterMockApis([ 518 'fillFromChromeLocalStorage', 519 'Date.now' 520 ]); 521 522 this.mockApis.expects(once()) 523 .fillFromChromeLocalStorage(eqJSON({notificationGroups: {}})) 524 .will(returnValue(Promise.resolve({notificationGroups: { 525 TIME18: {nextPollTime: 18}, 526 TIME19: {nextPollTime: 19}, 527 TIME20: {nextPollTime: 20}, 528 TIME21: {nextPollTime: 21}, 529 TIME22: {nextPollTime: 22}, 530 TIMEUNDEF: {} 531 }}))); 532 533 this.mockApis.expects(once()).Date_now().will(returnValue(20)); 534 535 getGroupsToRequest().then(function(groupsToRequest) { 536 assertTrue(groupsToRequest.length == 3); 537 assertTrue(groupsToRequest.indexOf('TIME18') >= 0); 538 assertTrue(groupsToRequest.indexOf('TIME19') >= 0); 539 assertTrue(groupsToRequest.indexOf('TIME20') >= 0); 540 }); 541 }); 542 543 /** 544 * combineGroup Tests 545 */ 546 TEST_F(TEST_NAME, 'CombineGroup', function() { 547 // Tests combineGroup function. Verifies that both notifications with and 548 // without show time are handled correctly and that cards are correctly 549 // added to existing cards with same ID or start a new combined card. 550 551 // Setup and expectations. 552 var combinedCards = { 553 'EXISTING CARD': [1] 554 }; 555 556 var receivedNotificationNoShowTime = { 557 chromeNotificationId: 'EXISTING CARD', 558 trigger: {hideTimeSec: 1} 559 }; 560 var receivedNotificationWithShowTime = { 561 chromeNotificationId: 'NEW CARD', 562 trigger: {showTimeSec: 2, hideTimeSec: 3} 563 } 564 565 var storedGroup = { 566 cardsTimestamp: 10000, 567 cards: [ 568 receivedNotificationNoShowTime, 569 receivedNotificationWithShowTime 570 ] 571 }; 572 573 // Invoking the tested function. 574 combineGroup(combinedCards, storedGroup); 575 576 // Check the output value. 577 var expectedCombinedCards = { 578 'EXISTING CARD': [ 579 1, 580 { 581 receivedNotification: receivedNotificationNoShowTime, 582 hideTime: 11000 583 } 584 ], 585 'NEW CARD': [ 586 { 587 receivedNotification: receivedNotificationWithShowTime, 588 showTime: 12000, 589 hideTime: 13000 590 } 591 ] 592 }; 593 594 assertEquals( 595 JSON.stringify(expectedCombinedCards), 596 JSON.stringify(combinedCards)); 597 }); 598 599 /** 600 * Mocks global functions and APIs that initialize() depends upon. 601 * @param {Test} fixture Test fixture. 602 */ 603 function mockInitializeDependencies(fixture) { 604 fixture.makeAndRegisterMockGlobals([ 605 'pollOptedInNoImmediateRecheck', 606 'recordEvent', 607 'removeAllCards', 608 'setBackgroundEnable', 609 'startPollingCards', 610 'stopPollingCards' 611 ]); 612 fixture.makeAndRegisterMockApis([ 613 'authenticationManager.isSignedIn', 614 'chrome.storage.local.remove', 615 'fillFromChromeLocalStorage', 616 'instrumented.metricsPrivate.getVariationParams', 617 'instrumented.notifications.getAll', 618 'instrumented.notifications.getPermissionLevel', 619 'instrumented.webstorePrivate.getBrowserLogin', 620 'optInPollAttempts.isRunning', 621 'optInPollAttempts.stop', 622 'tasks.add', 623 'updateCardsAttempts.isRunning', 624 'updateCardsAttempts.stop' 625 ]); 626 } 627 628 /** 629 * Sets up the test to expect the state machine calls and send 630 * the specified state machine state. Currently used to test initialize(). 631 * Note that this CAN NOT be used if any of the methods below are called 632 * outside of this context with the same argument matchers. 633 * expects() calls cannot be chained with the same argument matchers. 634 * @param {object} fixture Test fixture. 635 * @param {string} testIdentityToken getAuthToken callback token. 636 * @param {object} testExperimentVariationParams Response of 637 * metricsPrivate.getVariationParams. 638 * @param {string} testExperimentVariationParams Response of 639 * notifications.getPermissionLevel. 640 * @param {boolean} testGoogleNowEnabled True if the user is opted in to Google 641 * Now. 642 */ 643 function expectStateMachineCalls( 644 fixture, 645 testIdentityToken, 646 testExperimentVariationParams, 647 testNotificationPermissionLevel, 648 testGoogleNowEnabled) { 649 fixture.mockApis.expects(once()). 650 authenticationManager_isSignedIn(). 651 will(returnValue(new Promise(function(resolve) { 652 resolve(!!testIdentityToken); 653 }))); 654 655 var getVariationParamsSavedArgs = new SaveMockArguments(); 656 fixture.mockApis.expects(once()). 657 instrumented_metricsPrivate_getVariationParams( 658 getVariationParamsSavedArgs.match(ANYTHING), 659 getVariationParamsSavedArgs.match(ANYTHING)). 660 will(invokeCallback( 661 getVariationParamsSavedArgs, 1, testExperimentVariationParams)); 662 663 var notificationGetPermissionLevelSavedArgs = new SaveMockArguments(); 664 fixture.mockApis.expects(once()). 665 instrumented_notifications_getPermissionLevel( 666 notificationGetPermissionLevelSavedArgs.match(ANYTHING)). 667 will(invokeCallback( 668 notificationGetPermissionLevelSavedArgs, 669 0, 670 testNotificationPermissionLevel)) 671 672 expectChromeLocalStorageGet( 673 fixture, 674 {googleNowEnabled: false}, 675 {googleNowEnabled: testGoogleNowEnabled}); 676 677 var updateCardsAttemptsIsRunningSavedArgs = new SaveMockArguments(); 678 fixture.mockApis.expects(once()). 679 updateCardsAttempts_isRunning( 680 updateCardsAttemptsIsRunningSavedArgs.match(ANYTHING)). 681 will( 682 invokeCallback( 683 updateCardsAttemptsIsRunningSavedArgs, 0, undefined)); 684 685 var optInPollAttemptsIsRunningSavedArgs = new SaveMockArguments(); 686 fixture.mockApis.expects(once()). 687 optInPollAttempts_isRunning( 688 optInPollAttemptsIsRunningSavedArgs.match(ANYTHING)). 689 will( 690 invokeCallback( 691 optInPollAttemptsIsRunningSavedArgs, 0, undefined)); 692 } 693 694 /** 695 * Sets up the test to expect the initialization calls that 696 * initialize() invokes. 697 * Note that this CAN NOT be used if any of the methods below are called 698 * outside of this context with the same argument matchers. 699 * expects() calls cannot be chained with the same argument matchers. 700 */ 701 function expectInitialization(fixture) { 702 var tasksAddSavedArgs = new SaveMockArguments(); 703 fixture.mockApis.expects(once()). 704 tasks_add( 705 tasksAddSavedArgs.match(ANYTHING), 706 tasksAddSavedArgs.match(ANYTHING)). 707 will(invokeCallback(tasksAddSavedArgs, 1, function() {})); 708 709 // The ordering here between stubs and expects is important. 710 // We only care about the EXTENSION_START event. The other events are covered 711 // by the NoCards tests below. Reversing the calls will cause all recordEvent 712 // calls to be unexpected. 713 fixture.mockGlobals.stubs().recordEvent(ANYTHING); 714 fixture.mockGlobals. 715 expects(once()).recordEvent(GoogleNowEvent.EXTENSION_START); 716 } 717 718 TEST_F(TEST_NAME,'Initialize_SignedOut', function() { 719 // Tests the case when getAuthToken fails most likely because the user is 720 // not signed in. In this case, the function should quietly exit after 721 // finding out that getAuthToken fails. 722 723 // Setup and expectations. 724 var testIdentityToken = undefined; 725 var testExperimentVariationParams = {}; 726 var testNotificationPermissionLevel = 'denied'; 727 var testGoogleNowEnabled = undefined; 728 729 mockInitializeDependencies(this); 730 731 expectInitialization(this); 732 733 expectStateMachineCalls( 734 this, 735 testIdentityToken, 736 testExperimentVariationParams, 737 testNotificationPermissionLevel, 738 testGoogleNowEnabled); 739 740 this.mockGlobals.expects(once()).setBackgroundEnable(false); 741 this.mockGlobals.expects(never()).startPollingCards(); 742 this.mockGlobals.expects(once()).stopPollingCards(); 743 this.mockGlobals.expects(once()).removeAllCards(); 744 this.mockGlobals.expects(never()).pollOptedInNoImmediateRecheck(); 745 this.mockApis.expects(once()).optInPollAttempts_stop(); 746 747 // Invoking the tested function. 748 initialize(); 749 }); 750 751 TEST_F(TEST_NAME,'Initialize_NotificationDisabled', function() { 752 // Tests the case when Google Now is disabled in the notifications center. 753 754 // Setup and expectations. 755 var testIdentityToken = 'some identity token'; 756 var testExperimentVariationParams = {}; 757 var testNotificationPermissionLevel = 'denied'; 758 var testGoogleNowEnabled = undefined; 759 760 mockInitializeDependencies(this); 761 762 expectInitialization(this); 763 764 expectStateMachineCalls( 765 this, 766 testIdentityToken, 767 testExperimentVariationParams, 768 testNotificationPermissionLevel, 769 testGoogleNowEnabled); 770 771 this.mockGlobals.expects(once()).setBackgroundEnable(false); 772 this.mockGlobals.expects(never()).startPollingCards(); 773 this.mockGlobals.expects(once()).stopPollingCards(); 774 this.mockGlobals.expects(once()).removeAllCards(); 775 this.mockGlobals.expects(never()).pollOptedInNoImmediateRecheck(); 776 this.mockApis.expects(once()).optInPollAttempts_stop(); 777 778 // Invoking the tested function. 779 initialize(); 780 }); 781 782 TEST_F(TEST_NAME, 'Initialize_NoBackground', function() { 783 // Tests when the no background variation is received. 784 785 // Setup and expectations. 786 var testIdentityToken = 'some identity token'; 787 var testExperimentVariationParams = {canEnableBackground: 'false'}; 788 var testNotificationPermissionLevel = 'granted'; 789 var testGoogleNowEnabled = true; 790 791 mockInitializeDependencies(this); 792 793 expectInitialization(this); 794 795 expectStateMachineCalls( 796 this, 797 testIdentityToken, 798 testExperimentVariationParams, 799 testNotificationPermissionLevel, 800 testGoogleNowEnabled); 801 802 this.mockGlobals.expects(once()).setBackgroundEnable(false); 803 this.mockGlobals.expects(once()).startPollingCards(); 804 this.mockGlobals.expects(never()).stopPollingCards(); 805 this.mockGlobals.expects(never()).removeAllCards(); 806 this.mockGlobals.expects(never()).pollOptedInNoImmediateRecheck(); 807 this.mockApis.expects(once()).optInPollAttempts_stop(); 808 809 // Invoking the tested function. 810 initialize(); 811 }); 812 813 TEST_F(TEST_NAME, 'Initialize_GoogleNowDisabled', function() { 814 // Tests when the user has Google Now disabled. 815 816 // Setup and expectations. 817 var testIdentityToken = 'some identity token'; 818 var testExperimentVariationParams = {}; 819 var testNotificationPermissionLevel = 'granted'; 820 var testGoogleNowEnabled = false; 821 822 mockInitializeDependencies(this); 823 824 expectInitialization(this); 825 826 expectStateMachineCalls( 827 this, 828 testIdentityToken, 829 testExperimentVariationParams, 830 testNotificationPermissionLevel, 831 testGoogleNowEnabled); 832 833 this.mockGlobals.expects(once()).setBackgroundEnable(false); 834 this.mockGlobals.expects(never()).startPollingCards(); 835 this.mockGlobals.expects(once()).stopPollingCards(); 836 this.mockGlobals.expects(once()).removeAllCards(); 837 this.mockGlobals.expects(once()).pollOptedInNoImmediateRecheck(); 838 this.mockApis.expects(never()).optInPollAttempts_stop(); 839 840 // Invoking the tested function. 841 initialize(); 842 }); 843 844 TEST_F(TEST_NAME, 'Initialize_RunGoogleNow', function() { 845 // Tests if Google Now will invoke startPollingCards when all 846 // of the required state is fulfilled. 847 848 // Setup and expectations. 849 var testIdentityToken = 'some identity token'; 850 var testExperimentVariationParams = {}; 851 var testNotificationPermissionLevel = 'granted'; 852 var testGoogleNowEnabled = true; 853 854 mockInitializeDependencies(this); 855 856 expectInitialization(this); 857 858 expectStateMachineCalls( 859 this, 860 testIdentityToken, 861 testExperimentVariationParams, 862 testNotificationPermissionLevel, 863 testGoogleNowEnabled); 864 865 this.mockGlobals.expects(once()).setBackgroundEnable(true); 866 this.mockGlobals.expects(once()).startPollingCards(); 867 this.mockGlobals.expects(never()).stopPollingCards(); 868 this.mockGlobals.expects(never()).removeAllCards(); 869 this.mockGlobals.expects(never()).pollOptedInNoImmediateRecheck(); 870 this.mockApis.expects(once()).optInPollAttempts_stop(); 871 872 // Invoking the tested function. 873 initialize(); 874 }); 875 876 /** 877 * No Cards Event Recording Tests 878 */ 879 TEST_F(TEST_NAME, 'NoCardsSignedOut', function() { 880 var signedIn = false; 881 var notificationEnabled = false; 882 var googleNowEnabled = false; 883 this.makeAndRegisterMockGlobals([ 884 'recordEvent', 885 'removeAllCards', 886 'setBackgroundEnable', 887 'setShouldPollCards', 888 'setShouldPollOptInStatus']); 889 890 this.mockGlobals.stubs().removeAllCards(); 891 this.mockGlobals.stubs().setBackgroundEnable(ANYTHING); 892 this.mockGlobals.stubs().setShouldPollCards(ANYTHING); 893 this.mockGlobals.stubs().setShouldPollOptInStatus(ANYTHING); 894 895 this.mockGlobals.expects(once()).recordEvent( 896 GoogleNowEvent.STOPPED); 897 this.mockGlobals.expects(once()).recordEvent( 898 GoogleNowEvent.SIGNED_OUT); 899 this.mockGlobals.expects(never()).recordEvent( 900 GoogleNowEvent.NOTIFICATION_DISABLED); 901 this.mockGlobals.expects(never()).recordEvent( 902 GoogleNowEvent.GOOGLE_NOW_DISABLED); 903 updateRunningState(signedIn, true, notificationEnabled, googleNowEnabled); 904 }); 905 906 TEST_F(TEST_NAME, 'NoCardsNotificationsDisabled', function() { 907 var signedIn = true; 908 var notificationEnabled = false; 909 var googleNowEnabled = false; 910 this.makeAndRegisterMockGlobals([ 911 'recordEvent', 912 'removeAllCards', 913 'setBackgroundEnable', 914 'setShouldPollCards', 915 'setShouldPollOptInStatus']); 916 917 this.mockGlobals.stubs().removeAllCards(); 918 this.mockGlobals.stubs().setBackgroundEnable(ANYTHING); 919 this.mockGlobals.stubs().setShouldPollCards(ANYTHING); 920 this.mockGlobals.stubs().setShouldPollOptInStatus(ANYTHING); 921 922 this.mockGlobals.expects(once()).recordEvent( 923 GoogleNowEvent.STOPPED); 924 this.mockGlobals.expects(never()).recordEvent( 925 GoogleNowEvent.SIGNED_OUT); 926 this.mockGlobals.expects(once()).recordEvent( 927 GoogleNowEvent.NOTIFICATION_DISABLED); 928 this.mockGlobals.expects(never()).recordEvent( 929 GoogleNowEvent.GOOGLE_NOW_DISABLED); 930 updateRunningState(signedIn, true, notificationEnabled, googleNowEnabled); 931 }); 932 933 TEST_F(TEST_NAME, 'NoCardsGoogleNowDisabled', function() { 934 var signedIn = true; 935 var notificationEnabled = true; 936 var googleNowEnabled = false; 937 this.makeAndRegisterMockGlobals([ 938 'recordEvent', 939 'removeAllCards', 940 'setBackgroundEnable', 941 'setShouldPollCards', 942 'setShouldPollOptInStatus']); 943 944 this.mockGlobals.stubs().removeAllCards(); 945 this.mockGlobals.stubs().setBackgroundEnable(ANYTHING); 946 this.mockGlobals.stubs().setShouldPollCards(ANYTHING); 947 this.mockGlobals.stubs().setShouldPollOptInStatus(ANYTHING); 948 949 this.mockGlobals.expects(never()).recordEvent( 950 GoogleNowEvent.STOPPED); 951 this.mockGlobals.expects(never()).recordEvent( 952 GoogleNowEvent.SIGNED_OUT); 953 this.mockGlobals.expects(never()).recordEvent( 954 GoogleNowEvent.NOTIFICATION_DISABLED); 955 this.mockGlobals.expects(once()).recordEvent( 956 GoogleNowEvent.GOOGLE_NOW_DISABLED); 957 updateRunningState(signedIn, true, notificationEnabled, googleNowEnabled); 958 }); 959 960 TEST_F(TEST_NAME, 'NoCardsEverythingEnabled', function() { 961 var signedIn = true; 962 var notificationEnabled = true; 963 var googleNowEnabled = true; 964 this.makeAndRegisterMockGlobals([ 965 'recordEvent', 966 'removeAllCards', 967 'setBackgroundEnable', 968 'setShouldPollCards', 969 'setShouldPollOptInStatus']); 970 971 this.mockGlobals.stubs().removeAllCards(); 972 this.mockGlobals.stubs().setBackgroundEnable(ANYTHING); 973 this.mockGlobals.stubs().setShouldPollCards(ANYTHING); 974 this.mockGlobals.stubs().setShouldPollOptInStatus(ANYTHING); 975 976 this.mockGlobals.expects(never()).recordEvent( 977 GoogleNowEvent.STOPPED); 978 this.mockGlobals.expects(never()).recordEvent( 979 GoogleNowEvent.SIGNED_OUT); 980 this.mockGlobals.expects(never()).recordEvent( 981 GoogleNowEvent.NOTIFICATION_DISABLED); 982 this.mockGlobals.expects(never()).recordEvent( 983 GoogleNowEvent.GOOGLE_NOW_DISABLED); 984 updateRunningState(signedIn, true, notificationEnabled, googleNowEnabled); 985 }); 986 987 /** 988 * Mocks global functions and APIs that onNotificationClicked() depends upon. 989 * @param {Test} fixture Test fixture. 990 */ 991 function mockOnNotificationClickedDependencies(fixture) { 992 fixture.makeAndRegisterMockApis([ 993 'chrome.windows.create', 994 'chrome.windows.update', 995 'fillFromChromeLocalStorage', 996 'instrumented.tabs.create']); 997 } 998 999 TEST_F(TEST_NAME, 'OnNotificationClicked_NoData', function() { 1000 // Tests the case when there is no data associated with notification id. 1001 // In this case, the function should do nothing. 1002 1003 // Setup and expectations. 1004 var testNotificationId = 'TEST_ID'; 1005 var testNotificationDataRequest = {notificationsData: {}}; 1006 var testNotificationData = {notificationsData: {}}; 1007 1008 mockOnNotificationClickedDependencies(this); 1009 this.makeMockLocalFunctions(['selector']); 1010 1011 expectChromeLocalStorageGet( 1012 this, testNotificationDataRequest, testNotificationData); 1013 1014 // Invoking the tested function. 1015 onNotificationClicked( 1016 testNotificationId, this.mockLocalFunctions.functions().selector); 1017 }); 1018 1019 TEST_F(TEST_NAME, 'OnNotificationClicked_ActionUrlsUndefined', function() { 1020 // Tests the case when the data associated with notification id is 1021 // 'undefined'. 1022 // In this case, the function should do nothing. 1023 1024 // Setup and expectations. 1025 var testActionUrls = undefined; 1026 var testNotificationId = 'TEST_ID'; 1027 var testNotificationDataRequest = {notificationsData: {}}; 1028 var testNotificationData = { 1029 notificationsData: {'TEST_ID': {actionUrls: testActionUrls}} 1030 }; 1031 1032 mockOnNotificationClickedDependencies(this); 1033 this.makeMockLocalFunctions(['selector']); 1034 1035 expectChromeLocalStorageGet( 1036 this, testNotificationDataRequest, testNotificationData); 1037 1038 this.mockLocalFunctions.expects(once()) 1039 .selector(eqJSON( 1040 testNotificationData.notificationsData[testNotificationId])) 1041 .will(returnValue(undefined)); 1042 1043 // Invoking the tested function. 1044 onNotificationClicked( 1045 testNotificationId, this.mockLocalFunctions.functions().selector); 1046 }); 1047 1048 TEST_F(TEST_NAME, 'OnNotificationClicked_TabCreateSuccess', function() { 1049 // Tests the selected URL is OK and crome.tabs.create suceeds. 1050 1051 // Setup and expectations. 1052 var testActionUrls = {testField: 'TEST VALUE'}; 1053 var testNotificationId = 'TEST_ID'; 1054 var testNotificationDataRequest = {notificationsData: {}}; 1055 var testNotificationData = { 1056 notificationsData: {'TEST_ID': {actionUrls: testActionUrls}} 1057 }; 1058 var testActionUrl = 'http://testurl.com'; 1059 var testCreatedTab = {windowId: 239}; 1060 1061 mockOnNotificationClickedDependencies(this); 1062 this.makeMockLocalFunctions(['selector']); 1063 1064 expectChromeLocalStorageGet( 1065 this, testNotificationDataRequest, testNotificationData); 1066 this.mockLocalFunctions.expects(once()) 1067 .selector(eqJSON( 1068 testNotificationData.notificationsData[testNotificationId])) 1069 .will(returnValue(testActionUrl)); 1070 var chromeTabsCreateSavedArgs = new SaveMockArguments(); 1071 this.mockApis.expects(once()). 1072 instrumented_tabs_create( 1073 chromeTabsCreateSavedArgs.match(eqJSON({url: testActionUrl})), 1074 chromeTabsCreateSavedArgs.match(ANYTHING)). 1075 will(invokeCallback(chromeTabsCreateSavedArgs, 1, testCreatedTab)); 1076 this.mockApis.expects(once()).chrome_windows_update( 1077 testCreatedTab.windowId, 1078 eqJSON({focused: true})); 1079 1080 // Invoking the tested function. 1081 onNotificationClicked( 1082 testNotificationId, this.mockLocalFunctions.functions().selector); 1083 }); 1084 1085 TEST_F(TEST_NAME, 'OnNotificationClicked_TabCreateFail', function() { 1086 // Tests the selected URL is OK and crome.tabs.create fails. 1087 // In this case, the function should invoke chrome.windows.create as a 1088 // second attempt. 1089 1090 // Setup and expectations. 1091 var testActionUrls = {testField: 'TEST VALUE'}; 1092 var testNotificationId = 'TEST_ID'; 1093 var testNotificationDataRequest = {notificationsData: {}}; 1094 var testNotificationData = { 1095 notificationsData: {'TEST_ID': {actionUrls: testActionUrls}} 1096 }; 1097 var testActionUrl = 'http://testurl.com'; 1098 var testCreatedTab = undefined; // chrome.tabs.create fails 1099 1100 mockOnNotificationClickedDependencies(this); 1101 this.makeMockLocalFunctions(['selector']); 1102 1103 expectChromeLocalStorageGet( 1104 this, testNotificationDataRequest, testNotificationData); 1105 this.mockLocalFunctions.expects(once()) 1106 .selector(eqJSON( 1107 testNotificationData.notificationsData[testNotificationId])) 1108 .will(returnValue(testActionUrl)); 1109 var chromeTabsCreateSavedArgs = new SaveMockArguments(); 1110 this.mockApis.expects(once()). 1111 instrumented_tabs_create( 1112 chromeTabsCreateSavedArgs.match(eqJSON({url: testActionUrl})), 1113 chromeTabsCreateSavedArgs.match(ANYTHING)). 1114 will(invokeCallback(chromeTabsCreateSavedArgs, 1, testCreatedTab)); 1115 this.mockApis.expects(once()).chrome_windows_create( 1116 eqJSON({url: testActionUrl, focused: true})); 1117 1118 // Invoking the tested function. 1119 onNotificationClicked( 1120 testNotificationId, this.mockLocalFunctions.functions().selector); 1121 }); 1122 1123 TEST_F(TEST_NAME, 'ShowNotificationGroups', function() { 1124 // Tests showNotificationGroups function. Checks that the function properly 1125 // deletes the card that didn't get an update, updates existing card and 1126 // creates a new card that previously didn't exist. 1127 1128 // Setup and expectations. 1129 var existingNotifications = { 1130 'SHOULD BE DELETED': 'SOMETHING', 1131 'SHOULD BE KEPT': 'SOMETHING' 1132 }; 1133 1134 var keptCard = { 1135 chromeNotificationId: 'SHOULD BE KEPT', 1136 trigger: {showTimeSec: 0, hideTimeSec: 0} 1137 }; 1138 1139 var keptNotification = { 1140 receivedNotification: keptCard, 1141 showTime: 0, 1142 hideTime: 0 1143 }; 1144 1145 var newCard = { 1146 chromeNotificationId: 'NEW CARD', 1147 trigger: {showTimeSec: 0, hideTimeSec: 0} 1148 }; 1149 1150 var newNotification = { 1151 receivedNotification: newCard, 1152 showTime: 0, 1153 hideTime: 0 1154 }; 1155 1156 var notificationGroups = { 1157 'TEST GROUP 1': {cards: [keptCard], cardsTimestamp: 0}, 1158 'TEST GROUP 2': {cards: [newCard], cardsTimestamp: 0} 1159 }; 1160 1161 var fakeOnCardShownFunction = 'FAKE ON CARD SHOWN FUNCTION'; 1162 1163 var expectedUpdatedNotifications = { 1164 'SHOULD BE KEPT': 'KEPT CARD NOTIFICATION DATA', 1165 'NEW CARD': 'NEW CARD NOTIFICATION DATA' 1166 }; 1167 1168 this.makeAndRegisterMockApis([ 1169 'cardSet.update', 1170 'chrome.storage.local.set', 1171 'instrumented.notifications.getAll' 1172 ]); 1173 this.makeMockLocalFunctions([ 1174 'onSuccess' 1175 ]); 1176 1177 var notificationsGetAllSavedArgs = new SaveMockArguments(); 1178 this.mockApis.expects(once()). 1179 instrumented_notifications_getAll( 1180 notificationsGetAllSavedArgs.match(ANYTHING)). 1181 will(invokeCallback( 1182 notificationsGetAllSavedArgs, 0, existingNotifications)); 1183 1184 this.mockApis.expects(once()). 1185 cardSet_update( 1186 'SHOULD BE KEPT', 1187 eqJSON([keptNotification]), 1188 eqJSON(notificationGroups), 1189 fakeOnCardShownFunction). 1190 will(returnValue('KEPT CARD NOTIFICATION DATA')); 1191 this.mockApis.expects(once()). 1192 cardSet_update( 1193 'NEW CARD', 1194 eqJSON([newNotification]), 1195 eqJSON(notificationGroups), 1196 fakeOnCardShownFunction). 1197 will(returnValue('NEW CARD NOTIFICATION DATA')); 1198 this.mockApis.expects(once()). 1199 cardSet_update( 1200 'SHOULD BE DELETED', 1201 [], 1202 eqJSON(notificationGroups), 1203 fakeOnCardShownFunction). 1204 will(returnValue(undefined)); 1205 1206 this.mockApis.expects(once()). 1207 chrome_storage_local_set( 1208 eqJSON({notificationsData: expectedUpdatedNotifications})); 1209 1210 this.mockLocalFunctions.expects(once()). 1211 onSuccess(undefined); 1212 1213 // Invoking the tested function. 1214 showNotificationGroups(notificationGroups, fakeOnCardShownFunction) 1215 .then(this.mockLocalFunctions.functions().onSuccess); 1216 }); 1217 1218 TEST_F(TEST_NAME, 'ProcessServerResponse', function() { 1219 // Tests processServerResponse function. 1220 1221 // Setup and expectations. 1222 Date.now = function() { return 3000000; }; 1223 1224 // GROUP1 was requested and contains cards c4 and c5. For c5, there is a 1225 // non-expired dismissal, so it will be ignored. 1226 // GROUP2 was not requested, but is contained in server response to 1227 // indicate that the group still exists. Stored group GROUP2 won't change. 1228 // GROUP3 is stored, but is not present in server's response, which means 1229 // it doesn't exist anymore. This group will be deleted. 1230 // GROUP4 doesn't contain cards, but it was requested. This is treated as 1231 // if it had an empty array of cards. Cards in the stored group will be 1232 // replaced with an empty array. 1233 // GROUP5 doesn't have next poll time, and it will be stored without next 1234 // poll time. 1235 var serverResponse = { 1236 groups: { 1237 GROUP1: {requested: true, nextPollSeconds: 46}, 1238 GROUP2: {requested: false}, 1239 GROUP4: {requested: true, nextPollSeconds: 45}, 1240 GROUP5: {requested: true} 1241 }, 1242 notifications: [ 1243 {notificationId: 'c4', groupName: 'GROUP1'}, 1244 {notificationId: 'c5', groupName: 'GROUP1'} 1245 ] 1246 }; 1247 1248 var recentDismissals = { 1249 c4: 1800000, // expired dismissal 1250 c5: 1800001 // non-expired dismissal 1251 }; 1252 1253 var storedGroups = { 1254 GROUP2: { 1255 cards: [{notificationId: 'c2'}], 1256 cardsTimestamp: 239, 1257 nextPollTime: 10000 1258 }, 1259 GROUP3: { 1260 cards: [{notificationId: 'c3'}], 1261 cardsTimestamp: 240, 1262 nextPollTime: 10001 1263 }, 1264 GROUP4: { 1265 cards: [{notificationId: 'c6'}], 1266 cardsTimestamp: 241, 1267 nextPollTime: 10002 1268 } 1269 }; 1270 1271 var expectedUpdatedGroups = { 1272 GROUP1: { 1273 cards: [{notificationId: 'c4', groupName: 'GROUP1'}], 1274 cardsTimestamp: 3000000, 1275 nextPollTime: 3046000 1276 }, 1277 GROUP2: { 1278 cards: [{notificationId: 'c2'}], 1279 cardsTimestamp: 239, 1280 nextPollTime: 10000 1281 }, 1282 GROUP4: { 1283 cards: [], 1284 cardsTimestamp: 3000000, 1285 nextPollTime: 3045000 1286 }, 1287 GROUP5: { 1288 cards: [], 1289 cardsTimestamp: 3000000 1290 } 1291 }; 1292 1293 var expectedUpdatedRecentDismissals = { 1294 c5: 1800001 1295 }; 1296 1297 this.makeAndRegisterMockGlobals([ 1298 'scheduleNextCardsPoll' 1299 ]); 1300 1301 this.makeAndRegisterMockApis([ 1302 'fillFromChromeLocalStorage', 1303 ]); 1304 1305 expectChromeLocalStorageGet( 1306 this, 1307 { 1308 notificationGroups: {}, 1309 recentDismissals: {} 1310 }, 1311 { 1312 notificationGroups: storedGroups, 1313 recentDismissals: recentDismissals 1314 }); 1315 1316 this.mockGlobals.expects(once()) 1317 .scheduleNextCardsPoll(eqJSON(expectedUpdatedGroups)); 1318 1319 // Invoking the tested function. 1320 processServerResponse(serverResponse); 1321 }); 1322 1323 TEST_F(TEST_NAME, 'ProcessServerResponseGoogleNowDisabled', function() { 1324 // Tests processServerResponse function for the case when the response 1325 // indicates that Google Now is disabled. 1326 1327 // Setup and expectations. 1328 var serverResponse = { 1329 googleNowDisabled: true, 1330 groups: {} 1331 }; 1332 1333 this.makeAndRegisterMockGlobals([ 1334 'scheduleNextCardsPoll' 1335 ]); 1336 1337 this.makeAndRegisterMockApis([ 1338 'chrome.storage.local.set', 1339 'fillFromChromeLocalStorage' 1340 ]); 1341 1342 this.mockApis.expects(once()). 1343 chrome_storage_local_set(eqJSON({googleNowEnabled: false})); 1344 1345 this.mockGlobals.expects(never()).scheduleNextCardsPoll(); 1346 1347 // Invoking the tested function. 1348 processServerResponse(serverResponse); 1349 }); 1350 1351