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.
5 // TODO(robliao,vadimt): Determine the granularity of testing to perform.
8 * Test fixture for background.js.
10 * @extends {testing.Test}
12 function GoogleNowBackgroundUnitTest () {
13 testing.Test.call(this);
16 GoogleNowBackgroundUnitTest.prototype = {
17 __proto__: testing.Test.prototype,
21 'common_test_util.js',
22 'background_test_util.js',
27 var TEST_NAME = 'GoogleNowBackgroundUnitTest';
32 TEST_F(TEST_NAME, 'AreTasksConflicting', function() {
33 function testTaskPair(newTaskName, scheduledTaskName, expected) {
34 assertTrue(areTasksConflicting(newTaskName, scheduledTaskName) == expected,
35 '(' + newTaskName + ', ' + scheduledTaskName + ')');
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);
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);
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);
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);
60 * Server Request Tests
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 === '{}');
70 assertTrue(callbackCalled);
73 TEST_F(TEST_NAME, 'AuthServerRequestForbidden', function() {
74 this.makeAndRegisterMockApis(['authenticationManager.removeToken']);
75 this.mockApis.expects(once()).authenticationManager_removeToken(ANYTHING);
77 expectServerRequests(this, 403, '');
79 var thenCalled = false;
80 var catchCalled = false;
81 requestFromServer('GET', 'test/target').then(function(request) {
83 }).catch(function(request) {
84 // The promise is rejected on HTTP failures.
86 assertTrue(request.status === 403);
88 assertFalse(thenCalled);
89 assertTrue(catchCalled);
92 TEST_F(TEST_NAME, 'AuthServerRequestNoAuth', function() {
93 this.makeAndRegisterMockApis(['authenticationManager.removeToken']);
94 this.mockApis.expects(once()).authenticationManager_removeToken(ANYTHING);
96 expectServerRequests(this, 401, '');
98 var thenCalled = false;
99 var catchCalled = false;
100 requestFromServer('GET', 'test/target').then(function(request) {
102 }).catch(function(request) {
103 // The promise is rejected on HTTP failures.
105 assertTrue(request.status === 401);
107 assertFalse(thenCalled);
108 assertTrue(catchCalled);
111 function expectServerRequests(fixture, httpStatus, responseText) {
112 fixture.makeAndRegisterMockApis([
113 'authenticationManager.getAuthToken',
117 function XMLHttpRequest() {}
119 XMLHttpRequest.prototype = {
120 addEventListener: function(type, listener, wantsUntrusted) {},
121 setRequestHeader: function(header, value) {},
125 fixture.mockApis.expects(once()).authenticationManager_getAuthToken()
126 .will(returnValue(Promise.resolve('token')));
128 var mockXMLHttpRequest = mock(XMLHttpRequest);
129 var mockXMLHttpRequestProxy = mockXMLHttpRequest.proxy();
130 fixture.mockApis.expects(once())
131 .buildServerRequest(ANYTHING, ANYTHING, ANYTHING)
132 .will(returnValue(mockXMLHttpRequestProxy));
134 mockXMLHttpRequest.expects(once())
135 .setRequestHeader('Authorization', 'Bearer token');
137 var loadEndSavedArgs = new SaveMockArguments();
138 mockXMLHttpRequest.expects(once())
140 loadEndSavedArgs.match(eq('loadend')),
141 loadEndSavedArgs.match(ANYTHING),
142 loadEndSavedArgs.match(eq(false)));
144 mockXMLHttpRequestProxy.status = httpStatus;
145 mockXMLHttpRequestProxy.response = responseText;
146 mockXMLHttpRequestProxy.responseText = responseText;
148 mockXMLHttpRequest.expects(once()).send()
149 .will(invokeCallback(loadEndSavedArgs, 1, mockXMLHttpRequestProxy));
152 TEST_F(TEST_NAME, 'AuthServerRequestNoToken', function() {
153 this.makeAndRegisterMockApis([
154 'authenticationManager.getAuthToken',
158 this.mockApis.expects(once()).authenticationManager_getAuthToken()
159 .will(returnValue(Promise.reject()));
160 this.mockApis.expects(never()).buildServerRequest()
162 var thenCalled = false;
163 var catchCalled = false;
164 requestFromServer('GET', 'test/target').then(function(request) {
166 }).catch(function() {
169 assertFalse(thenCalled);
170 assertTrue(catchCalled);
174 * requestNotificationGroupsFromServer Tests
176 TEST_F(TEST_NAME, 'RequestNotificationGroupsFromServerEmpty', function() {
177 this.makeAndRegisterMockGlobals([
178 'shouldShowExplanatoryCard',
183 this.mockGlobals.expects(once()).shouldShowExplanatoryCard()
184 .will(returnValue(false));
186 this.mockGlobals.expects(once()).recordEvent(
187 GoogleNowEvent.REQUEST_FOR_CARDS_TOTAL);
189 this.mockGlobals.expects(once()).recordEvent(
190 GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS);
192 var requestFromServerArgs = new SaveMockArguments();
193 this.mockGlobals.expects(once()).requestFromServer(
194 requestFromServerArgs.match(eq('GET')),
195 requestFromServerArgs.match(ANYTHING))
197 Promise.resolve({status: 200, responseText: "{}"})));
199 var thenCalled = false;
200 var catchCalled = false;
201 requestNotificationGroupsFromServer([]).then(function() {
203 }).catch(function() {
206 assertTrue(thenCalled);
207 assertFalse(catchCalled);
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);
216 TEST_F(TEST_NAME, 'RequestNotificationGroupsFromServerWithGroups', function() {
217 this.makeAndRegisterMockGlobals([
218 'shouldShowExplanatoryCard',
223 this.mockGlobals.expects(once()).shouldShowExplanatoryCard()
224 .will(returnValue(false));
226 this.mockGlobals.expects(once()).recordEvent(
227 GoogleNowEvent.REQUEST_FOR_CARDS_TOTAL);
229 this.mockGlobals.expects(once()).recordEvent(
230 GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS);
232 var requestFromServerArgs = new SaveMockArguments();
233 this.mockGlobals.expects(once()).requestFromServer(
234 requestFromServerArgs.match(eq('GET')),
235 requestFromServerArgs.match(ANYTHING))
237 Promise.resolve({status: 200, responseText: "{}"})));
239 var thenCalled = false;
240 var catchCalled = false;
241 requestNotificationGroupsFromServer(['A', 'B', 'C']).then(function() {
243 }).catch(function() {
246 assertTrue(thenCalled);
247 assertFalse(catchCalled);
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);
259 TEST_F(TEST_NAME, 'RequestNotificationGroupsFromServerExplanatory', function() {
260 this.makeAndRegisterMockGlobals([
261 'shouldShowExplanatoryCard',
266 this.mockGlobals.expects(once()).shouldShowExplanatoryCard()
267 .will(returnValue(true));
269 this.mockGlobals.expects(once()).recordEvent(
270 GoogleNowEvent.REQUEST_FOR_CARDS_TOTAL);
272 this.mockGlobals.expects(once()).recordEvent(
273 GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS);
275 var requestFromServerArgs = new SaveMockArguments();
276 this.mockGlobals.expects(once()).requestFromServer(
277 requestFromServerArgs.match(eq('GET')),
278 requestFromServerArgs.match(ANYTHING))
280 Promise.resolve({status: 200, responseText: "{}"})));
282 var thenCalled = false;
283 var catchCalled = false;
284 requestNotificationGroupsFromServer([]).then(function() {
286 }).catch(function() {
289 assertTrue(thenCalled);
290 assertFalse(catchCalled);
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);
299 TEST_F(TEST_NAME, 'RequestNotificationGroupsFromServerFailure', function() {
300 this.makeAndRegisterMockGlobals([
301 'shouldShowExplanatoryCard',
306 this.mockGlobals.expects(once()).shouldShowExplanatoryCard()
307 .will(returnValue(false));
309 this.mockGlobals.expects(once()).recordEvent(
310 GoogleNowEvent.REQUEST_FOR_CARDS_TOTAL);
312 this.mockGlobals.expects(never()).recordEvent(
313 GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS);
315 var requestFromServerArgs = new SaveMockArguments();
316 this.mockGlobals.expects(once()).requestFromServer(
317 requestFromServerArgs.match(eq('GET')),
318 requestFromServerArgs.match(ANYTHING))
320 Promise.reject({status: 401})));
322 var thenCalled = false;
323 var catchCalled = false;
324 requestNotificationGroupsFromServer([]).then(function() {
326 }).catch(function() {
329 assertFalse(thenCalled);
330 assertTrue(catchCalled);
334 * shouldScheduleRetryFromGroupList Tests
336 TEST_F(TEST_NAME, 'ShouldScheduleRetryEmptyGroupList', function() {
337 assertTrue(shouldScheduleRetryFromGroupList([]));
340 TEST_F(TEST_NAME, 'ShouldScheduleRetryNorOnlyGroupList', function() {
341 assertFalse(shouldScheduleRetryFromGroupList(['NOR']));
344 TEST_F(TEST_NAME, 'ShouldScheduleRetryNotOnlyGroupList', function() {
345 assertTrue(shouldScheduleRetryFromGroupList(['NOT']));
348 TEST_F(TEST_NAME, 'ShouldScheduleRetryMultipleGroupsList', function() {
349 assertTrue(shouldScheduleRetryFromGroupList(['NOR', 'NOT']));
353 * requestAndUpdateOptIn Tests
355 TEST_F(TEST_NAME, 'RequestAndUpdateOptInOptedIn', function() {
356 this.makeAndRegisterMockApis([
357 'chrome.storage.local.set',
361 this.mockApis.expects(once()).requestFromServer('GET', 'settings/optin')
362 .will(returnValue(Promise.resolve({
364 responseText: '{"value": true}'})));
366 this.mockApis.expects(once())
367 .chrome_storage_local_set(eqJSON({googleNowEnabled: true}));
369 var thenCalled = false;
370 var catchCalled = false;
371 requestAndUpdateOptedIn().then(function(optedIn) {
374 }).catch(function() {
377 assertTrue(thenCalled);
378 assertFalse(catchCalled);
381 TEST_F(TEST_NAME, 'RequestAndUpdateOptInOptedOut', function() {
382 this.makeAndRegisterMockApis([
383 'chrome.storage.local.set',
387 this.mockApis.expects(once()).requestFromServer('GET', 'settings/optin')
388 .will(returnValue(Promise.resolve({
390 responseText: '{"value": false}'})));
392 this.mockApis.expects(once())
393 .chrome_storage_local_set(eqJSON({googleNowEnabled: false}));
395 var thenCalled = false;
396 var catchCalled = false;
397 requestAndUpdateOptedIn().then(function(optedIn) {
399 assertFalse(optedIn);
400 }).catch(function() {
403 assertTrue(thenCalled);
404 assertFalse(catchCalled);
407 TEST_F(TEST_NAME, 'RequestAndUpdateOptInFailure', function() {
408 this.makeAndRegisterMockApis([
409 'chrome.storage.local.set',
413 this.mockApis.expects(once()).requestFromServer('GET', 'settings/optin')
414 .will(returnValue(Promise.reject({status: 404})));
416 this.mockApis.expects(never()).chrome_storage_local_set();
418 var thenCalled = false;
419 var catchCalled = false;
420 requestAndUpdateOptedIn().then(function() {
422 }).catch(function() {
425 assertFalse(thenCalled);
426 assertTrue(catchCalled);
430 * pollOptedInNoImmediateRecheck Tests
432 TEST_F(TEST_NAME, 'pollOptedInNoImmediateRecheckOptedIn', function() {
433 this.makeAndRegisterMockApis([
434 'requestAndUpdateOptedIn',
435 'instrumented.metricsPrivate.getVariationParams',
436 'optInPollAttempts.start'
439 this.mockApis.expects(once()).requestAndUpdateOptedIn()
440 .will(returnValue(Promise.resolve(true)));
442 this.mockApis.expects(never())
443 .instrumented_metricsPrivate_getVariationParams();
445 this.mockApis.expects(never()).optInPollAttempts_start();
447 pollOptedInNoImmediateRecheck();
450 TEST_F(TEST_NAME, 'pollOptedInNoImmediateRecheckOptedOut', function() {
451 this.makeAndRegisterMockApis([
452 'requestAndUpdateOptedIn',
453 'instrumented.metricsPrivate.getVariationParams',
454 'optInPollAttempts.start'
457 this.mockApis.expects(once()).requestAndUpdateOptedIn()
458 .will(returnValue(Promise.resolve(false)));
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, {}));
467 this.mockApis.expects(once())
468 .optInPollAttempts_start(DEFAULT_OPTIN_CHECK_PERIOD_SECONDS);
470 pollOptedInNoImmediateRecheck();
473 TEST_F(TEST_NAME, 'pollOptedInNoImmediateRecheckFailure', function() {
474 this.makeAndRegisterMockApis([
475 'requestAndUpdateOptedIn',
476 'instrumented.metricsPrivate.getVariationParams',
477 'optInPollAttempts.start'
480 this.mockApis.expects(once()).requestAndUpdateOptedIn()
481 .will(returnValue(Promise.reject()));
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, {}));
490 this.mockApis.expects(once())
491 .optInPollAttempts_start(DEFAULT_OPTIN_CHECK_PERIOD_SECONDS);
493 pollOptedInNoImmediateRecheck();
497 * getGroupsToRequest Tests
499 TEST_F(TEST_NAME, 'GetGroupsToRequestNone', function() {
500 this.makeAndRegisterMockApis([
501 'fillFromChromeLocalStorage',
505 this.mockApis.expects(once())
506 .fillFromChromeLocalStorage(eqJSON({notificationGroups: {}}))
507 .will(returnValue(Promise.resolve({notificationGroups: {}})));
509 this.mockApis.expects(once()).Date_now().will(returnValue(20));
511 getGroupsToRequest().then(function(groupsToRequest) {
512 assertTrue(JSON.stringify(groupsToRequest) === '[]');
516 TEST_F(TEST_NAME, 'GetGroupsToRequestWithGroups', function() {
517 this.makeAndRegisterMockApis([
518 'fillFromChromeLocalStorage',
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},
533 this.mockApis.expects(once()).Date_now().will(returnValue(20));
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);
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.
551 // Setup and expectations.
552 var combinedCards = {
556 var receivedNotificationNoShowTime = {
557 chromeNotificationId: 'EXISTING CARD',
558 trigger: {hideTimeSec: 1}
560 var receivedNotificationWithShowTime = {
561 chromeNotificationId: 'NEW CARD',
562 trigger: {showTimeSec: 2, hideTimeSec: 3}
566 cardsTimestamp: 10000,
568 receivedNotificationNoShowTime,
569 receivedNotificationWithShowTime
573 // Invoking the tested function.
574 combineGroup(combinedCards, storedGroup);
576 // Check the output value.
577 var expectedCombinedCards = {
581 receivedNotification: receivedNotificationNoShowTime,
587 receivedNotification: receivedNotificationWithShowTime,
595 JSON.stringify(expectedCombinedCards),
596 JSON.stringify(combinedCards));
600 * Mocks global functions and APIs that initialize() depends upon.
601 * @param {Test} fixture Test fixture.
603 function mockInitializeDependencies(fixture) {
604 fixture.makeAndRegisterMockGlobals([
605 'pollOptedInNoImmediateRecheck',
608 'setBackgroundEnable',
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',
623 'updateCardsAttempts.isRunning',
624 'updateCardsAttempts.stop'
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
643 function expectStateMachineCalls(
646 testExperimentVariationParams,
647 testNotificationPermissionLevel,
648 testGoogleNowEnabled) {
649 fixture.mockApis.expects(once()).
650 authenticationManager_isSignedIn().
651 will(returnValue(new Promise(function(resolve) {
652 resolve(!!testIdentityToken);
655 var getVariationParamsSavedArgs = new SaveMockArguments();
656 fixture.mockApis.expects(once()).
657 instrumented_metricsPrivate_getVariationParams(
658 getVariationParamsSavedArgs.match(ANYTHING),
659 getVariationParamsSavedArgs.match(ANYTHING)).
661 getVariationParamsSavedArgs, 1, testExperimentVariationParams));
663 var notificationGetPermissionLevelSavedArgs = new SaveMockArguments();
664 fixture.mockApis.expects(once()).
665 instrumented_notifications_getPermissionLevel(
666 notificationGetPermissionLevelSavedArgs.match(ANYTHING)).
668 notificationGetPermissionLevelSavedArgs,
670 testNotificationPermissionLevel))
672 expectChromeLocalStorageGet(
674 {googleNowEnabled: false},
675 {googleNowEnabled: testGoogleNowEnabled});
677 var updateCardsAttemptsIsRunningSavedArgs = new SaveMockArguments();
678 fixture.mockApis.expects(once()).
679 updateCardsAttempts_isRunning(
680 updateCardsAttemptsIsRunningSavedArgs.match(ANYTHING)).
683 updateCardsAttemptsIsRunningSavedArgs, 0, undefined));
685 var optInPollAttemptsIsRunningSavedArgs = new SaveMockArguments();
686 fixture.mockApis.expects(once()).
687 optInPollAttempts_isRunning(
688 optInPollAttemptsIsRunningSavedArgs.match(ANYTHING)).
691 optInPollAttemptsIsRunningSavedArgs, 0, undefined));
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.
701 function expectInitialization(fixture) {
702 var tasksAddSavedArgs = new SaveMockArguments();
703 fixture.mockApis.expects(once()).
705 tasksAddSavedArgs.match(ANYTHING),
706 tasksAddSavedArgs.match(ANYTHING)).
707 will(invokeCallback(tasksAddSavedArgs, 1, function() {}));
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);
715 expects(once()).recordEvent(GoogleNowEvent.EXTENSION_START);
716 fixture.mockApis.expects(once())
717 .fillFromChromeLocalStorage(eqJSON({gcmNotificationKey: undefined}))
718 .will(returnValue(Promise.resolve({gcmNotificationKey: 'gcmkey'})));
722 TEST_F(TEST_NAME,'Initialize_SignedOut', function() {
723 // Tests the case when getAuthToken fails most likely because the user is
724 // not signed in. In this case, the function should quietly exit after
725 // finding out that getAuthToken fails.
727 // Setup and expectations.
728 var testIdentityToken = undefined;
729 var testExperimentVariationParams = {};
730 var testNotificationPermissionLevel = 'denied';
731 var testGoogleNowEnabled = undefined;
733 mockInitializeDependencies(this);
735 expectInitialization(this);
737 expectStateMachineCalls(
740 testExperimentVariationParams,
741 testNotificationPermissionLevel,
742 testGoogleNowEnabled);
744 this.mockGlobals.expects(once()).setBackgroundEnable(false);
745 this.mockGlobals.expects(never()).startPollingCards();
746 this.mockGlobals.expects(once()).stopPollingCards();
747 this.mockGlobals.expects(once()).removeAllCards();
748 this.mockGlobals.expects(never()).pollOptedInNoImmediateRecheck();
749 this.mockApis.expects(once()).optInPollAttempts_stop();
751 // Invoking the tested function.
755 TEST_F(TEST_NAME,'Initialize_NotificationDisabled', function() {
756 // Tests the case when Google Now is disabled in the notifications center.
758 // Setup and expectations.
759 var testIdentityToken = 'some identity token';
760 var testExperimentVariationParams = {};
761 var testNotificationPermissionLevel = 'denied';
762 var testGoogleNowEnabled = undefined;
764 mockInitializeDependencies(this);
766 expectInitialization(this);
768 expectStateMachineCalls(
771 testExperimentVariationParams,
772 testNotificationPermissionLevel,
773 testGoogleNowEnabled);
775 this.mockGlobals.expects(once()).setBackgroundEnable(false);
776 this.mockGlobals.expects(never()).startPollingCards();
777 this.mockGlobals.expects(once()).stopPollingCards();
778 this.mockGlobals.expects(once()).removeAllCards();
779 this.mockGlobals.expects(never()).pollOptedInNoImmediateRecheck();
780 this.mockApis.expects(once()).optInPollAttempts_stop();
782 // Invoking the tested function.
786 TEST_F(TEST_NAME, 'Initialize_NoBackground', function() {
787 // Tests when the no background variation is received.
789 // Setup and expectations.
790 var testIdentityToken = 'some identity token';
791 var testExperimentVariationParams = {canEnableBackground: 'false'};
792 var testNotificationPermissionLevel = 'granted';
793 var testGoogleNowEnabled = true;
795 mockInitializeDependencies(this);
797 expectInitialization(this);
799 expectStateMachineCalls(
802 testExperimentVariationParams,
803 testNotificationPermissionLevel,
804 testGoogleNowEnabled);
806 this.mockGlobals.expects(once()).setBackgroundEnable(false);
807 this.mockGlobals.expects(once()).startPollingCards();
808 this.mockGlobals.expects(never()).stopPollingCards();
809 this.mockGlobals.expects(never()).removeAllCards();
810 this.mockGlobals.expects(never()).pollOptedInNoImmediateRecheck();
811 this.mockApis.expects(once()).optInPollAttempts_stop();
813 // Invoking the tested function.
817 TEST_F(TEST_NAME, 'Initialize_GoogleNowDisabled', function() {
818 // Tests when the user has Google Now disabled.
820 // Setup and expectations.
821 var testIdentityToken = 'some identity token';
822 var testExperimentVariationParams = {};
823 var testNotificationPermissionLevel = 'granted';
824 var testGoogleNowEnabled = false;
826 mockInitializeDependencies(this);
828 expectInitialization(this);
830 expectStateMachineCalls(
833 testExperimentVariationParams,
834 testNotificationPermissionLevel,
835 testGoogleNowEnabled);
837 this.mockGlobals.expects(once()).setBackgroundEnable(false);
838 this.mockGlobals.expects(never()).startPollingCards();
839 this.mockGlobals.expects(once()).stopPollingCards();
840 this.mockGlobals.expects(once()).removeAllCards();
841 this.mockGlobals.expects(once()).pollOptedInNoImmediateRecheck();
842 this.mockApis.expects(never()).optInPollAttempts_stop();
844 // Invoking the tested function.
848 TEST_F(TEST_NAME, 'Initialize_RunGoogleNow', function() {
849 // Tests if Google Now will invoke startPollingCards when all
850 // of the required state is fulfilled.
852 // Setup and expectations.
853 var testIdentityToken = 'some identity token';
854 var testExperimentVariationParams = {};
855 var testNotificationPermissionLevel = 'granted';
856 var testGoogleNowEnabled = true;
858 mockInitializeDependencies(this);
860 expectInitialization(this);
862 expectStateMachineCalls(
865 testExperimentVariationParams,
866 testNotificationPermissionLevel,
867 testGoogleNowEnabled);
869 this.mockGlobals.expects(once()).setBackgroundEnable(true);
870 this.mockGlobals.expects(once()).startPollingCards();
871 this.mockGlobals.expects(never()).stopPollingCards();
872 this.mockGlobals.expects(never()).removeAllCards();
873 this.mockGlobals.expects(never()).pollOptedInNoImmediateRecheck();
874 this.mockApis.expects(once()).optInPollAttempts_stop();
876 // Invoking the tested function.
881 * No Cards Event Recording Tests
883 TEST_F(TEST_NAME, 'NoCardsSignedOut', function() {
884 var signedIn = false;
885 var notificationEnabled = false;
886 var googleNowEnabled = false;
887 this.makeAndRegisterMockGlobals([
890 'setBackgroundEnable',
891 'setShouldPollCards',
892 'setShouldPollOptInStatus']);
894 this.mockGlobals.stubs().removeAllCards();
895 this.mockGlobals.stubs().setBackgroundEnable(ANYTHING);
896 this.mockGlobals.stubs().setShouldPollCards(ANYTHING);
897 this.mockGlobals.stubs().setShouldPollOptInStatus(ANYTHING);
899 this.mockGlobals.expects(once()).recordEvent(
900 GoogleNowEvent.STOPPED);
901 this.mockGlobals.expects(once()).recordEvent(
902 GoogleNowEvent.SIGNED_OUT);
903 this.mockGlobals.expects(never()).recordEvent(
904 GoogleNowEvent.NOTIFICATION_DISABLED);
905 this.mockGlobals.expects(never()).recordEvent(
906 GoogleNowEvent.GOOGLE_NOW_DISABLED);
907 updateRunningState(signedIn, true, notificationEnabled, googleNowEnabled);
910 TEST_F(TEST_NAME, 'NoCardsNotificationsDisabled', function() {
912 var notificationEnabled = false;
913 var googleNowEnabled = false;
914 this.makeAndRegisterMockGlobals([
917 'setBackgroundEnable',
918 'setShouldPollCards',
919 'setShouldPollOptInStatus']);
921 this.mockGlobals.stubs().removeAllCards();
922 this.mockGlobals.stubs().setBackgroundEnable(ANYTHING);
923 this.mockGlobals.stubs().setShouldPollCards(ANYTHING);
924 this.mockGlobals.stubs().setShouldPollOptInStatus(ANYTHING);
926 this.mockGlobals.expects(once()).recordEvent(
927 GoogleNowEvent.STOPPED);
928 this.mockGlobals.expects(never()).recordEvent(
929 GoogleNowEvent.SIGNED_OUT);
930 this.mockGlobals.expects(once()).recordEvent(
931 GoogleNowEvent.NOTIFICATION_DISABLED);
932 this.mockGlobals.expects(never()).recordEvent(
933 GoogleNowEvent.GOOGLE_NOW_DISABLED);
934 updateRunningState(signedIn, true, notificationEnabled, googleNowEnabled);
937 TEST_F(TEST_NAME, 'NoCardsGoogleNowDisabled', function() {
939 var notificationEnabled = true;
940 var googleNowEnabled = false;
941 this.makeAndRegisterMockGlobals([
944 'setBackgroundEnable',
945 'setShouldPollCards',
946 'setShouldPollOptInStatus']);
948 this.mockGlobals.stubs().removeAllCards();
949 this.mockGlobals.stubs().setBackgroundEnable(ANYTHING);
950 this.mockGlobals.stubs().setShouldPollCards(ANYTHING);
951 this.mockGlobals.stubs().setShouldPollOptInStatus(ANYTHING);
953 this.mockGlobals.expects(never()).recordEvent(
954 GoogleNowEvent.STOPPED);
955 this.mockGlobals.expects(never()).recordEvent(
956 GoogleNowEvent.SIGNED_OUT);
957 this.mockGlobals.expects(never()).recordEvent(
958 GoogleNowEvent.NOTIFICATION_DISABLED);
959 this.mockGlobals.expects(once()).recordEvent(
960 GoogleNowEvent.GOOGLE_NOW_DISABLED);
961 updateRunningState(signedIn, true, notificationEnabled, googleNowEnabled);
964 TEST_F(TEST_NAME, 'NoCardsEverythingEnabled', function() {
966 var notificationEnabled = true;
967 var googleNowEnabled = true;
968 this.makeAndRegisterMockGlobals([
971 'setBackgroundEnable',
972 'setShouldPollCards',
973 'setShouldPollOptInStatus']);
975 this.mockGlobals.stubs().removeAllCards();
976 this.mockGlobals.stubs().setBackgroundEnable(ANYTHING);
977 this.mockGlobals.stubs().setShouldPollCards(ANYTHING);
978 this.mockGlobals.stubs().setShouldPollOptInStatus(ANYTHING);
980 this.mockGlobals.expects(never()).recordEvent(
981 GoogleNowEvent.STOPPED);
982 this.mockGlobals.expects(never()).recordEvent(
983 GoogleNowEvent.SIGNED_OUT);
984 this.mockGlobals.expects(never()).recordEvent(
985 GoogleNowEvent.NOTIFICATION_DISABLED);
986 this.mockGlobals.expects(never()).recordEvent(
987 GoogleNowEvent.GOOGLE_NOW_DISABLED);
988 updateRunningState(signedIn, true, notificationEnabled, googleNowEnabled);
992 * Mocks global functions and APIs that onNotificationClicked() depends upon.
993 * @param {Test} fixture Test fixture.
995 function mockOnNotificationClickedDependencies(fixture) {
996 fixture.makeAndRegisterMockApis([
997 'chrome.windows.create',
998 'chrome.windows.update',
999 'fillFromChromeLocalStorage',
1000 'instrumented.tabs.create']);
1003 TEST_F(TEST_NAME, 'OnNotificationClicked_NoData', function() {
1004 // Tests the case when there is no data associated with notification id.
1005 // In this case, the function should do nothing.
1007 // Setup and expectations.
1008 var testNotificationId = 'TEST_ID';
1009 var testNotificationDataRequest = {notificationsData: {}};
1010 var testNotificationData = {notificationsData: {}};
1012 mockOnNotificationClickedDependencies(this);
1013 this.makeMockLocalFunctions(['selector']);
1015 expectChromeLocalStorageGet(
1016 this, testNotificationDataRequest, testNotificationData);
1018 // Invoking the tested function.
1019 onNotificationClicked(
1020 testNotificationId, this.mockLocalFunctions.functions().selector);
1023 TEST_F(TEST_NAME, 'OnNotificationClicked_ActionUrlsUndefined', function() {
1024 // Tests the case when the data associated with notification id is
1026 // In this case, the function should do nothing.
1028 // Setup and expectations.
1029 var testActionUrls = undefined;
1030 var testNotificationId = 'TEST_ID';
1031 var testNotificationDataRequest = {notificationsData: {}};
1032 var testNotificationData = {
1033 notificationsData: {'TEST_ID': {actionUrls: testActionUrls}}
1036 mockOnNotificationClickedDependencies(this);
1037 this.makeMockLocalFunctions(['selector']);
1039 expectChromeLocalStorageGet(
1040 this, testNotificationDataRequest, testNotificationData);
1042 this.mockLocalFunctions.expects(once())
1044 testNotificationData.notificationsData[testNotificationId]))
1045 .will(returnValue(undefined));
1047 // Invoking the tested function.
1048 onNotificationClicked(
1049 testNotificationId, this.mockLocalFunctions.functions().selector);
1052 TEST_F(TEST_NAME, 'OnNotificationClicked_TabCreateSuccess', function() {
1053 // Tests the selected URL is OK and crome.tabs.create suceeds.
1055 // Setup and expectations.
1056 var testActionUrls = {testField: 'TEST VALUE'};
1057 var testNotificationId = 'TEST_ID';
1058 var testNotificationDataRequest = {notificationsData: {}};
1059 var testNotificationData = {
1060 notificationsData: {'TEST_ID': {actionUrls: testActionUrls}}
1062 var testActionUrl = 'http://testurl.com';
1063 var testCreatedTab = {windowId: 239};
1065 mockOnNotificationClickedDependencies(this);
1066 this.makeMockLocalFunctions(['selector']);
1068 expectChromeLocalStorageGet(
1069 this, testNotificationDataRequest, testNotificationData);
1070 this.mockLocalFunctions.expects(once())
1072 testNotificationData.notificationsData[testNotificationId]))
1073 .will(returnValue(testActionUrl));
1074 var chromeTabsCreateSavedArgs = new SaveMockArguments();
1075 this.mockApis.expects(once()).
1076 instrumented_tabs_create(
1077 chromeTabsCreateSavedArgs.match(eqJSON({url: testActionUrl})),
1078 chromeTabsCreateSavedArgs.match(ANYTHING)).
1079 will(invokeCallback(chromeTabsCreateSavedArgs, 1, testCreatedTab));
1080 this.mockApis.expects(once()).chrome_windows_update(
1081 testCreatedTab.windowId,
1082 eqJSON({focused: true}));
1084 // Invoking the tested function.
1085 onNotificationClicked(
1086 testNotificationId, this.mockLocalFunctions.functions().selector);
1089 TEST_F(TEST_NAME, 'OnNotificationClicked_TabCreateFail', function() {
1090 // Tests the selected URL is OK and crome.tabs.create fails.
1091 // In this case, the function should invoke chrome.windows.create as a
1094 // Setup and expectations.
1095 var testActionUrls = {testField: 'TEST VALUE'};
1096 var testNotificationId = 'TEST_ID';
1097 var testNotificationDataRequest = {notificationsData: {}};
1098 var testNotificationData = {
1099 notificationsData: {'TEST_ID': {actionUrls: testActionUrls}}
1101 var testActionUrl = 'http://testurl.com';
1102 var testCreatedTab = undefined; // chrome.tabs.create fails
1104 mockOnNotificationClickedDependencies(this);
1105 this.makeMockLocalFunctions(['selector']);
1107 expectChromeLocalStorageGet(
1108 this, testNotificationDataRequest, testNotificationData);
1109 this.mockLocalFunctions.expects(once())
1111 testNotificationData.notificationsData[testNotificationId]))
1112 .will(returnValue(testActionUrl));
1113 var chromeTabsCreateSavedArgs = new SaveMockArguments();
1114 this.mockApis.expects(once()).
1115 instrumented_tabs_create(
1116 chromeTabsCreateSavedArgs.match(eqJSON({url: testActionUrl})),
1117 chromeTabsCreateSavedArgs.match(ANYTHING)).
1118 will(invokeCallback(chromeTabsCreateSavedArgs, 1, testCreatedTab));
1119 this.mockApis.expects(once()).chrome_windows_create(
1120 eqJSON({url: testActionUrl, focused: true}));
1122 // Invoking the tested function.
1123 onNotificationClicked(
1124 testNotificationId, this.mockLocalFunctions.functions().selector);
1127 TEST_F(TEST_NAME, 'ShowNotificationGroups', function() {
1128 // Tests showNotificationGroups function. Checks that the function properly
1129 // deletes the card that didn't get an update, updates existing card and
1130 // creates a new card that previously didn't exist.
1132 // Setup and expectations.
1133 var existingNotifications = {
1134 'SHOULD BE DELETED': 'SOMETHING',
1135 'SHOULD BE KEPT': 'SOMETHING'
1139 chromeNotificationId: 'SHOULD BE KEPT',
1140 trigger: {showTimeSec: 0, hideTimeSec: 0}
1143 var keptNotification = {
1144 receivedNotification: keptCard,
1150 chromeNotificationId: 'NEW CARD',
1151 trigger: {showTimeSec: 0, hideTimeSec: 0}
1154 var newNotification = {
1155 receivedNotification: newCard,
1160 var notificationGroups = {
1161 'TEST GROUP 1': {cards: [keptCard], cardsTimestamp: 0},
1162 'TEST GROUP 2': {cards: [newCard], cardsTimestamp: 0}
1165 var fakeOnCardShownFunction = 'FAKE ON CARD SHOWN FUNCTION';
1167 var expectedUpdatedNotifications = {
1168 'SHOULD BE KEPT': 'KEPT CARD NOTIFICATION DATA',
1169 'NEW CARD': 'NEW CARD NOTIFICATION DATA'
1172 this.makeAndRegisterMockApis([
1174 'chrome.storage.local.set',
1175 'instrumented.notifications.getAll'
1177 this.makeMockLocalFunctions([
1181 var notificationsGetAllSavedArgs = new SaveMockArguments();
1182 this.mockApis.expects(once()).
1183 instrumented_notifications_getAll(
1184 notificationsGetAllSavedArgs.match(ANYTHING)).
1185 will(invokeCallback(
1186 notificationsGetAllSavedArgs, 0, existingNotifications));
1188 this.mockApis.expects(once()).
1191 eqJSON([keptNotification]),
1192 eqJSON(notificationGroups),
1193 fakeOnCardShownFunction).
1194 will(returnValue('KEPT CARD NOTIFICATION DATA'));
1195 this.mockApis.expects(once()).
1198 eqJSON([newNotification]),
1199 eqJSON(notificationGroups),
1200 fakeOnCardShownFunction).
1201 will(returnValue('NEW CARD NOTIFICATION DATA'));
1202 this.mockApis.expects(once()).
1204 'SHOULD BE DELETED',
1206 eqJSON(notificationGroups),
1207 fakeOnCardShownFunction).
1208 will(returnValue(undefined));
1210 this.mockApis.expects(once()).
1211 chrome_storage_local_set(
1212 eqJSON({notificationsData: expectedUpdatedNotifications}));
1214 this.mockLocalFunctions.expects(once()).
1215 onSuccess(undefined);
1217 // Invoking the tested function.
1218 showNotificationGroups(notificationGroups, fakeOnCardShownFunction)
1219 .then(this.mockLocalFunctions.functions().onSuccess);
1222 TEST_F(TEST_NAME, 'ProcessServerResponse', function() {
1223 // Tests processServerResponse function.
1225 // Setup and expectations.
1226 Date.now = function() { return 3000000; };
1228 // GROUP1 was requested and contains cards c4 and c5. For c5, there is a
1229 // non-expired dismissal, so it will be ignored.
1230 // GROUP2 was not requested, but is contained in server response to
1231 // indicate that the group still exists. Stored group GROUP2 won't change.
1232 // GROUP3 is stored, but is not present in server's response, which means
1233 // it doesn't exist anymore. This group will be deleted.
1234 // GROUP4 doesn't contain cards, but it was requested. This is treated as
1235 // if it had an empty array of cards. Cards in the stored group will be
1236 // replaced with an empty array.
1237 // GROUP5 doesn't have next poll time, and it will be stored without next
1239 var serverResponse = {
1241 GROUP1: {requested: true, nextPollSeconds: 46},
1242 GROUP2: {requested: false},
1243 GROUP4: {requested: true, nextPollSeconds: 45},
1244 GROUP5: {requested: true}
1247 {notificationId: 'c4', groupName: 'GROUP1'},
1248 {notificationId: 'c5', groupName: 'GROUP1'}
1252 var recentDismissals = {
1253 c4: 1800000, // expired dismissal
1254 c5: 1800001 // non-expired dismissal
1257 var storedGroups = {
1259 cards: [{notificationId: 'c2'}],
1260 cardsTimestamp: 239,
1264 cards: [{notificationId: 'c3'}],
1265 cardsTimestamp: 240,
1269 cards: [{notificationId: 'c6'}],
1270 cardsTimestamp: 241,
1275 var expectedUpdatedGroups = {
1277 cards: [{notificationId: 'c4', groupName: 'GROUP1'}],
1278 cardsTimestamp: 3000000,
1279 nextPollTime: 3046000
1282 cards: [{notificationId: 'c2'}],
1283 cardsTimestamp: 239,
1288 cardsTimestamp: 3000000,
1289 nextPollTime: 3045000
1293 cardsTimestamp: 3000000
1297 var expectedUpdatedRecentDismissals = {
1301 this.makeAndRegisterMockGlobals([
1302 'scheduleNextCardsPoll'
1305 this.makeAndRegisterMockApis([
1306 'fillFromChromeLocalStorage',
1309 expectChromeLocalStorageGet(
1312 notificationGroups: {},
1313 recentDismissals: {}
1316 notificationGroups: storedGroups,
1317 recentDismissals: recentDismissals
1320 this.mockGlobals.expects(once())
1321 .scheduleNextCardsPoll(eqJSON(expectedUpdatedGroups));
1323 // Invoking the tested function.
1324 processServerResponse(serverResponse);
1327 TEST_F(TEST_NAME, 'ProcessServerResponseGoogleNowDisabled', function() {
1328 // Tests processServerResponse function for the case when the response
1329 // indicates that Google Now is disabled.
1331 // Setup and expectations.
1332 var serverResponse = {
1333 googleNowDisabled: true,
1337 this.makeAndRegisterMockGlobals([
1338 'scheduleNextCardsPoll'
1341 this.makeAndRegisterMockApis([
1342 'chrome.storage.local.set',
1343 'fillFromChromeLocalStorage'
1346 this.mockApis.expects(once()).
1347 chrome_storage_local_set(eqJSON({googleNowEnabled: false}));
1349 this.mockGlobals.expects(never()).scheduleNextCardsPoll();
1351 // Invoking the tested function.
1352 processServerResponse(serverResponse);