Home | History | Annotate | Download | only in webui
      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 sync internals WebUI testing.
      7  * @constructor
      8  * @extends {testing.Test}
      9  */
     10 function SyncInternalsWebUITest() {}
     11 
     12 SyncInternalsWebUITest.prototype = {
     13   __proto__: testing.Test.prototype,
     14 
     15   /**
     16    * Browse to the sync internals page.
     17    * @override
     18    */
     19   browsePreload: 'chrome://sync-internals',
     20 
     21   /**
     22    * Disable accessibility testing for this page.
     23    * @override
     24    */
     25   runAccessibilityChecks: false,
     26 
     27   /** @override */
     28   preLoad: function() {
     29     this.makeAndRegisterMockHandler([
     30         'getAllNodes',
     31     ]);
     32   },
     33 
     34   /**
     35    * Checks aboutInfo's details section for the specified field.
     36    * @param {boolean} isValid Whether the field is valid.
     37    * @param {string} key The name of the key to search for in details.
     38    * @param {string} value The expected value if |key| is found.
     39    * @return {boolean} whether the field was found in the details.
     40    * @protected
     41    */
     42   hasInDetails: function(isValid, key, value) {
     43     var details = chrome.sync.aboutInfo.details;
     44     if (!details)
     45       return false;
     46     for (var i = 0; i < details.length; ++i) {
     47       if (!details[i].data)
     48         continue;
     49       for (var j = 0; j < details[i].data.length; ++j) {
     50         var obj = details[i].data[j];
     51         if (obj.stat_name == key)
     52           return obj.is_valid == isValid && obj.stat_value == value;
     53       }
     54     }
     55     return false;
     56   }
     57 };
     58 
     59 /**
     60  * Constant hard-coded value to return from mock getAllNodes.
     61  * @const
     62  */
     63 var HARD_CODED_ALL_NODES = [{
     64   'nodes': [{
     65     'ATTACHMENT_METADATA': '',
     66     'BASE_SERVER_SPECIFICS': {},
     67     'BASE_VERSION': '1396470970810000',
     68     'CTIME': 'Wednesday, December 31, 1969 4:00:00 PM',
     69     'ID': 'sZ:ADqtAZwzF4GOIyvkI2enSI62AU5p/7MNmvuSSyf7yXJ1SkJwpp1YL' +
     70       '6bbMkF8inzqW+EO6n2aPJ/uXccW9GHxorBlnKoZAWHVzg==',
     71     'IS_DEL': false,
     72     'IS_DIR': true,
     73     'IS_UNAPPLIED_UPDATE': false,
     74     'IS_UNSYNCED': false,
     75     'LOCAL_EXTERNAL_ID': '0',
     76     'META_HANDLE': '387',
     77     'MTIME': 'Wednesday, December 31, 1969 4:00:00 PM',
     78     'NON_UNIQUE_NAME': 'Autofill',
     79     'PARENT_ID': 'r',
     80     'SERVER_CTIME': 'Wednesday, December 31, 1969 4:00:00 PM',
     81     'SERVER_IS_DEL': false,
     82     'SERVER_IS_DIR': true,
     83     'SERVER_MTIME': 'Wednesday, December 31, 1969 4:00:00 PM',
     84     'SERVER_NON_UNIQUE_NAME': 'Autofill',
     85     'SERVER_PARENT_ID': 'r',
     86     'SERVER_SPECIFICS': {
     87       'autofill': {
     88         'usage_timestamp': []
     89       }
     90     },
     91     'SERVER_UNIQUE_POSITION': 'INVALID[]',
     92     'SERVER_VERSION': '1396470970810000',
     93     'SPECIFICS': {
     94       'autofill': {
     95         'usage_timestamp': []
     96       }
     97     },
     98     'SYNCING': false,
     99     'TRANSACTION_VERSION': '1',
    100     'UNIQUE_BOOKMARK_TAG': '',
    101     'UNIQUE_CLIENT_TAG': '',
    102     'UNIQUE_POSITION': 'INVALID[]',
    103     'UNIQUE_SERVER_TAG': 'google_chrome_autofill',
    104     'isDirty': false,
    105     'serverModelType': 'Autofill'
    106   }, {
    107     'ATTACHMENT_METADATA': '',
    108     'BASE_SERVER_SPECIFICS': {},
    109     'BASE_VERSION': '1394241139528639',
    110     'CTIME': 'Friday, March 7, 2014 5:12:19 PM',
    111     'ID': 'sZ:ADqtAZwzc/ol1iaz+yNLjjWak9PBE0o/hATzpqJsyq/HX2xzV2f88' +
    112       'FaOrT7HDE4tyn7zx2LWgkAFvZfCA5mOy4p0XFgiY0L+mw==',
    113     'IS_DEL': false,
    114     'IS_DIR': false,
    115     'IS_UNAPPLIED_UPDATE': false,
    116     'IS_UNSYNCED': false,
    117     'LOCAL_EXTERNAL_ID': '0',
    118     'META_HANDLE': '2989',
    119     'MTIME': 'Friday, March 7, 2014 5:12:19 PM',
    120     'NON_UNIQUE_NAME': 'autofill_entry|Email|rlsynctet2',
    121     'PARENT_ID': 'sZ:ADqtAZwzF4GOIyvkI2enSI62AU5p/7MNmvuSSyf7yXJ1Sk' +
    122       'Jwpp1YL6bbMkF8inzqW+EO6n2aPJ/uXccW9GHxorBlnKoZAWHVzg==',
    123     'SERVER_CTIME': 'Friday, March 7, 2014 5:12:19 PM',
    124     'SERVER_IS_DEL': false,
    125     'SERVER_IS_DIR': false,
    126     'SERVER_MTIME': 'Friday, March 7, 2014 5:12:19 PM',
    127     'SERVER_NON_UNIQUE_NAME': 'autofill_entry|Email|rlsynctet2',
    128     'SERVER_PARENT_ID': 'sZ:ADqtAZwzF4GOIyvkI2enSI62AU5p/7MNmvuSSyf' +
    129       '7yXJ1SkJwpp1YL6bbMkF8inzqW+EO6n2aPJ/uXccW9GHxorBlnKoZAWHVzg==',
    130     'SERVER_SPECIFICS': {
    131       'autofill': {
    132         'name': 'Email',
    133         'usage_timestamp': ['13038713887000000', '13038713890000000'],
    134         'value': 'rlsynctet2'
    135       }
    136     },
    137     'SERVER_UNIQUE_POSITION': 'INVALID[]',
    138     'SERVER_VERSION': '1394241139528639',
    139     'SPECIFICS': {
    140       'autofill': {
    141         'name': 'Email',
    142         'usage_timestamp': ['13038713887000000', '13038713890000000'],
    143         'value': 'rlsynctet2'
    144       }
    145     },
    146     'SYNCING': false,
    147     'TRANSACTION_VERSION': '1',
    148     'UNIQUE_BOOKMARK_TAG': '',
    149     'UNIQUE_CLIENT_TAG': 'EvliorKUf1rLjT+BGkNZp586Tsk=',
    150     'UNIQUE_POSITION': 'INVALID[]',
    151     'UNIQUE_SERVER_TAG': '',
    152     'isDirty': false,
    153     'serverModelType': 'Autofill'
    154   }],
    155   'type': 'Autofill'
    156 }];
    157 
    158 /**
    159  * A value to return in mock onReceivedUpdatedAboutInfo event.
    160  * @const
    161  */
    162 HARD_CODED_ABOUT_INFO = {
    163   'actionable_error': [
    164     {
    165       'is_valid': false,
    166       'stat_name': 'Error Type',
    167       'stat_value': 'Uninitialized'
    168     },
    169     {
    170       'is_valid': false,
    171       'stat_name': 'Action',
    172       'stat_value': 'Uninitialized'
    173     },
    174     {
    175       'is_valid': false,
    176       'stat_name': 'URL',
    177       'stat_value': 'Uninitialized'
    178     },
    179     {
    180       'is_valid': false,
    181       'stat_name': 'Error Description',
    182       'stat_value': 'Uninitialized'
    183     }
    184   ],
    185   'actionable_error_detected': false,
    186   'details': [
    187     {
    188       'data': [
    189         {
    190           'is_valid': true,
    191           'stat_name': 'Summary',
    192           'stat_value': 'Sync service initialized'
    193         }
    194       ],
    195       'is_sensitive': false,
    196       'title': 'Summary'
    197     },
    198   ],
    199   'type_status': [
    200     {
    201       'name': 'Model Type',
    202       'num_entries': 'Total Entries',
    203       'num_live': 'Live Entries',
    204       'status': 'header',
    205       'value': 'Group Type'
    206     },
    207     {
    208       'name': 'Bookmarks',
    209       'num_entries': 2793,
    210       'num_live': 2793,
    211       'status': 'ok',
    212       'value': 'Active: GROUP_UI'
    213     },
    214   ],
    215   'unrecoverable_error_detected': false
    216 };
    217 
    218 NETWORK_EVENT_DETAILS_1 = {
    219   'details': 'Notified types: Bookmarks, Autofill',
    220   'proto': {},
    221   'time': 1395874542192.407,
    222   'type': 'Normal GetUpdate request',
    223 };
    224 
    225 NETWORK_EVENT_DETAILS_2 = {
    226   'details': 'Received error: SYNC_AUTH_ERROR',
    227   'proto': {},
    228   'time': 1395874542192.837,
    229   'type': 'GetUpdates Response',
    230 };
    231 
    232 TEST_F('SyncInternalsWebUITest', 'Uninitialized', function() {
    233   assertNotEquals(null, chrome.sync.aboutInfo);
    234   expectTrue(this.hasInDetails(true, 'Username', ''));
    235   expectTrue(this.hasInDetails(false, 'Summary', 'Uninitialized'));
    236 });
    237 
    238 TEST_F('SyncInternalsWebUITest', 'LoadPastedAboutInfo', function() {
    239   // Expose the text field.
    240   $('import-status').click();
    241 
    242   // Fill it with fake data.
    243   $('status-text').value = JSON.stringify(HARD_CODED_ABOUT_INFO);
    244 
    245   // Trigger the import.
    246   $('import-status').click();
    247 
    248   expectTrue(this.hasInDetails(true, 'Summary', 'Sync service initialized'));
    249 });
    250 
    251 TEST_F('SyncInternalsWebUITest', 'NetworkEventsTest', function() {
    252   networkEvent1 = new Event('onProtocolEvent');
    253   networkEvent1.details = NETWORK_EVENT_DETAILS_1;
    254   networkEvent2 = new Event('onProtocolEvent');
    255   networkEvent2.details = NETWORK_EVENT_DETAILS_2;
    256 
    257   chrome.sync.events.dispatchEvent(networkEvent1);
    258   chrome.sync.events.dispatchEvent(networkEvent2);
    259 
    260   expectEquals(2, $('traffic-event-container').children.length);
    261 
    262   // Test that repeated events are not re-displayed.
    263   chrome.sync.events.dispatchEvent(networkEvent1);
    264   expectEquals(2, $('traffic-event-container').children.length);
    265 });
    266 
    267 TEST_F('SyncInternalsWebUITest', 'SearchTabDoesntChangeOnItemSelect',
    268        function() {
    269   // Select the search tab.
    270   $('sync-search-tab').selected = true;
    271   expectTrue($('sync-search-tab').selected);
    272 
    273   // Build the data model and attach to result list.
    274   cr.ui.List.decorate($('sync-results-list'));
    275   $('sync-results-list').dataModel = new cr.ui.ArrayDataModel([
    276     {
    277       value: 'value 0',
    278       toString: function() { return 'node 0'; },
    279     },
    280     {
    281       value: 'value 1',
    282       toString: function() { return 'node 1'; },
    283     }
    284   ]);
    285 
    286   // Select the first list item and verify the search tab remains selected.
    287   $('sync-results-list').getListItemByIndex(0).selected = true;
    288   expectTrue($('sync-search-tab').selected);
    289 });
    290 
    291 TEST_F('SyncInternalsWebUITest', 'NodeBrowserTest', function() {
    292   var getAllNodesSavedArgs = new SaveMockArguments();
    293   this.mockHandler.expects(once()).
    294       getAllNodes(getAllNodesSavedArgs.match(ANYTHING)).
    295       will(callFunctionWithSavedArgs(getAllNodesSavedArgs,
    296                                      chrome.sync.getAllNodesCallback,
    297                                      HARD_CODED_ALL_NODES));
    298 
    299   // Hit the refresh button.
    300   $('node-browser-refresh-button').click();
    301 
    302   // Check that the refresh time was updated.
    303   expectNotEquals($('node-browser-refresh-time').textContent, 'Never');
    304 
    305   // Verify some hard-coded assumptions.  These depend on the vaue of the
    306   // hard-coded nodes, specified elsewhere in this file.
    307 
    308   // Start with the tree itself.
    309   var tree = $('sync-node-tree');
    310   assertEquals(1, tree.items.length);
    311 
    312   // Check the type root and expand it.
    313   var typeRoot = tree.items[0];
    314   expectFalse(typeRoot.expanded);
    315   typeRoot.expanded = true;
    316   assertEquals(1, typeRoot.items.length);
    317 
    318   // An actual sync node.  The child of the type root.
    319   var leaf = typeRoot.items[0];
    320 
    321   // Verify that selecting it affects the details view.
    322   expectTrue($('node-details').hasAttribute('hidden'));
    323   leaf.selected = true;
    324   expectFalse($('node-details').hasAttribute('hidden'));
    325 });
    326 
    327 TEST_F('SyncInternalsWebUITest', 'NodeBrowserRefreshOnTabSelect', function() {
    328   var getAllNodesSavedArgs = new SaveMockArguments();
    329   this.mockHandler.expects(once()).
    330       getAllNodes(getAllNodesSavedArgs.match(ANYTHING)).
    331       will(callFunctionWithSavedArgs(getAllNodesSavedArgs,
    332                                      chrome.sync.getAllNodesCallback,
    333                                      HARD_CODED_ALL_NODES));
    334 
    335   // Should start with non-refreshed node browser.
    336   expectEquals($('node-browser-refresh-time').textContent, 'Never');
    337 
    338   // Selecting the tab will refresh it.
    339   $('sync-browser-tab').selected = true;
    340   expectNotEquals($('node-browser-refresh-time').textContent, 'Never');
    341 
    342   // Re-selecting the tab shouldn't re-refresh.
    343   $('node-browser-refresh-time').textContent = 'TestCanary';
    344   $('sync-browser-tab').selected = false;
    345   $('sync-browser-tab').selected = true;
    346   expectEquals($('node-browser-refresh-time').textContent, 'TestCanary');
    347 });
    348 
    349 // Tests that the events log page correctly receives and displays an event.
    350 TEST_F('SyncInternalsWebUITest', 'EventLogTest', function() {
    351   // Dispatch an event.
    352   var connectionEvent = new Event('onConnectionStatusChange');
    353   connectionEvent.details = {'status': 'CONNECTION_OK'};
    354   chrome.sync.events.dispatchEvent(connectionEvent);
    355 
    356   // Verify that it is displayed in the events log.
    357   var syncEventsTable = $('sync-events');
    358   var firstRow = syncEventsTable.children[0];
    359 
    360   // Makes some assumptions about column ordering.  We'll need re-think this if
    361   // it turns out to be a maintenance burden.
    362   assertEquals(4, firstRow.children.length);
    363   var submoduleName = firstRow.children[1].textContent;
    364   var eventName = firstRow.children[2].textContent;
    365   var detailsText = firstRow.children[3].textContent;
    366 
    367   expectGE(submoduleName.indexOf('manager'), 0,
    368       'submoduleName=' + submoduleName);
    369   expectGE(eventName.indexOf('onConnectionStatusChange'), 0,
    370       'eventName=' + eventName);
    371   expectGE(detailsText.indexOf('CONNECTION_OK'), 0,
    372       'detailsText=' + detailsText);
    373 });
    374 
    375 TEST_F('SyncInternalsWebUITest', 'DumpSyncEventsToText', function() {
    376   // Dispatch an event.
    377   var connectionEvent = new Event('onConnectionStatusChange');
    378   connectionEvent.details = {'status': 'CONNECTION_OK'};
    379   chrome.sync.events.dispatchEvent(connectionEvent);
    380 
    381   // Click the dump-to-text button.
    382   $('dump-to-text').click();
    383 
    384   // Verify our event is among the results.
    385   var eventDumpText = $('data-dump').textContent;
    386 
    387   expectGE(eventDumpText.indexOf('onConnectionStatusChange'), 0);
    388   expectGE(eventDumpText.indexOf('CONNECTION_OK'), 0);
    389 });
    390