Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(309)

Side by Side Diff: chrome/browser/resources/file_manager/background/js/test_util.js

Issue 247123002: Move Files.app files to ui/file_manager (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix the test failure on non-chromeos Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 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 * Namespace for test related things.
7 */
8 var test = test || {};
9
10 /**
11 * Namespace for test utility functions.
12 *
13 * Public functions in the test.util.sync and the test.util.async namespaces are
14 * published to test cases and can be called by using callRemoteTestUtil. The
15 * arguments are serialized as JSON internally. If application ID is passed to
16 * callRemoteTestUtil, the content window of the application is added as the
17 * first argument. The functions in the test.util.async namespace are passed the
18 * callback function as the last argument.
19 */
20 test.util = {};
21
22 /**
23 * Namespace for synchronous utility functions.
24 */
25 test.util.sync = {};
26
27 /**
28 * Namespace for asynchronous utility functions.
29 */
30 test.util.async = {};
31
32 /**
33 * Extension ID of the testing extension.
34 * @type {string}
35 * @const
36 */
37 test.util.TESTING_EXTENSION_ID = 'oobinhbdbiehknkpbpejbbpdbkdjmoco';
38
39 /**
40 * Opens the main Files.app's window and waits until it is ready.
41 *
42 * @param {Object} appState App state.
43 * @param {function(string)} callback Completion callback with the new window's
44 * App ID.
45 */
46 test.util.async.openMainWindow = function(appState, callback) {
47 launchFileManager(appState,
48 undefined, // opt_type
49 undefined, // opt_id
50 callback);
51 };
52
53 /**
54 * Obtains window information.
55 *
56 * @param {string} appIdPrefix ID prefix of the requested window.
57 * @param {function(Array.<{innerWidth:number, innerHeight:number}>)} callback
58 * Completion callback with the window information.
59 * @return {Object.<string, {innerWidth:number, innerHeight:number}>} Map window
60 * ID and window information.
61 */
62 test.util.sync.getWindows = function() {
63 var windows = {};
64 for (var id in background.appWindows) {
65 var windowWrapper = background.appWindows[id];
66 windows[id] = {
67 innerWidth: windowWrapper.contentWindow.innerWidth,
68 innerHeight: windowWrapper.contentWindow.innerHeight
69 };
70 }
71 return windows;
72 };
73
74 /**
75 * Closes the specified window.
76 *
77 * @param {string} appId AppId of window to be closed.
78 * @return {boolean} Result: True if success, false otherwise.
79 */
80 test.util.sync.closeWindow = function(appId) {
81 if (appId in background.appWindows &&
82 background.appWindows[appId].contentWindow) {
83 background.appWindows[appId].close();
84 return true;
85 }
86 return false;
87 };
88
89 /**
90 * Gets a document in the Files.app's window, including iframes.
91 *
92 * @param {Window} contentWindow Window to be used.
93 * @param {string=} opt_iframeQuery Query for the iframe.
94 * @return {Document=} Returns the found document or undefined if not found.
95 * @private
96 */
97 test.util.sync.getDocument_ = function(contentWindow, opt_iframeQuery) {
98 if (opt_iframeQuery) {
99 var iframe = contentWindow.document.querySelector(opt_iframeQuery);
100 return iframe && iframe.contentWindow && iframe.contentWindow.document;
101 }
102
103 return contentWindow.document;
104 };
105
106 /**
107 * Gets total Javascript error count from background page and each app window.
108 * @return {number} Error count.
109 */
110 test.util.sync.getErrorCount = function() {
111 var totalCount = JSErrorCount;
112 for (var appId in background.appWindows) {
113 var contentWindow = background.appWindows[appId].contentWindow;
114 if (contentWindow.JSErrorCount)
115 totalCount += contentWindow.JSErrorCount;
116 }
117 return totalCount;
118 };
119
120 /**
121 * Resizes the window to the specified dimensions.
122 *
123 * @param {Window} contentWindow Window to be tested.
124 * @param {number} width Window width.
125 * @param {number} height Window height.
126 * @return {boolean} True for success.
127 */
128 test.util.sync.resizeWindow = function(contentWindow, width, height) {
129 background.appWindows[contentWindow.appID].resizeTo(width, height);
130 return true;
131 };
132
133 /**
134 * Returns an array with the files currently selected in the file manager.
135 * TODO(hirono): Integrate the method into getFileList method.
136 *
137 * @param {Window} contentWindow Window to be tested.
138 * @return {Array.<string>} Array of selected files.
139 */
140 test.util.sync.getSelectedFiles = function(contentWindow) {
141 var table = contentWindow.document.querySelector('#detail-table');
142 var rows = table.querySelectorAll('li');
143 var selected = [];
144 for (var i = 0; i < rows.length; ++i) {
145 if (rows[i].hasAttribute('selected')) {
146 selected.push(
147 rows[i].querySelector('.filename-label').textContent);
148 }
149 }
150 return selected;
151 };
152
153 /**
154 * Returns an array with the files on the file manager's file list.
155 *
156 * @param {Window} contentWindow Window to be tested.
157 * @return {Array.<Array.<string>>} Array of rows.
158 */
159 test.util.sync.getFileList = function(contentWindow) {
160 var table = contentWindow.document.querySelector('#detail-table');
161 var rows = table.querySelectorAll('li');
162 var fileList = [];
163 for (var j = 0; j < rows.length; ++j) {
164 var row = rows[j];
165 fileList.push([
166 row.querySelector('.filename-label').textContent,
167 row.querySelector('.size').textContent,
168 row.querySelector('.type').textContent,
169 row.querySelector('.date').textContent
170 ]);
171 }
172 return fileList;
173 };
174
175 /**
176 * Queries all elements.
177 *
178 * @param {Window} contentWindow Window to be tested.
179 * @param {string} targetQuery Query to specify the element.
180 * @param {?string} iframeQuery Iframe selector or null if no iframe.
181 * @param {Array.<string>=} opt_styleNames List of CSS property name to be
182 * obtained.
183 * @return {Array.<{attributes:Object.<string, string>, text:string,
184 * styles:Object.<string, string>, hidden:boolean}>} Element
185 * information that contains contentText, attribute names and
186 * values, hidden attribute, and style names and values.
187 */
188 test.util.sync.queryAllElements = function(
189 contentWindow, targetQuery, iframeQuery, opt_styleNames) {
190 var doc = test.util.sync.getDocument_(contentWindow, iframeQuery);
191 if (!doc)
192 return [];
193 // The return value of querySelectorAll is not an array.
194 return Array.prototype.map.call(
195 doc.querySelectorAll(targetQuery),
196 function(element) {
197 var attributes = {};
198 for (var i = 0; i < element.attributes.length; i++) {
199 attributes[element.attributes[i].nodeName] =
200 element.attributes[i].nodeValue;
201 }
202 var styles = {};
203 var styleNames = opt_styleNames || [];
204 var computedStyles = contentWindow.getComputedStyle(element);
205 for (var i = 0; i < styleNames.length; i++) {
206 styles[styleNames[i]] = computedStyles[styleNames[i]];
207 }
208 var text = element.textContent;
209 return {
210 attributes: attributes,
211 text: text,
212 styles: styles,
213 // The hidden attribute is not in the element.attributes even if
214 // element.hasAttribute('hidden') is true.
215 hidden: !!element.hidden
216 };
217 });
218 };
219
220 /**
221 * Assigns the text to the input element.
222 * @param {Window} contentWindow Window to be tested.
223 * @param {string} query Query for the input element.
224 * @param {string} text Text to be assigned.
225 */
226 test.util.sync.inputText = function(contentWindow, query, text) {
227 var input = contentWindow.document.querySelector(query);
228 input.value = text;
229 };
230
231 /**
232 * Fakes pressing the down arrow until the given |filename| is selected.
233 *
234 * @param {Window} contentWindow Window to be tested.
235 * @param {string} filename Name of the file to be selected.
236 * @return {boolean} True if file got selected, false otherwise.
237 */
238 test.util.sync.selectFile = function(contentWindow, filename) {
239 var rows = contentWindow.document.querySelectorAll('#detail-table li');
240 test.util.sync.fakeKeyDown(contentWindow, '#file-list', 'Home', false);
241 for (var index = 0; index < rows.length; ++index) {
242 var selection = test.util.sync.getSelectedFiles(contentWindow);
243 if (selection.length === 1 && selection[0] === filename)
244 return true;
245 test.util.sync.fakeKeyDown(contentWindow, '#file-list', 'Down', false);
246 }
247 console.error('Failed to select file "' + filename + '"');
248 return false;
249 };
250
251 /**
252 * Open the file by selectFile and fakeMouseDoubleClick.
253 *
254 * @param {Window} contentWindow Window to be tested.
255 * @param {string} filename Name of the file to be opened.
256 * @return {boolean} True if file got selected and a double click message is
257 * sent, false otherwise.
258 */
259 test.util.sync.openFile = function(contentWindow, filename) {
260 var query = '#file-list li.table-row[selected] .filename-label span';
261 return test.util.sync.selectFile(contentWindow, filename) &&
262 test.util.sync.fakeMouseDoubleClick(contentWindow, query);
263 };
264
265 /**
266 * Selects a volume specified by its icon name
267 *
268 * @param {Window} contentWindow Window to be tested.
269 * @param {string} iconName Name of the volume icon.
270 * @param {function(boolean)} callback Callback function to notify the caller
271 * whether the target is found and mousedown and click events are sent.
272 */
273 test.util.async.selectVolume = function(contentWindow, iconName, callback) {
274 var query = '[volume-type-icon=' + iconName + ']';
275 var driveQuery = '[volume-type-icon=drive]';
276 var isDriveSubVolume = iconName == 'drive_recent' ||
277 iconName == 'drive_shared_with_me' ||
278 iconName == 'drive_offline';
279 var preSelection = false;
280 var steps = {
281 checkQuery: function() {
282 if (contentWindow.document.querySelector(query)) {
283 steps.sendEvents();
284 return;
285 }
286 // If the target volume is sub-volume of drive, we must click 'drive'
287 // before clicking the sub-item.
288 if (!preSelection) {
289 if (!isDriveSubVolume) {
290 callback(false);
291 return;
292 }
293 if (!(test.util.sync.fakeMouseDown(contentWindow, driveQuery) &&
294 test.util.sync.fakeMouseClick(contentWindow, driveQuery))) {
295 callback(false);
296 return;
297 }
298 preSelection = true;
299 }
300 setTimeout(steps.checkQuery, 50);
301 },
302 sendEvents: function() {
303 // To change the selected volume, we have to send both events 'mousedown'
304 // and 'click' to the navigation list.
305 callback(test.util.sync.fakeMouseDown(contentWindow, query) &&
306 test.util.sync.fakeMouseClick(contentWindow, query));
307 }
308 };
309 steps.checkQuery();
310 };
311
312 /**
313 * Executes Javascript code on a webview and returns the result.
314 *
315 * @param {Window} contentWindow Window to be tested.
316 * @param {string} webViewQuery Selector for the web view.
317 * @param {string} code Javascript code to be executed within the web view.
318 * @param {function(*)} callback Callback function with results returned by the
319 * script.
320 */
321 test.util.async.executeScriptInWebView = function(
322 contentWindow, webViewQuery, code, callback) {
323 var webView = contentWindow.document.querySelector(webViewQuery);
324 webView.executeScript({code: code}, callback);
325 };
326
327 /**
328 * Sends an event to the element specified by |targetQuery|.
329 *
330 * @param {Window} contentWindow Window to be tested.
331 * @param {string} targetQuery Query to specify the element.
332 * @param {Event} event Event to be sent.
333 * @param {string=} opt_iframeQuery Optional iframe selector.
334 * @return {boolean} True if the event is sent to the target, false otherwise.
335 */
336 test.util.sync.sendEvent = function(
337 contentWindow, targetQuery, event, opt_iframeQuery) {
338 var doc = test.util.sync.getDocument_(contentWindow, opt_iframeQuery);
339 if (doc) {
340 var target = doc.querySelector(targetQuery);
341 if (target) {
342 target.dispatchEvent(event);
343 return true;
344 }
345 }
346 console.error('Target element for ' + targetQuery + ' not found.');
347 return false;
348 };
349
350 /**
351 * Sends an fake event having the specified type to the target query.
352 *
353 * @param {Window} contentWindow Window to be tested.
354 * @param {string} targetQuery Query to specify the element.
355 * @param {string} event Type of event.
356 * @return {boolean} True if the event is sent to the target, false otherwise.
357 */
358 test.util.sync.fakeEvent = function(contentWindow, targetQuery, event) {
359 return test.util.sync.sendEvent(
360 contentWindow, targetQuery, new Event(event));
361 };
362
363 /**
364 * Sends a fake key event to the element specified by |targetQuery| with the
365 * given |keyIdentifier| and optional |ctrl| modifier to the file manager.
366 *
367 * @param {Window} contentWindow Window to be tested.
368 * @param {string} targetQuery Query to specify the element.
369 * @param {string} keyIdentifier Identifier of the emulated key.
370 * @param {boolean} ctrl Whether CTRL should be pressed, or not.
371 * @param {string=} opt_iframeQuery Optional iframe selector.
372 * @return {boolean} True if the event is sent to the target, false otherwise.
373 */
374 test.util.sync.fakeKeyDown = function(
375 contentWindow, targetQuery, keyIdentifier, ctrl, opt_iframeQuery) {
376 var event = new KeyboardEvent(
377 'keydown',
378 { bubbles: true, keyIdentifier: keyIdentifier, ctrlKey: ctrl });
379 return test.util.sync.sendEvent(
380 contentWindow, targetQuery, event, opt_iframeQuery);
381 };
382
383 /**
384 * Simulates a fake mouse click (left button, single click) on the element
385 * specified by |targetQuery|. If the element has the click method, just calls
386 * it. Otherwise, this sends 'mouseover', 'mousedown', 'mouseup' and 'click'
387 * events in turns.
388 *
389 * @param {Window} contentWindow Window to be tested.
390 * @param {string} targetQuery Query to specify the element.
391 * @param {string=} opt_iframeQuery Optional iframe selector.
392 * @return {boolean} True if the all events are sent to the target, false
393 * otherwise.
394 */
395 test.util.sync.fakeMouseClick = function(
396 contentWindow, targetQuery, opt_iframeQuery) {
397 var mouseOverEvent = new MouseEvent('mouseover', {bubbles: true, detail: 1});
398 var resultMouseOver = test.util.sync.sendEvent(
399 contentWindow, targetQuery, mouseOverEvent, opt_iframeQuery);
400 var mouseDownEvent = new MouseEvent('mousedown', {bubbles: true, detail: 1});
401 var resultMouseDown = test.util.sync.sendEvent(
402 contentWindow, targetQuery, mouseDownEvent, opt_iframeQuery);
403 var mouseUpEvent = new MouseEvent('mouseup', {bubbles: true, detail: 1});
404 var resultMouseUp = test.util.sync.sendEvent(
405 contentWindow, targetQuery, mouseUpEvent, opt_iframeQuery);
406 var clickEvent = new MouseEvent('click', {bubbles: true, detail: 1});
407 var resultClick = test.util.sync.sendEvent(
408 contentWindow, targetQuery, clickEvent, opt_iframeQuery);
409 return resultMouseOver && resultMouseDown && resultMouseUp && resultClick;
410 };
411
412 /**
413 * Simulates a fake double click event (left button) to the element specified by
414 * |targetQuery|.
415 *
416 * @param {Window} contentWindow Window to be tested.
417 * @param {string} targetQuery Query to specify the element.
418 * @param {string=} opt_iframeQuery Optional iframe selector.
419 * @return {boolean} True if the event is sent to the target, false otherwise.
420 */
421 test.util.sync.fakeMouseDoubleClick = function(
422 contentWindow, targetQuery, opt_iframeQuery) {
423 // Double click is always preceded with a single click.
424 if (!test.util.sync.fakeMouseClick(
425 contentWindow, targetQuery, opt_iframeQuery)) {
426 return false;
427 }
428
429 // Send the second click event, but with detail equal to 2 (number of clicks)
430 // in a row.
431 var event = new MouseEvent('click', { bubbles: true, detail: 2 });
432 if (!test.util.sync.sendEvent(
433 contentWindow, targetQuery, event, opt_iframeQuery)) {
434 return false;
435 }
436
437 // Send the double click event.
438 var event = new MouseEvent('dblclick', { bubbles: true });
439 if (!test.util.sync.sendEvent(
440 contentWindow, targetQuery, event, opt_iframeQuery)) {
441 return false;
442 }
443
444 return true;
445 };
446
447 /**
448 * Sends a fake mouse down event to the element specified by |targetQuery|.
449 *
450 * @param {Window} contentWindow Window to be tested.
451 * @param {string} targetQuery Query to specify the element.
452 * @param {string=} opt_iframeQuery Optional iframe selector.
453 * @return {boolean} True if the event is sent to the target, false otherwise.
454 */
455 test.util.sync.fakeMouseDown = function(
456 contentWindow, targetQuery, opt_iframeQuery) {
457 var event = new MouseEvent('mousedown', { bubbles: true });
458 return test.util.sync.sendEvent(
459 contentWindow, targetQuery, event, opt_iframeQuery);
460 };
461
462 /**
463 * Sends a fake mouse up event to the element specified by |targetQuery|.
464 *
465 * @param {Window} contentWindow Window to be tested.
466 * @param {string} targetQuery Query to specify the element.
467 * @param {string=} opt_iframeQuery Optional iframe selector.
468 * @return {boolean} True if the event is sent to the target, false otherwise.
469 */
470 test.util.sync.fakeMouseUp = function(
471 contentWindow, targetQuery, opt_iframeQuery) {
472 var event = new MouseEvent('mouseup', { bubbles: true });
473 return test.util.sync.sendEvent(
474 contentWindow, targetQuery, event, opt_iframeQuery);
475 };
476
477 /**
478 * Selects |filename| and fakes pressing Ctrl+C, Ctrl+V (copy, paste).
479 *
480 * @param {Window} contentWindow Window to be tested.
481 * @param {string} filename Name of the file to be copied.
482 * @return {boolean} True if copying got simulated successfully. It does not
483 * say if the file got copied, or not.
484 */
485 test.util.sync.copyFile = function(contentWindow, filename) {
486 if (!test.util.sync.selectFile(contentWindow, filename))
487 return false;
488 // Ctrl+C and Ctrl+V
489 test.util.sync.fakeKeyDown(contentWindow, '#file-list', 'U+0043', true);
490 test.util.sync.fakeKeyDown(contentWindow, '#file-list', 'U+0056', true);
491 return true;
492 };
493
494 /**
495 * Selects |filename| and fakes pressing the Delete key.
496 *
497 * @param {Window} contentWindow Window to be tested.
498 * @param {string} filename Name of the file to be deleted.
499 * @return {boolean} True if deleting got simulated successfully. It does not
500 * say if the file got deleted, or not.
501 */
502 test.util.sync.deleteFile = function(contentWindow, filename) {
503 if (!test.util.sync.selectFile(contentWindow, filename))
504 return false;
505 // Delete
506 test.util.sync.fakeKeyDown(contentWindow, '#file-list', 'U+007F', false);
507 return true;
508 };
509
510 /**
511 * Execute a command on the document in the specified window.
512 *
513 * @param {Window} contentWindow Window to be tested.
514 * @param {string} command Command name.
515 * @return {boolean} True if the command is executed successfully.
516 */
517 test.util.sync.execCommand = function(contentWindow, command) {
518 return contentWindow.document.execCommand(command);
519 };
520
521 /**
522 * Override the installWebstoreItem method in private api for test.
523 *
524 * @param {Window} contentWindow Window to be tested.
525 * @param {string} expectedItemId Item ID to be called this method with.
526 * @param {?string} intendedError Error message to be returned when the item id
527 * matches. 'null' represents no error.
528 * @return {boolean} Always return true.
529 */
530 test.util.sync.overrideInstallWebstoreItemApi =
531 function(contentWindow, expectedItemId, intendedError) {
532 var setLastError = function(message) {
533 contentWindow.chrome.runtime.lastError =
534 message ? {message: message} : null;
535 };
536
537 var installWebstoreItem = function(itemId, callback) {
538 setTimeout(function() {
539 if (itemId !== expectedItemId) {
540 setLastError('Invalid Chrome Web Store item ID');
541 callback();
542 return;
543 }
544
545 setLastError(intendedError);
546 callback();
547 });
548 };
549
550 test.util.executedTasks_ = [];
551 contentWindow.chrome.fileBrowserPrivate.installWebstoreItem =
552 installWebstoreItem;
553 return true;
554 };
555
556 /**
557 * Override the task-related methods in private api for test.
558 *
559 * @param {Window} contentWindow Window to be tested.
560 * @param {Array.<Object>} taskList List of tasks to be returned in
561 * fileBrowserPrivate.getFileTasks().
562 * @return {boolean} Always return true.
563 */
564 test.util.sync.overrideTasks = function(contentWindow, taskList) {
565 var getFileTasks = function(urls, mime, onTasks) {
566 // Call onTask asynchronously (same with original getFileTasks).
567 setTimeout(function() {
568 onTasks(taskList);
569 });
570 };
571
572 var executeTask = function(taskId, url) {
573 test.util.executedTasks_.push(taskId);
574 };
575
576 test.util.executedTasks_ = [];
577 contentWindow.chrome.fileBrowserPrivate.getFileTasks = getFileTasks;
578 contentWindow.chrome.fileBrowserPrivate.executeTask = executeTask;
579 return true;
580 };
581
582 /**
583 * Obtains the list of executed tasks.
584 * @param {Window} contentWindow Window to be tested.
585 * @return {Array.<string>} List of executed task ID.
586 */
587 test.util.sync.getExecutedTasks = function(contentWindow) {
588 if (!test.util.executedTasks_) {
589 console.error('Please call overrideTasks() first.');
590 return null;
591 }
592 return test.util.executedTasks_;
593 };
594
595 /**
596 * Invoke chrome.fileBrowserPrivate.visitDesktop(profileId) to cause window
597 * teleportation.
598 *
599 * @param {Window} contentWindow Window to be tested.
600 * @param {string} profileId Destination profile's ID.
601 * @return {boolean} Always return true.
602 */
603 test.util.sync.visitDesktop = function(contentWindow, profileId) {
604 contentWindow.chrome.fileBrowserPrivate.visitDesktop(profileId);
605 return true;
606 };
607
608 /**
609 * Runs the 'Move to profileId' menu.
610 *
611 * @param {Window} contentWindow Window to be tested.
612 * @param {string} profileId Destination profile's ID.
613 * @return {boolean} True if the menu is found and run.
614 */
615 test.util.sync.runVisitDesktopMenu = function(contentWindow, profileId) {
616 var list = contentWindow.document.querySelectorAll('.visit-desktop');
617 for (var i = 0; i < list.length; ++i) {
618 if (list[i].label.indexOf(profileId) != -1) {
619 var activateEvent = contentWindow.document.createEvent('Event');
620 activateEvent.initEvent('activate');
621 list[i].dispatchEvent(activateEvent);
622 return true;
623 }
624 }
625 return false;
626 };
627
628 /**
629 * Registers message listener, which runs test utility functions.
630 */
631 test.util.registerRemoteTestUtils = function() {
632 // Register the message listener.
633 var onMessage = chrome.runtime ? chrome.runtime.onMessageExternal :
634 chrome.extension.onMessageExternal;
635 // Return true for asynchronous functions and false for synchronous.
636 onMessage.addListener(function(request, sender, sendResponse) {
637 // Check the sender.
638 if (sender.id != test.util.TESTING_EXTENSION_ID) {
639 console.error('The testing extension must be white-listed.');
640 return false;
641 }
642 // Set a global flag that we are in tests, so other components are aware
643 // of it.
644 window.IN_TEST = true;
645 // Check the function name.
646 if (!request.func || request.func[request.func.length - 1] == '_') {
647 request.func = '';
648 }
649 // Prepare arguments.
650 var args = request.args.slice(); // shallow copy
651 if (request.appId) {
652 if (!background.appWindows[request.appId]) {
653 console.error('Specified window not found: ' + request.appId);
654 return false;
655 }
656 args.unshift(background.appWindows[request.appId].contentWindow);
657 }
658 // Call the test utility function and respond the result.
659 if (test.util.async[request.func]) {
660 args[test.util.async[request.func].length - 1] = function() {
661 console.debug('Received the result of ' + request.func);
662 sendResponse.apply(null, arguments);
663 };
664 console.debug('Waiting for the result of ' + request.func);
665 test.util.async[request.func].apply(null, args);
666 return true;
667 } else if (test.util.sync[request.func]) {
668 sendResponse(test.util.sync[request.func].apply(null, args));
669 return false;
670 } else {
671 console.error('Invalid function name.');
672 return false;
673 }
674 });
675 };
676
677 // Register the test utils.
678 test.util.registerRemoteTestUtils();
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698