| OLD | NEW | 
|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 // TODO(robliao,vadimt): Determine the granularity of testing to perform. | 5 // TODO(robliao,vadimt): Determine the granularity of testing to perform. | 
| 6 | 6 | 
| 7 /** | 7 /** | 
| 8  * Test fixture for background.js. | 8  * Test fixture for background.js. | 
| 9  * @constructor | 9  * @constructor | 
| 10  * @extends {testing.Test} | 10  * @extends {testing.Test} | 
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 44   testTaskPair(RETRY_DISMISS_TASK_NAME, DISMISS_CARD_TASK_NAME, true); | 44   testTaskPair(RETRY_DISMISS_TASK_NAME, DISMISS_CARD_TASK_NAME, true); | 
| 45   testTaskPair(RETRY_DISMISS_TASK_NAME, RETRY_DISMISS_TASK_NAME, true); | 45   testTaskPair(RETRY_DISMISS_TASK_NAME, RETRY_DISMISS_TASK_NAME, true); | 
| 46   testTaskPair(RETRY_DISMISS_TASK_NAME, STATE_CHANGED_TASK_NAME, false); | 46   testTaskPair(RETRY_DISMISS_TASK_NAME, STATE_CHANGED_TASK_NAME, false); | 
| 47 | 47 | 
| 48   testTaskPair(STATE_CHANGED_TASK_NAME, UPDATE_CARDS_TASK_NAME, false); | 48   testTaskPair(STATE_CHANGED_TASK_NAME, UPDATE_CARDS_TASK_NAME, false); | 
| 49   testTaskPair(STATE_CHANGED_TASK_NAME, DISMISS_CARD_TASK_NAME, false); | 49   testTaskPair(STATE_CHANGED_TASK_NAME, DISMISS_CARD_TASK_NAME, false); | 
| 50   testTaskPair(STATE_CHANGED_TASK_NAME, RETRY_DISMISS_TASK_NAME, false); | 50   testTaskPair(STATE_CHANGED_TASK_NAME, RETRY_DISMISS_TASK_NAME, false); | 
| 51   testTaskPair(STATE_CHANGED_TASK_NAME, STATE_CHANGED_TASK_NAME, false); | 51   testTaskPair(STATE_CHANGED_TASK_NAME, STATE_CHANGED_TASK_NAME, false); | 
| 52 }); | 52 }); | 
| 53 | 53 | 
| 54 var testNotificationId = 'TEST GROUP-SOME TEST ID'; |  | 
| 55 var testChromeNotificationId = 'TEST CARD ID'; |  | 
| 56 var testNotification1 = |  | 
| 57     {testNotificationField: 'TEST NOTIFICATION VALUE1', priority: -1}; |  | 
| 58 var testNotification2 = |  | 
| 59     {testNotificationField: 'TEST NOTIFICATION VALUE2', priority: 0}; |  | 
| 60 var testActionUrls1 = {testField: 'TEST VALUE1'}; |  | 
| 61 var testActionUrls2 = {testField: 'TEST VALUE2'}; |  | 
| 62 var testDismissal1 = {testDismissalField: 'TEST DISMISSAL VALUE 1'}; |  | 
| 63 var testDismissal2 = {testDismissalField: 'TEST DISMISSAL VALUE 2'}; |  | 
| 64 var testVersion = 7; |  | 
| 65 var testTimestamp1 = 300000; |  | 
| 66 var testTimestamp2 = 600000; |  | 
| 67 var testGroupRank1 = 19; |  | 
| 68 var testGroupRank2 = 23; |  | 
| 69 var testTriggerUnmerged = {showTimeSec: 100, hideTimeSec: 200}; |  | 
| 70 var testTriggerMerged = {showTime: 300007, hideTime: 300011}; |  | 
| 71 var testVersion1 = 29; |  | 
| 72 var testVersion2 = 31; |  | 
| 73 |  | 
| 74 TEST_F( |  | 
| 75     'GoogleNowBackgroundUnitTest', |  | 
| 76     'MergeCardsEmptyNoTrigger', |  | 
| 77     function() { |  | 
| 78       // Tests merging a card with an empty trigger into an 'undefined' merged |  | 
| 79       // card. This should start a new card. |  | 
| 80 |  | 
| 81       // Invoking the tested function. |  | 
| 82       var resultingMergedCard = mergeCards(undefined, { |  | 
| 83         notificationId: testNotificationId, |  | 
| 84         chromeNotificationId: testChromeNotificationId, |  | 
| 85         version: testVersion1, |  | 
| 86         chromeNotificationOptions: testNotification1, |  | 
| 87         actionUrls: testActionUrls1, |  | 
| 88         dismissal: testDismissal1 |  | 
| 89       }, testTimestamp1, testGroupRank1); |  | 
| 90 |  | 
| 91       // Check the return value. |  | 
| 92       assertEquals( |  | 
| 93           JSON.stringify({ |  | 
| 94             dismissals: [ |  | 
| 95               { |  | 
| 96                 notificationId: testNotificationId, |  | 
| 97                 parameters: testDismissal1 |  | 
| 98               } |  | 
| 99             ], |  | 
| 100             groupRank: testGroupRank1, |  | 
| 101             trigger: {}, |  | 
| 102             timestamp: testTimestamp1, |  | 
| 103             notification: testNotification1, |  | 
| 104             actionUrls: testActionUrls1, |  | 
| 105             version: testVersion1 |  | 
| 106           }), |  | 
| 107         JSON.stringify(resultingMergedCard)); |  | 
| 108     }); |  | 
| 109 |  | 
| 110 TEST_F( |  | 
| 111     'GoogleNowBackgroundUnitTest', |  | 
| 112     'MergeCards1', |  | 
| 113     function() { |  | 
| 114       // Tests merging a unmerged card into a merged card. |  | 
| 115       // Unmerged card priority is greater than merged card one. Unmerged card |  | 
| 116       // rank is less than merged card one, and it's older. |  | 
| 117 |  | 
| 118       // Setup. |  | 
| 119       var mergedCard = { |  | 
| 120         trigger: testTriggerMerged, |  | 
| 121         version: testVersion1, |  | 
| 122         timestamp: testTimestamp2, |  | 
| 123         notification: testNotification1, |  | 
| 124         actionUrls: testActionUrls1, |  | 
| 125         groupRank: testGroupRank2, |  | 
| 126         dismissals: |  | 
| 127             [{notificationId: testNotificationId, parameters: testDismissal1}] |  | 
| 128       }; |  | 
| 129 |  | 
| 130       var unmergedNotification = { |  | 
| 131         notificationId: testNotificationId, |  | 
| 132         chromeNotificationId: testChromeNotificationId, |  | 
| 133         version: testVersion2, |  | 
| 134         chromeNotificationOptions: testNotification2, |  | 
| 135         actionUrls: testActionUrls2, |  | 
| 136         dismissal: testDismissal2, |  | 
| 137         trigger: testTriggerUnmerged |  | 
| 138       }; |  | 
| 139 |  | 
| 140       // Invoking the tested function. |  | 
| 141       var resultingMergedCard = mergeCards( |  | 
| 142           mergedCard, unmergedNotification, testTimestamp1, testGroupRank1); |  | 
| 143 |  | 
| 144       // Check the return value. |  | 
| 145       assertEquals( |  | 
| 146           JSON.stringify({ |  | 
| 147             trigger: testTriggerMerged, |  | 
| 148             version: testVersion1, |  | 
| 149             timestamp: testTimestamp2, |  | 
| 150             notification: { |  | 
| 151                 testNotificationField: 'TEST NOTIFICATION VALUE1', |  | 
| 152                 priority: 0 |  | 
| 153              }, |  | 
| 154             actionUrls: testActionUrls1, |  | 
| 155             groupRank: testGroupRank2, |  | 
| 156             dismissals: [ |  | 
| 157               {notificationId: testNotificationId, parameters: testDismissal1}, |  | 
| 158               {notificationId: testNotificationId, parameters: testDismissal2} |  | 
| 159             ] |  | 
| 160           }), |  | 
| 161         JSON.stringify(resultingMergedCard)); |  | 
| 162     }); |  | 
| 163 |  | 
| 164 TEST_F( |  | 
| 165     'GoogleNowBackgroundUnitTest', |  | 
| 166     'MergeCards2', |  | 
| 167     function() { |  | 
| 168       // Tests merging a unmerged card into a merged card. |  | 
| 169       // Unmerged card priority is less than merged card one. Unmerged card rank |  | 
| 170       // is greater than merged card one, and it's older. |  | 
| 171 |  | 
| 172       // Setup. |  | 
| 173       var mergedCard = { |  | 
| 174         trigger: testTriggerMerged, |  | 
| 175         version: testVersion1, |  | 
| 176         timestamp: testTimestamp2, |  | 
| 177         notification: testNotification2, |  | 
| 178         actionUrls: testActionUrls1, |  | 
| 179         groupRank: testGroupRank1, |  | 
| 180         dismissals: |  | 
| 181             [{notificationId: testNotificationId, parameters: testDismissal1}] |  | 
| 182       }; |  | 
| 183 |  | 
| 184       var unmergedNotification = { |  | 
| 185         notificationId: testNotificationId, |  | 
| 186         chromeNotificationId: testChromeNotificationId, |  | 
| 187         version: testVersion2, |  | 
| 188         chromeNotificationOptions: testNotification1, |  | 
| 189         actionUrls: testActionUrls2, |  | 
| 190         dismissal: testDismissal2, |  | 
| 191         trigger: testTriggerUnmerged |  | 
| 192       }; |  | 
| 193 |  | 
| 194       // Invoking the tested function. |  | 
| 195       var resultingMergedCard = mergeCards( |  | 
| 196           mergedCard, unmergedNotification, testTimestamp1, testGroupRank2); |  | 
| 197 |  | 
| 198       // Check the return value. |  | 
| 199       assertEquals( |  | 
| 200           JSON.stringify({ |  | 
| 201             trigger: {showTime: 400000, hideTime: 500000}, |  | 
| 202             version: testVersion1, |  | 
| 203             timestamp: testTimestamp2, |  | 
| 204             notification: { |  | 
| 205                 testNotificationField: 'TEST NOTIFICATION VALUE2', |  | 
| 206                 priority: 0 |  | 
| 207              }, |  | 
| 208             actionUrls: testActionUrls1, |  | 
| 209             groupRank: testGroupRank2, |  | 
| 210             dismissals: [ |  | 
| 211               {notificationId: testNotificationId, parameters: testDismissal1}, |  | 
| 212               {notificationId: testNotificationId, parameters: testDismissal2} |  | 
| 213             ] |  | 
| 214           }), |  | 
| 215         JSON.stringify(resultingMergedCard)); |  | 
| 216     }); |  | 
| 217 |  | 
| 218 TEST_F( |  | 
| 219     'GoogleNowBackgroundUnitTest', |  | 
| 220     'MergeCards3', |  | 
| 221     function() { |  | 
| 222       // Tests merging a unmerged card into a merged card. |  | 
| 223       // Unmerged card priority is less than merged card one. Unmerged card rank |  | 
| 224       // is less than merged card one, and it's newer. |  | 
| 225 |  | 
| 226       // Setup. |  | 
| 227       var mergedCard = { |  | 
| 228         trigger: testTriggerMerged, |  | 
| 229         version: testVersion1, |  | 
| 230         timestamp: testTimestamp1, |  | 
| 231         notification: testNotification2, |  | 
| 232         actionUrls: testActionUrls1, |  | 
| 233         groupRank: testGroupRank2, |  | 
| 234         dismissals: |  | 
| 235             [{notificationId: testNotificationId, parameters: testDismissal1}] |  | 
| 236       }; |  | 
| 237 |  | 
| 238       var unmergedNotification = { |  | 
| 239         notificationId: testNotificationId, |  | 
| 240         chromeNotificationId: testChromeNotificationId, |  | 
| 241         version: testVersion2, |  | 
| 242         chromeNotificationOptions: testNotification1, |  | 
| 243         actionUrls: testActionUrls2, |  | 
| 244         dismissal: testDismissal2, |  | 
| 245         trigger: testTriggerUnmerged |  | 
| 246       }; |  | 
| 247 |  | 
| 248       // Invoking the tested function. |  | 
| 249       var resultingMergedCard = mergeCards( |  | 
| 250           mergedCard, unmergedNotification, testTimestamp2, testGroupRank1); |  | 
| 251 |  | 
| 252       // Check the return value. |  | 
| 253       assertEquals( |  | 
| 254           JSON.stringify({ |  | 
| 255             trigger: testTriggerMerged, |  | 
| 256             version: testVersion2, |  | 
| 257             timestamp: testTimestamp2, |  | 
| 258             notification: { |  | 
| 259                 testNotificationField: 'TEST NOTIFICATION VALUE1', |  | 
| 260                 priority: 0 |  | 
| 261              }, |  | 
| 262             actionUrls: testActionUrls2, |  | 
| 263             groupRank: testGroupRank2, |  | 
| 264             dismissals: [ |  | 
| 265               {notificationId: testNotificationId, parameters: testDismissal1}, |  | 
| 266               {notificationId: testNotificationId, parameters: testDismissal2} |  | 
| 267             ] |  | 
| 268           }), |  | 
| 269         JSON.stringify(resultingMergedCard)); |  | 
| 270     }); |  | 
| 271 |  | 
| 272 TEST_F( |  | 
| 273     'GoogleNowBackgroundUnitTest', |  | 
| 274     'MergeGroup', |  | 
| 275     function() { |  | 
| 276       // Tests mergeGroup method. |  | 
| 277 |  | 
| 278       // Setup. |  | 
| 279       this.makeAndRegisterMockGlobals(['mergeCards']); |  | 
| 280 |  | 
| 281       this.mockGlobals.expects(once()). |  | 
| 282           mergeCards( |  | 
| 283               undefined, |  | 
| 284               eqJSON({chromeNotificationId: 'ID 1', testField: 'TEST_FIELD1'}), |  | 
| 285               300000, |  | 
| 286               17). |  | 
| 287           will(returnValue({testField: 'RESULT 1'})); |  | 
| 288       this.mockGlobals.expects(once()). |  | 
| 289           mergeCards( |  | 
| 290               eqJSON({testField: 'TEST_FIELD22'}), |  | 
| 291               eqJSON({chromeNotificationId: 'ID 2', testField: 'TEST_FIELD2'}), |  | 
| 292               300000, |  | 
| 293               17). |  | 
| 294           will(returnValue({testField: 'RESULT 2'})); |  | 
| 295 |  | 
| 296       var group = { |  | 
| 297         cards: [ |  | 
| 298           {chromeNotificationId: 'ID 1', testField: 'TEST_FIELD1'}, |  | 
| 299           {chromeNotificationId: 'ID 2', testField: 'TEST_FIELD2'} |  | 
| 300         ], |  | 
| 301         cardsTimestamp: 300000, |  | 
| 302         nextPollTime: 600000, |  | 
| 303         rank: 17 |  | 
| 304       }; |  | 
| 305 |  | 
| 306       var mergedCards = { |  | 
| 307         'ID 2': { testField: 'TEST_FIELD22' }, |  | 
| 308         'ID 3': { testField: 'TEST_FIELD3' } |  | 
| 309       }; |  | 
| 310 |  | 
| 311       // Invoking the tested function. |  | 
| 312       mergeGroup(mergedCards, group); |  | 
| 313 |  | 
| 314       // Check the output parameter. |  | 
| 315       assertEquals( |  | 
| 316           JSON.stringify({ |  | 
| 317             'ID 2': { testField: 'RESULT 2' }, |  | 
| 318             'ID 3': { testField: 'TEST_FIELD3'}, |  | 
| 319             'ID 1': { testField: 'RESULT 1' }}), |  | 
| 320           JSON.stringify(mergedCards)); |  | 
| 321     }); |  | 
| 322 |  | 
| 323 TEST_F( |  | 
| 324     'GoogleNowBackgroundUnitTest', |  | 
| 325     'MergeAndShowNotificationCards', |  | 
| 326     function() { |  | 
| 327       // Tests mergeAndShowNotificationCards function. |  | 
| 328       // The test passes 2 groups to mergeAndShowNotificationCards, checks that |  | 
| 329       // it calls mergeGroup() for each of these groups and calls |  | 
| 330       // showNotificationCards() with the results of these mergeGroup() calls. |  | 
| 331 |  | 
| 332       // Setup and expectations. |  | 
| 333       var testGroups = { |  | 
| 334         'TEST GROUP 1': {testField: 'TEST VALUE 1'}, |  | 
| 335         'TEST GROUP 2': {testField: 'TEST VALUE 2'} |  | 
| 336       }; |  | 
| 337 |  | 
| 338       this.makeAndRegisterMockGlobals(['mergeGroup', 'showNotificationCards']); |  | 
| 339 |  | 
| 340       var mergeGroupSavedArgs = new SaveMockArguments(); |  | 
| 341       this.mockGlobals.expects(once()). |  | 
| 342           mergeGroup( |  | 
| 343               mergeGroupSavedArgs.match(eqJSON({})), |  | 
| 344               mergeGroupSavedArgs.match(eqJSON({testField: 'TEST VALUE 1'}))). |  | 
| 345           will(callFunction(function() { |  | 
| 346             mergeGroupSavedArgs.arguments[0].card1 = { |  | 
| 347               testValue: 'TEST CARD VALUE 1' |  | 
| 348             }; |  | 
| 349           })); |  | 
| 350       this.mockGlobals.expects(once()). |  | 
| 351           mergeGroup( |  | 
| 352               mergeGroupSavedArgs.match( |  | 
| 353                   eqJSON({card1: {testValue: 'TEST CARD VALUE 1'}})), |  | 
| 354               mergeGroupSavedArgs.match( |  | 
| 355                   eqJSON({testField: 'TEST VALUE 2'}))). |  | 
| 356           will(callFunction(function() { |  | 
| 357               mergeGroupSavedArgs.arguments[0].card2 = { |  | 
| 358                 testValue: 'TEST CARD VALUE 2' |  | 
| 359               }; |  | 
| 360           })); |  | 
| 361       this.mockGlobals.expects(once()). |  | 
| 362           showNotificationCards( |  | 
| 363               eqJSON({ |  | 
| 364                 card1: {testValue: 'TEST CARD VALUE 1'}, |  | 
| 365                 card2: {testValue: 'TEST CARD VALUE 2'} |  | 
| 366               }), |  | 
| 367               ANYTHING); |  | 
| 368 |  | 
| 369       // Invoking the tested function. |  | 
| 370       mergeAndShowNotificationCards(testGroups, function() {}); |  | 
| 371     }); |  | 
| 372 |  | 
| 373 // TODO(vadimt): Add more tests for parseAndShowNotificationCards(). |  | 
| 374 TEST_F( |  | 
| 375     'GoogleNowBackgroundUnitTest', |  | 
| 376     'ParseAndShowNotificationCardsAdd1Remove1', |  | 
| 377     function() { |  | 
| 378       // Tests parseAndShowNotificationCards function for the case when the |  | 
| 379       // extension has 2 groups, and the server sends update with 2 groups, one |  | 
| 380       // of which is new, and another one matches a stored group. The client |  | 
| 381       // has to delete the group that didn't receive an update, keep the |  | 
| 382       // existing group that received an update, and add a new stored group for |  | 
| 383       // the new group from the server. |  | 
| 384 |  | 
| 385       // Setup and expectations. |  | 
| 386       var serverResponse = { |  | 
| 387         groups: { |  | 
| 388           GROUP1: {}, |  | 
| 389           GROUP2: {} |  | 
| 390         } |  | 
| 391       }; |  | 
| 392 |  | 
| 393       var storedGroups = { |  | 
| 394         GROUP2: { |  | 
| 395           cards: ['c2'], |  | 
| 396           cardsTimestamp: 239, |  | 
| 397           nextPollTime: 10000, |  | 
| 398           rank: 1 |  | 
| 399         }, |  | 
| 400         GROUP3: { |  | 
| 401           cards: ['c3'], |  | 
| 402           cardsTimestamp: 240, |  | 
| 403           nextPollTime: 10001, |  | 
| 404           rank: 2 |  | 
| 405         } |  | 
| 406       }; |  | 
| 407 |  | 
| 408       var expectedUpdatedGroups = { |  | 
| 409         GROUP1: { |  | 
| 410           cards: [] |  | 
| 411         }, |  | 
| 412         GROUP2: { |  | 
| 413           cards: ['c2'], |  | 
| 414           cardsTimestamp: 239, |  | 
| 415           nextPollTime: 10000, |  | 
| 416           rank: 1 |  | 
| 417         } |  | 
| 418       }; |  | 
| 419 |  | 
| 420       this.makeAndRegisterMockGlobals( |  | 
| 421           ['scheduleNextPoll', 'mergeAndShowNotificationCards', 'recordEvent']); |  | 
| 422 |  | 
| 423       this.makeAndRegisterMockApis([ |  | 
| 424         'chrome.storage.local.set', |  | 
| 425         'instrumented.storage.local.get' |  | 
| 426       ]); |  | 
| 427 |  | 
| 428       var storageGetSavedArgs = new SaveMockArguments(); |  | 
| 429       this.mockApis.expects(once()). |  | 
| 430           instrumented_storage_local_get( |  | 
| 431               storageGetSavedArgs.match(eq('notificationGroups')), |  | 
| 432               storageGetSavedArgs.match(ANYTHING)). |  | 
| 433           will(invokeCallback( |  | 
| 434               storageGetSavedArgs, 1, {notificationGroups: storedGroups})); |  | 
| 435 |  | 
| 436       this.mockGlobals.expects(once()). |  | 
| 437           scheduleNextPoll(eqJSON(expectedUpdatedGroups), true); |  | 
| 438 |  | 
| 439       this.mockApis.expects(once()). |  | 
| 440           chrome_storage_local_set( |  | 
| 441               eqJSON({notificationGroups: expectedUpdatedGroups})); |  | 
| 442 |  | 
| 443       this.mockGlobals.expects(once()). |  | 
| 444           mergeAndShowNotificationCards( |  | 
| 445               eqJSON(expectedUpdatedGroups), ANYTHING); |  | 
| 446 |  | 
| 447       this.mockGlobals.expects(once()). |  | 
| 448           recordEvent(GoogleNowEvent.CARDS_PARSE_SUCCESS); |  | 
| 449 |  | 
| 450       // Invoking the tested function. |  | 
| 451       parseAndShowNotificationCards(JSON.stringify(serverResponse)); |  | 
| 452     }); |  | 
| 453 |  | 
| 454 /** | 54 /** | 
| 455  * Mocks global functions and APIs that initialize() depends upon. | 55  * Mocks global functions and APIs that initialize() depends upon. | 
| 456  * @param {Test} fixture Test fixture. | 56  * @param {Test} fixture Test fixture. | 
| 457  */ | 57  */ | 
| 458 function mockInitializeDependencies(fixture) { | 58 function mockInitializeDependencies(fixture) { | 
| 459   fixture.makeAndRegisterMockGlobals([ | 59   fixture.makeAndRegisterMockGlobals([ | 
| 460     'recordEvent', | 60     'recordEvent', | 
| 461     'setBackgroundEnable', | 61     'setBackgroundEnable', | 
| 462     'startPollingCards' | 62     'startPollingCards' | 
| 463   ]); | 63   ]); | 
| (...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 870               chromeTabsCreateSavedArgs.match(eqJSON({url: testActionUrl})), | 470               chromeTabsCreateSavedArgs.match(eqJSON({url: testActionUrl})), | 
| 871               chromeTabsCreateSavedArgs.match(ANYTHING)). | 471               chromeTabsCreateSavedArgs.match(ANYTHING)). | 
| 872           will(invokeCallback(chromeTabsCreateSavedArgs, 1, testCreatedTab)); | 472           will(invokeCallback(chromeTabsCreateSavedArgs, 1, testCreatedTab)); | 
| 873       this.mockApis.expects(once()).chrome_windows_create( | 473       this.mockApis.expects(once()).chrome_windows_create( | 
| 874           eqJSON({url: testActionUrl, focused: true})); | 474           eqJSON({url: testActionUrl, focused: true})); | 
| 875 | 475 | 
| 876       // Invoking the tested function. | 476       // Invoking the tested function. | 
| 877       onNotificationClicked( | 477       onNotificationClicked( | 
| 878           testNotificationId, this.mockLocalFunctions.functions().selector); | 478           testNotificationId, this.mockLocalFunctions.functions().selector); | 
| 879     }); | 479     }); | 
| OLD | NEW | 
|---|