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 cards.js. 7 * @constructor 8 * @extends {testing.Test} 9 */ 10 function GoogleNowCardsUnitTest () { 11 testing.Test.call(this); 12 } 13 14 GoogleNowCardsUnitTest.prototype = { 15 __proto__: testing.Test.prototype, 16 17 /** @override */ 18 extraLibraries: [ 19 'common_test_util.js', 20 'cards.js' 21 ] 22 }; 23 24 // Test implementation of a function provided by utility.js. 25 function verify(condition, message) { 26 assertTrue(condition, message); 27 } 28 29 var testChromeNotificationId = 'TEST CHROME NOTIFICATION ID'; 30 var testServerNotificationIdA = 'TEST SERVER NOTIFICATION ID-A'; 31 var testServerNotificationIdB = 'TEST SERVER NOTIFICATION ID-B'; 32 var testNotificationA = { 33 testNotificationField: 'TEST NOTIFICATION VALUE A', 34 priority: 1 35 }; 36 var testNotificationB = { 37 testNotificationField: 'TEST NOTIFICATION VALUE B', 38 priority: 2 39 }; 40 var groupNameA = 'A'; 41 var groupNameB = 'B'; 42 var expectedAlarmId = 'card-TEST CHROME NOTIFICATION ID'; 43 var testActionUrlsA = {testField: 'TEST VALUE A'}; 44 var testActionUrlsB = {testField: 'TEST VALUE B'}; 45 var testDismissalA = {testDismissalField: 'TEST DISMISSAL VALUE A'}; 46 var testDismissalB = {testDismissalField: 'TEST DISMISSAL VALUE B'}; 47 var EXPLANATORY_CARDS_LINK_THRESHOLD = 4; 48 var localStorage = {explanatoryCardsShown: 0}; 49 var notificationUpdateSuccessful = true; 50 var notificationUpdateFailed = false; 51 52 function setUpCardManagerTest(fixture) { 53 fixture.makeAndRegisterMockApis([ 54 'chrome.alarms.clear', 55 'chrome.alarms.create', 56 'chrome.storage.local.set', 57 'countExplanatoryCard', 58 'fillFromChromeLocalStorage', 59 'instrumented.alarms.onAlarm.addListener', 60 'instrumented.notifications.clear', 61 'instrumented.notifications.create', 62 'instrumented.notifications.update', 63 'tasks.add' 64 ]); 65 66 chrome.runtime = {}; // No error. 67 68 var onAlarmSavedArgs = new SaveMockArguments(); 69 fixture.mockApis.expects(once()). 70 instrumented_alarms_onAlarm_addListener( 71 onAlarmSavedArgs.match(ANYTHING)); 72 73 var cardSet = buildCardSet(); 74 75 Mock4JS.verifyAllMocks(); 76 77 Date.now = function() { return 300000; }; 78 79 var test = { 80 cardSet: cardSet, 81 alarmCallback: onAlarmSavedArgs.arguments [0] 82 }; 83 84 return test; 85 } 86 87 TEST_F('GoogleNowCardsUnitTest', 'BuildCardManager', function() { 88 // Tests that buildCardSet() call completes with no problems. 89 var test = setUpCardManagerTest(this); 90 91 assertEquals('object', typeof test.cardSet); 92 assertEquals('function', typeof test.alarmCallback); 93 }); 94 95 TEST_F('GoogleNowCardsUnitTest', 'UpdateSimpleHideFuture', function() { 96 // Update a simple card with the hide event in future. 97 98 var testUncombinedNotification = { 99 receivedNotification: { 100 notificationId: testServerNotificationIdA, 101 chromeNotificationId: testChromeNotificationId, 102 chromeNotificationOptions: testNotificationA, 103 actionUrls: testActionUrlsA, 104 dismissal: testDismissalA, 105 groupName: groupNameA 106 }, 107 hideTime: 300001 108 }; 109 110 // Setup and expectations. 111 var test = setUpCardManagerTest(this); 112 this.mockApis.expects(once()). 113 chrome_alarms_clear(expectedAlarmId); 114 var chromeNotificationsUpdateSavedArgs = new SaveMockArguments(); 115 this.mockApis.expects(once()). 116 instrumented_notifications_update( 117 chromeNotificationsUpdateSavedArgs.match( 118 eq(testChromeNotificationId)), 119 chromeNotificationsUpdateSavedArgs.match(eqJSON(testNotificationA)), 120 chromeNotificationsUpdateSavedArgs.match(ANYTHING)). 121 will(invokeCallback( 122 chromeNotificationsUpdateSavedArgs, 2, notificationUpdateSuccessful)); 123 this.mockApis.expects(once()). 124 chrome_alarms_create(expectedAlarmId, eqJSON({when: 300001})); 125 126 // Call tested method. 127 var notificationData = test.cardSet.update( 128 testChromeNotificationId, [testUncombinedNotification], {}); 129 130 // Check the return value. 131 assertEquals( 132 JSON.stringify({ 133 actionUrls: testActionUrlsA, 134 timestamp: 300000, 135 combinedCard: [testUncombinedNotification] 136 }), 137 JSON.stringify(notificationData)); 138 }); 139 140 TEST_F('GoogleNowCardsUnitTest', 'CreateSimpleHideFuture', function() { 141 // Create a simple card with the hide event in future. 142 143 var testUncombinedNotification = { 144 receivedNotification: { 145 notificationId: testServerNotificationIdA, 146 chromeNotificationId: testChromeNotificationId, 147 chromeNotificationOptions: testNotificationA, 148 actionUrls: testActionUrlsA, 149 dismissal: testDismissalA, 150 groupName: groupNameA 151 }, 152 hideTime: 300001 153 }; 154 155 // Setup and expectations. 156 var test = setUpCardManagerTest(this); 157 this.makeMockLocalFunctions(['onCardShown']); 158 159 this.mockApis.expects(once()). 160 chrome_alarms_clear(expectedAlarmId); 161 162 // notifications.update will return false, which will trigger 163 // notifications.create. 164 var chromeNotificationsUpdateSavedArgs = new SaveMockArguments(); 165 this.mockApis.expects(once()). 166 instrumented_notifications_update( 167 chromeNotificationsUpdateSavedArgs.match( 168 eq(testChromeNotificationId)), 169 chromeNotificationsUpdateSavedArgs.match(eqJSON(testNotificationA)), 170 chromeNotificationsUpdateSavedArgs.match(ANYTHING)). 171 will(invokeCallback( 172 chromeNotificationsUpdateSavedArgs, 2, notificationUpdateFailed)); 173 var chromeNotificationsCreateSavedArgs = new SaveMockArguments(); 174 this.mockApis.expects(once()). 175 instrumented_notifications_create( 176 chromeNotificationsCreateSavedArgs.match( 177 eq(testChromeNotificationId)), 178 chromeNotificationsCreateSavedArgs.match(eqJSON(testNotificationA)), 179 chromeNotificationsCreateSavedArgs.match(ANYTHING)). 180 will(invokeCallback( 181 chromeNotificationsCreateSavedArgs, 2, testChromeNotificationId)); 182 183 this.mockLocalFunctions.expects(once()). 184 onCardShown(eqJSON(testUncombinedNotification.receivedNotification)); 185 186 this.mockApis.expects(once()). 187 chrome_alarms_create(expectedAlarmId, eqJSON({when: 300001})); 188 189 // Call tested method. 190 var notificationData = test.cardSet.update( 191 testChromeNotificationId, 192 [testUncombinedNotification], 193 {}, 194 this.mockLocalFunctions.functions().onCardShown); 195 196 // Check the return value. 197 assertEquals( 198 JSON.stringify({ 199 actionUrls: testActionUrlsA, 200 timestamp: 300000, 201 combinedCard: [testUncombinedNotification] 202 }), 203 JSON.stringify(notificationData)); 204 }); 205 206 TEST_F('GoogleNowCardsUnitTest', 'CreateSimpleShowFuture', function() { 207 // Create a simple card with the show event in future. Should create an alarm 208 // to fire at the show time. 209 210 var testUncombinedNotification = { 211 receivedNotification: { 212 notificationId: testServerNotificationIdA, 213 chromeNotificationId: testChromeNotificationId, 214 chromeNotificationOptions: testNotificationA, 215 actionUrls: testActionUrlsA, 216 dismissal: testDismissalA, 217 groupName: groupNameA 218 }, 219 showTime: 300001, 220 hideTime: 300002 221 }; 222 223 // Setup and expectations. 224 var test = setUpCardManagerTest(this); 225 226 this.mockApis.expects(once()). 227 chrome_alarms_clear(expectedAlarmId); 228 this.mockApis.expects(once()). 229 instrumented_notifications_clear(testChromeNotificationId, ANYTHING); 230 this.mockApis.expects(once()). 231 chrome_alarms_create(expectedAlarmId, eqJSON({when: 300001})); 232 233 // Call tested method. 234 var notificationData = test.cardSet.update( 235 testChromeNotificationId, [testUncombinedNotification], {}); 236 237 // Check the return value. 238 assertEquals( 239 JSON.stringify({ 240 timestamp: 300000, 241 combinedCard: [testUncombinedNotification] 242 }), 243 JSON.stringify(notificationData)); 244 }); 245 246 TEST_F('GoogleNowCardsUnitTest', 'UpdateSimpleHidePast', function() { 247 // Update a simple card with the hide event in the past (actually, present). 248 // Should clear the notification. 249 250 var testUncombinedNotification = { 251 receivedNotification: { 252 notificationId: testServerNotificationIdA, 253 chromeNotificationId: testChromeNotificationId, 254 chromeNotificationOptions: testNotificationA, 255 actionUrls: testActionUrlsA, 256 dismissal: testDismissalA, 257 groupName: groupNameA 258 }, 259 hideTime: 300000 260 }; 261 262 // Setup and expectations. 263 var test = setUpCardManagerTest(this); 264 this.mockApis.expects(once()). 265 chrome_alarms_clear(expectedAlarmId); 266 this.mockApis.expects(once()). 267 instrumented_notifications_clear(testChromeNotificationId, ANYTHING); 268 269 var groups = { 270 A: { 271 cards: [ 272 {chromeNotificationId: 'ID1'}, 273 {chromeNotificationId: testChromeNotificationId} 274 ] 275 }, 276 B: { 277 cards: [ 278 {chromeNotificationId: testChromeNotificationId}, 279 {chromeNotificationId: 'ID2'} 280 ] 281 } 282 }; 283 284 // Call tested method. 285 var notificationData = test.cardSet.update( 286 testChromeNotificationId, [testUncombinedNotification], groups); 287 288 // Check the return value. 289 assertEquals(undefined, notificationData); 290 291 // Check that groups were cleaned up. 292 var expectedCleanedGroups = { 293 A: { 294 cards: [{chromeNotificationId: 'ID1'}] 295 }, 296 B: { 297 cards: [{chromeNotificationId: 'ID2'}] 298 } 299 }; 300 301 assertEquals(JSON.stringify(expectedCleanedGroups), JSON.stringify(groups)); 302 }); 303 304 TEST_F('GoogleNowCardsUnitTest', 'UpdateComplex', function() { 305 // Update a combined card that contains 2 uncombined cards. The card from 306 // group B has higher priority and wins. 307 308 var testUncombinedNotificationA = { 309 receivedNotification: { 310 notificationId: testServerNotificationIdA, 311 chromeNotificationId: testChromeNotificationId, 312 chromeNotificationOptions: testNotificationA, 313 actionUrls: testActionUrlsA, 314 dismissal: testDismissalA, 315 groupName: groupNameA 316 }, 317 hideTime: 300001 318 }; 319 320 var testUncombinedNotificationB = { 321 receivedNotification: { 322 notificationId: testServerNotificationIdB, 323 chromeNotificationId: testChromeNotificationId, 324 chromeNotificationOptions: testNotificationB, 325 actionUrls: testActionUrlsB, 326 dismissal: testDismissalB, 327 groupName: groupNameB 328 }, 329 hideTime: 300002 330 }; 331 332 // Setup and expectations. 333 var test = setUpCardManagerTest(this); 334 this.mockApis.expects(once()). 335 chrome_alarms_clear(expectedAlarmId); 336 var chromeNotificationsUpdateSavedArgs = new SaveMockArguments(); 337 this.mockApis.expects(once()). 338 instrumented_notifications_update( 339 chromeNotificationsUpdateSavedArgs.match( 340 eq(testChromeNotificationId)), 341 chromeNotificationsUpdateSavedArgs.match(eqJSON(testNotificationB)), 342 chromeNotificationsUpdateSavedArgs.match(ANYTHING)). 343 will(invokeCallback( 344 chromeNotificationsUpdateSavedArgs, 2, notificationUpdateSuccessful)); 345 this.mockApis.expects(once()). 346 chrome_alarms_create(expectedAlarmId, eqJSON({when: 300001})); 347 348 // Call tested method. 349 var notificationData = test.cardSet.update( 350 testChromeNotificationId, 351 [testUncombinedNotificationA, testUncombinedNotificationB], 352 {}); 353 354 // Check the return value. 355 assertEquals( 356 JSON.stringify({ 357 actionUrls: testActionUrlsB, 358 timestamp: 300000, 359 combinedCard: [testUncombinedNotificationA, testUncombinedNotificationB] 360 }), 361 JSON.stringify(notificationData)); 362 }); 363 364 TEST_F('GoogleNowCardsUnitTest', 'DismissSimple', function() { 365 // Dismiss a combined card that contains 1 uncombined currently visible card. 366 // The notification should be deleted, and the card data should be cleared. 367 368 var testUncombinedNotificationA = { 369 receivedNotification: { 370 notificationId: testServerNotificationIdA, 371 chromeNotificationId: testChromeNotificationId, 372 chromeNotificationOptions: testNotificationA, 373 actionUrls: testActionUrlsA, 374 dismissal: testDismissalA, 375 groupName: groupNameA 376 }, 377 showTime: 299995, 378 hideTime: 300005 379 }; 380 381 // Setup and expectations. 382 var test = setUpCardManagerTest(this); 383 this.mockApis.expects(once()). 384 chrome_alarms_clear(expectedAlarmId); 385 this.mockApis.expects(once()). 386 instrumented_notifications_clear(testChromeNotificationId, ANYTHING); 387 388 var groups = { 389 A: { 390 cards: [ 391 {chromeNotificationId: 'ID1'}, 392 {chromeNotificationId: testChromeNotificationId} 393 ] 394 }, 395 B: { 396 cards: [ 397 {chromeNotificationId: testChromeNotificationId}, 398 {chromeNotificationId: 'ID2'} 399 ] 400 } 401 }; 402 403 // Call tested method. 404 var dismissalResult = test.cardSet.onDismissal( 405 testChromeNotificationId, 406 { 407 actionUrls: testActionUrlsA, 408 timestamp: 299999, 409 combinedCard: [testUncombinedNotificationA] 410 }, 411 groups); 412 413 // Check the return value. 414 assertEquals( 415 JSON.stringify({ 416 dismissals: [{ 417 notificationId: testServerNotificationIdA, 418 parameters: testDismissalA 419 }], 420 notificationData: undefined 421 }), 422 JSON.stringify(dismissalResult)); 423 424 // Check that groups were cleaned up. 425 var expectedCleanedGroups = { 426 A: { 427 cards: [{chromeNotificationId: 'ID1'}] 428 }, 429 B: { 430 cards: [{chromeNotificationId: 'ID2'}] 431 } 432 }; 433 434 assertEquals(JSON.stringify(expectedCleanedGroups), JSON.stringify(groups)); 435 }); 436 437 TEST_F('GoogleNowCardsUnitTest', 'DismissComplex', function() { 438 // Dismiss a combined card that contains 2 uncombined cards. One of them (B), 439 // is currently shown, and it should be dismissed. The other one (A) has 440 // showTime in future, and it should not be dismissed. 441 442 var testUncombinedNotificationA = { 443 receivedNotification: { 444 notificationId: testServerNotificationIdA, 445 chromeNotificationId: testChromeNotificationId, 446 chromeNotificationOptions: testNotificationA, 447 actionUrls: testActionUrlsA, 448 dismissal: testDismissalA, 449 groupName: groupNameA 450 }, 451 showTime: 300010, 452 hideTime: 300011 453 }; 454 455 var testUncombinedNotificationB = { 456 receivedNotification: { 457 notificationId: testServerNotificationIdB, 458 chromeNotificationId: testChromeNotificationId, 459 chromeNotificationOptions: testNotificationB, 460 actionUrls: testActionUrlsB, 461 dismissal: testDismissalB, 462 groupName: groupNameB 463 }, 464 showTime: 299995, 465 hideTime: 300005 466 }; 467 468 // Setup and expectations. 469 var test = setUpCardManagerTest(this); 470 this.mockApis.expects(once()). 471 chrome_alarms_clear(expectedAlarmId); 472 this.mockApis.expects(once()). 473 instrumented_notifications_clear(testChromeNotificationId, ANYTHING); 474 this.mockApis.expects(once()). 475 chrome_alarms_create(expectedAlarmId, eqJSON({when: 300010})); 476 477 // Call tested method. 478 var dismissalResult = test.cardSet.onDismissal( 479 testChromeNotificationId, 480 { 481 actionUrls: testActionUrlsB, 482 timestamp: 299999, 483 combinedCard: [testUncombinedNotificationA, testUncombinedNotificationB] 484 }, 485 {}); 486 487 // Check the return value. 488 assertEquals( 489 JSON.stringify({ 490 dismissals: [{ 491 notificationId: testServerNotificationIdB, 492 parameters: testDismissalB 493 }], 494 notificationData: { 495 timestamp: 300000, 496 combinedCard: [testUncombinedNotificationA] 497 }}), 498 JSON.stringify(dismissalResult)); 499 }); 500 501 TEST_F('GoogleNowCardsUnitTest', 'onAlarmUnrecognized', function() { 502 // Tests onAlarm does nothing on an unrelated alarm. 503 var test = setUpCardManagerTest(this); 504 505 // Call tested method. 506 test.alarmCallback({name: 'unrelated'}); 507 }); 508 509 TEST_F('GoogleNowCardsUnitTest', 'onAlarmClear', function() { 510 // Tests onAlarm fired at a moment past all card's events. The card should be 511 // cleaned. 512 var testUncombinedNotification = { 513 receivedNotification: { 514 notificationId: testServerNotificationIdA, 515 chromeNotificationId: testChromeNotificationId, 516 chromeNotificationOptions: testNotificationA, 517 actionUrls: testActionUrlsA, 518 dismissal: testDismissalA, 519 groupName: groupNameA 520 }, 521 hideTime: 299999 522 }; 523 524 // Setup and expectations. 525 var test = setUpCardManagerTest(this); 526 var tasksAddSavedArgs = new SaveMockArguments(); 527 this.mockApis.expects(once()). 528 tasks_add( 529 tasksAddSavedArgs.match(eq(UPDATE_CARD_TASK_NAME)), 530 tasksAddSavedArgs.match(ANYTHING)). 531 will(invokeCallback(tasksAddSavedArgs,1)); 532 expectChromeLocalStorageGet( 533 this, 534 { 535 notificationsData: {}, 536 notificationGroups: {} 537 }, 538 { 539 notificationsData: { 540 'TEST CHROME NOTIFICATION ID': { 541 actionUrls: testActionUrlsA, 542 timestamp: 299998, 543 combinedCard: [testUncombinedNotification] 544 }, 545 'TEST CARD ID 1': {testField: 'TEST VALUE 1'} 546 }, 547 notificationGroups: { 548 A: { 549 cards: [ 550 {chromeNotificationId: 'ID1'}, 551 {chromeNotificationId: testChromeNotificationId} 552 ] 553 }, 554 B: { 555 cards: [ 556 {chromeNotificationId: testChromeNotificationId}, 557 {chromeNotificationId: 'ID2'} 558 ] 559 }}}); 560 this.mockApis.expects(once()). 561 instrumented_notifications_clear(testChromeNotificationId, ANYTHING); 562 this.mockApis.expects(once()). 563 chrome_alarms_clear(expectedAlarmId); 564 this.mockApis.expects(once()). 565 chrome_storage_local_set(eqJSON({ 566 notificationsData: { 567 'TEST CARD ID 1': {testField: 'TEST VALUE 1'} 568 }, 569 notificationGroups: { 570 A: { 571 cards: [{chromeNotificationId: 'ID1'}] 572 }, 573 B: { 574 cards: [{chromeNotificationId: 'ID2'}] 575 }}})); 576 577 // Call tested method. 578 test.alarmCallback({name: expectedAlarmId}); 579 }); 580 581 TEST_F('GoogleNowCardsUnitTest', 'onAlarmUpdate', function() { 582 // Tests onAlarm fired at a moment when there are future card's events. The 583 // card needs to be updated. 584 var testUncombinedNotification = { 585 receivedNotification: { 586 notificationId: testServerNotificationIdA, 587 chromeNotificationId: testChromeNotificationId, 588 chromeNotificationOptions: testNotificationA, 589 actionUrls: testActionUrlsA, 590 dismissal: testDismissalA, 591 groupName: groupNameA 592 }, 593 hideTime: 300001 594 }; 595 596 // Setup and expectations. 597 var test = setUpCardManagerTest(this); 598 var tasksAddSavedArgs = new SaveMockArguments(); 599 this.mockApis.expects(once()). 600 tasks_add( 601 tasksAddSavedArgs.match(eq(UPDATE_CARD_TASK_NAME)), 602 tasksAddSavedArgs.match(ANYTHING)). 603 will(invokeCallback(tasksAddSavedArgs,1)); 604 expectChromeLocalStorageGet( 605 this, 606 { 607 notificationsData: {}, 608 notificationGroups: {} 609 }, 610 { 611 notificationsData: { 612 'TEST CHROME NOTIFICATION ID': { 613 actionUrls: testActionUrlsA, 614 timestamp: 299998, 615 combinedCard: [testUncombinedNotification] 616 }}, 617 notificationGroups: {} 618 }); 619 this.mockApis.expects(once()). 620 chrome_alarms_clear(expectedAlarmId); 621 var chromeNotificationsUpdateSavedArgs = new SaveMockArguments(); 622 this.mockApis.expects(once()). 623 instrumented_notifications_update( 624 chromeNotificationsUpdateSavedArgs.match( 625 eq(testChromeNotificationId)), 626 chromeNotificationsUpdateSavedArgs.match(eqJSON(testNotificationA)), 627 chromeNotificationsUpdateSavedArgs.match(ANYTHING)). 628 will(invokeCallback( 629 chromeNotificationsUpdateSavedArgs, 2, notificationUpdateSuccessful)); 630 this.mockApis.expects(once()). 631 chrome_alarms_create(expectedAlarmId, eqJSON({when: 300001})); 632 this.mockApis.expects(once()). 633 chrome_storage_local_set(eqJSON({ 634 notificationsData: { 635 'TEST CHROME NOTIFICATION ID': { 636 actionUrls: testActionUrlsA, 637 timestamp: 300000, 638 combinedCard: [testUncombinedNotification] 639 } 640 }, 641 notificationGroups: { 642 }})); 643 644 // Call tested method. 645 test.alarmCallback({name: expectedAlarmId}); 646 }); 647