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.
6 * Test fixture for sync internals WebUI testing.
8 * @extends {testing.Test}
10 function SyncInternalsWebUITest() {}
12 SyncInternalsWebUITest.prototype = {
13 __proto__: testing.Test.prototype,
16 * Browse to the sync internals page.
19 browsePreload: 'chrome://sync-internals',
22 * Disable accessibility testing for this page.
25 runAccessibilityChecks: false,
29 this.makeAndRegisterMockHandler([
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.
42 hasInDetails: function(isValid, key, value) {
43 var details = chrome.sync.aboutInfo.details;
46 for (var i = 0; i < details.length; ++i) {
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;
60 * Constant hard-coded value to return from mock getAllNodes.
63 var HARD_CODED_ALL_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==',
73 'IS_UNAPPLIED_UPDATE': false,
75 'LOCAL_EXTERNAL_ID': '0',
77 'MTIME': 'Wednesday, December 31, 1969 4:00:00 PM',
78 'NON_UNIQUE_NAME': 'Autofill',
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',
91 'SERVER_UNIQUE_POSITION': 'INVALID[]',
92 'SERVER_VERSION': '1396470970810000',
99 'TRANSACTION_VERSION': '1',
100 'UNIQUE_BOOKMARK_TAG': '',
101 'UNIQUE_CLIENT_TAG': '',
102 'UNIQUE_POSITION': 'INVALID[]',
103 'UNIQUE_SERVER_TAG': 'google_chrome_autofill',
105 'modelType': 'Autofill'
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==',
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': {
133 'usage_timestamp': ['13038713887000000', '13038713890000000'],
134 'value': 'rlsynctet2'
137 'SERVER_UNIQUE_POSITION': 'INVALID[]',
138 'SERVER_VERSION': '1394241139528639',
142 'usage_timestamp': ['13038713887000000', '13038713890000000'],
143 'value': 'rlsynctet2'
147 'TRANSACTION_VERSION': '1',
148 'UNIQUE_BOOKMARK_TAG': '',
149 'UNIQUE_CLIENT_TAG': 'EvliorKUf1rLjT+BGkNZp586Tsk=',
150 'UNIQUE_POSITION': 'INVALID[]',
151 'UNIQUE_SERVER_TAG': '',
153 'modelType': 'Autofill'
159 * A value to return in mock onReceivedUpdatedAboutInfo event.
162 HARD_CODED_ABOUT_INFO = {
163 'actionable_error': [
166 'stat_name': 'Error Type',
167 'stat_value': 'Uninitialized'
171 'stat_name': 'Action',
172 'stat_value': 'Uninitialized'
177 'stat_value': 'Uninitialized'
181 'stat_name': 'Error Description',
182 'stat_value': 'Uninitialized'
185 'actionable_error_detected': false,
191 'stat_name': 'Summary',
192 'stat_value': 'Sync service initialized'
195 'is_sensitive': false,
201 'name': 'Model Type',
202 'num_entries': 'Total Entries',
203 'num_live': 'Live Entries',
205 'value': 'Group Type'
212 'value': 'Active: GROUP_UI'
215 'unrecoverable_error_detected': false
218 NETWORK_EVENT_DETAILS_1 = {
219 'details': 'Notified types: Bookmarks, Autofill',
221 'time': 1395874542192.407,
222 'type': 'Normal GetUpdate request',
225 NETWORK_EVENT_DETAILS_2 = {
226 'details': 'Received error: SYNC_AUTH_ERROR',
228 'time': 1395874542192.837,
229 'type': 'GetUpdates Response',
232 TEST_F('SyncInternalsWebUITest', 'Uninitialized', function() {
233 assertNotEquals(null, chrome.sync.aboutInfo);
234 expectTrue(this.hasInDetails(false, 'Summary', 'Uninitialized'));
237 // Test that username is set correctly when the user is signed in or not.
238 // On chromeos, browser tests are signed in by default. On other platforms,
239 // browser tests are signed out.
240 GEN('#if defined(OS_CHROMEOS)');
241 TEST_F('SyncInternalsWebUITest', 'SignedIn', function() {
242 assertNotEquals(null, chrome.sync.aboutInfo);
243 expectTrue(this.hasInDetails(true, 'Username', 'stub-user@example.com'));
246 TEST_F('SyncInternalsWebUITest', 'SignedOut', function() {
247 assertNotEquals(null, chrome.sync.aboutInfo);
248 expectTrue(this.hasInDetails(true, 'Username', ''));
250 GEN('#endif // defined(OS_CHROMEOS)');
252 TEST_F('SyncInternalsWebUITest', 'LoadPastedAboutInfo', function() {
253 // Expose the text field.
254 $('import-status').click();
256 // Fill it with fake data.
257 $('status-text').value = JSON.stringify(HARD_CODED_ABOUT_INFO);
259 // Trigger the import.
260 $('import-status').click();
262 expectTrue(this.hasInDetails(true, 'Summary', 'Sync service initialized'));
265 TEST_F('SyncInternalsWebUITest', 'NetworkEventsTest', function() {
266 networkEvent1 = new Event('onProtocolEvent');
267 networkEvent1.details = NETWORK_EVENT_DETAILS_1;
268 networkEvent2 = new Event('onProtocolEvent');
269 networkEvent2.details = NETWORK_EVENT_DETAILS_2;
271 chrome.sync.events.dispatchEvent(networkEvent1);
272 chrome.sync.events.dispatchEvent(networkEvent2);
274 expectEquals(2, $('traffic-event-container').children.length);
276 // Test that repeated events are not re-displayed.
277 chrome.sync.events.dispatchEvent(networkEvent1);
278 expectEquals(2, $('traffic-event-container').children.length);
281 TEST_F('SyncInternalsWebUITest', 'SearchTabDoesntChangeOnItemSelect',
283 // Select the search tab.
284 $('sync-search-tab').selected = true;
285 expectTrue($('sync-search-tab').selected);
287 // Build the data model and attach to result list.
288 cr.ui.List.decorate($('sync-results-list'));
289 $('sync-results-list').dataModel = new cr.ui.ArrayDataModel([
292 toString: function() { return 'node 0'; },
296 toString: function() { return 'node 1'; },
300 // Select the first list item and verify the search tab remains selected.
301 $('sync-results-list').getListItemByIndex(0).selected = true;
302 expectTrue($('sync-search-tab').selected);
305 TEST_F('SyncInternalsWebUITest', 'NodeBrowserTest', function() {
306 var getAllNodesSavedArgs = new SaveMockArguments();
307 this.mockHandler.expects(once()).
308 getAllNodes(getAllNodesSavedArgs.match(ANYTHING)).
309 will(callFunctionWithSavedArgs(getAllNodesSavedArgs,
310 chrome.sync.getAllNodesCallback,
311 HARD_CODED_ALL_NODES));
313 // Hit the refresh button.
314 $('node-browser-refresh-button').click();
316 // Check that the refresh time was updated.
317 expectNotEquals($('node-browser-refresh-time').textContent, 'Never');
319 // Verify some hard-coded assumptions. These depend on the vaue of the
320 // hard-coded nodes, specified elsewhere in this file.
322 // Start with the tree itself.
323 var tree = $('sync-node-tree');
324 assertEquals(1, tree.items.length);
326 // Check the type root and expand it.
327 var typeRoot = tree.items[0];
328 expectFalse(typeRoot.expanded);
329 typeRoot.expanded = true;
330 assertEquals(1, typeRoot.items.length);
332 // An actual sync node. The child of the type root.
333 var leaf = typeRoot.items[0];
335 // Verify that selecting it affects the details view.
336 expectTrue($('node-details').hasAttribute('hidden'));
337 leaf.selected = true;
338 expectFalse($('node-details').hasAttribute('hidden'));
341 TEST_F('SyncInternalsWebUITest', 'NodeBrowserRefreshOnTabSelect', function() {
342 var getAllNodesSavedArgs = new SaveMockArguments();
343 this.mockHandler.expects(once()).
344 getAllNodes(getAllNodesSavedArgs.match(ANYTHING)).
345 will(callFunctionWithSavedArgs(getAllNodesSavedArgs,
346 chrome.sync.getAllNodesCallback,
347 HARD_CODED_ALL_NODES));
349 // Should start with non-refreshed node browser.
350 expectEquals($('node-browser-refresh-time').textContent, 'Never');
352 // Selecting the tab will refresh it.
353 $('sync-browser-tab').selected = true;
354 expectNotEquals($('node-browser-refresh-time').textContent, 'Never');
356 // Re-selecting the tab shouldn't re-refresh.
357 $('node-browser-refresh-time').textContent = 'TestCanary';
358 $('sync-browser-tab').selected = false;
359 $('sync-browser-tab').selected = true;
360 expectEquals($('node-browser-refresh-time').textContent, 'TestCanary');
363 // Tests that the events log page correctly receives and displays an event.
364 TEST_F('SyncInternalsWebUITest', 'EventLogTest', function() {
365 // Dispatch an event.
366 var connectionEvent = new Event('onConnectionStatusChange');
367 connectionEvent.details = {'status': 'CONNECTION_OK'};
368 chrome.sync.events.dispatchEvent(connectionEvent);
370 // Verify that it is displayed in the events log.
371 var syncEventsTable = $('sync-events');
372 var firstRow = syncEventsTable.children[0];
374 // Makes some assumptions about column ordering. We'll need re-think this if
375 // it turns out to be a maintenance burden.
376 assertEquals(4, firstRow.children.length);
377 var detailsText = firstRow.children[0].textContent;
378 var submoduleName = firstRow.children[1].textContent;
379 var eventName = firstRow.children[2].textContent;
381 expectGE(submoduleName.indexOf('manager'), 0,
382 'submoduleName=' + submoduleName);
383 expectGE(eventName.indexOf('onConnectionStatusChange'), 0,
384 'eventName=' + eventName);
385 expectGE(detailsText.indexOf('CONNECTION_OK'), 0,
386 'detailsText=' + detailsText);
389 TEST_F('SyncInternalsWebUITest', 'DumpSyncEventsToText', function() {
390 // Dispatch an event.
391 var connectionEvent = new Event('onConnectionStatusChange');
392 connectionEvent.details = {'status': 'CONNECTION_OK'};
393 chrome.sync.events.dispatchEvent(connectionEvent);
395 // Click the dump-to-text button.
396 $('dump-to-text').click();
398 // Verify our event is among the results.
399 var eventDumpText = $('data-dump').textContent;
401 expectGE(eventDumpText.indexOf('onConnectionStatusChange'), 0);
402 expectGE(eventDumpText.indexOf('CONNECTION_OK'), 0);