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 'serverModelType': '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 'serverModelType': '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(true, 'Username', ''));
235 expectTrue(this.hasInDetails(false, 'Summary', 'Uninitialized'));
238 TEST_F('SyncInternalsWebUITest', 'LoadPastedAboutInfo', function() {
239 // Expose the text field.
240 $('import-status').click();
242 // Fill it with fake data.
243 $('status-text').value
= JSON
.stringify(HARD_CODED_ABOUT_INFO
);
245 // Trigger the import.
246 $('import-status').click();
248 expectTrue(this.hasInDetails(true, 'Summary', 'Sync service initialized'));
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
;
257 chrome
.sync
.events
.dispatchEvent(networkEvent1
);
258 chrome
.sync
.events
.dispatchEvent(networkEvent2
);
260 expectEquals(2, $('traffic-event-container').children
.length
);
262 // Test that repeated events are not re-displayed.
263 chrome
.sync
.events
.dispatchEvent(networkEvent1
);
264 expectEquals(2, $('traffic-event-container').children
.length
);
267 TEST_F('SyncInternalsWebUITest', 'SearchTabDoesntChangeOnItemSelect',
269 // Select the search tab.
270 $('sync-search-tab').selected
= true;
271 expectTrue($('sync-search-tab').selected
);
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([
278 toString: function() { return 'node 0'; },
282 toString: function() { return 'node 1'; },
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
);
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
));
299 // Hit the refresh button.
300 $('node-browser-refresh-button').click();
302 // Check that the refresh time was updated.
303 expectNotEquals($('node-browser-refresh-time').textContent
, 'Never');
305 // Verify some hard-coded assumptions. These depend on the vaue of the
306 // hard-coded nodes, specified elsewhere in this file.
308 // Start with the tree itself.
309 var tree
= $('sync-node-tree');
310 assertEquals(1, tree
.items
.length
);
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
);
318 // An actual sync node. The child of the type root.
319 var leaf
= typeRoot
.items
[0];
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'));
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
));
335 // Should start with non-refreshed node browser.
336 expectEquals($('node-browser-refresh-time').textContent
, 'Never');
338 // Selecting the tab will refresh it.
339 $('sync-browser-tab').selected
= true;
340 expectNotEquals($('node-browser-refresh-time').textContent
, 'Never');
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');
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
);
356 // Verify that it is displayed in the events log.
357 var syncEventsTable
= $('sync-events');
358 var firstRow
= syncEventsTable
.children
[0];
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
;
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
);
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
);
381 // Click the dump-to-text button.
382 $('dump-to-text').click();
384 // Verify our event is among the results.
385 var eventDumpText
= $('data-dump').textContent
;
387 expectGE(eventDumpText
.indexOf('onConnectionStatusChange'), 0);
388 expectGE(eventDumpText
.indexOf('CONNECTION_OK'), 0);