Upstream version 11.39.266.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / Tests.js
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31
32 /**
33  * @fileoverview This file contains small testing framework along with the
34  * test suite for the frontend. These tests are a part of the continues build
35  * and are executed by the devtools_sanity_unittest.cc as a part of the
36  * Interactive UI Test suite.
37  * FIXME: change field naming style to use trailing underscore.
38  */
39
40 if (window.domAutomationController) {
41
42 var ___interactiveUiTestsMode = true;
43
44 /**
45  * Test suite for interactive UI tests.
46  * @constructor
47  */
48 TestSuite = function()
49 {
50     this.controlTaken_ = false;
51     this.timerId_ = -1;
52 };
53
54
55 /**
56  * Reports test failure.
57  * @param {string} message Failure description.
58  */
59 TestSuite.prototype.fail = function(message)
60 {
61     if (this.controlTaken_)
62         this.reportFailure_(message);
63     else
64         throw message;
65 };
66
67
68 /**
69  * Equals assertion tests that expected === actual.
70  * @param {!Object} expected Expected object.
71  * @param {!Object} actual Actual object.
72  * @param {string} opt_message User message to print if the test fails.
73  */
74 TestSuite.prototype.assertEquals = function(expected, actual, opt_message)
75 {
76     if (expected !== actual) {
77         var message = "Expected: '" + expected + "', but was '" + actual + "'";
78         if (opt_message)
79             message = opt_message + "(" + message + ")";
80         this.fail(message);
81     }
82 };
83
84 /**
85  * True assertion tests that value == true.
86  * @param {!Object} value Actual object.
87  * @param {string} opt_message User message to print if the test fails.
88  */
89 TestSuite.prototype.assertTrue = function(value, opt_message)
90 {
91     this.assertEquals(true, !!value, opt_message);
92 };
93
94
95 /**
96  * HasKey assertion tests that object has given key.
97  * @param {!Object} object
98  * @param {string} key
99  */
100 TestSuite.prototype.assertHasKey = function(object, key)
101 {
102     if (!object.hasOwnProperty(key))
103         this.fail("Expected object to contain key '" + key + "'");
104 };
105
106
107 /**
108  * Contains assertion tests that string contains substring.
109  * @param {string} string Outer.
110  * @param {string} substring Inner.
111  */
112 TestSuite.prototype.assertContains = function(string, substring)
113 {
114     if (string.indexOf(substring) === -1)
115         this.fail("Expected to: '" + string + "' to contain '" + substring + "'");
116 };
117
118
119 /**
120  * Takes control over execution.
121  */
122 TestSuite.prototype.takeControl = function()
123 {
124     this.controlTaken_ = true;
125     // Set up guard timer.
126     var self = this;
127     this.timerId_ = setTimeout(function() {
128         self.reportFailure_("Timeout exceeded: 20 sec");
129     }, 20000);
130 };
131
132
133 /**
134  * Releases control over execution.
135  */
136 TestSuite.prototype.releaseControl = function()
137 {
138     if (this.timerId_ !== -1) {
139         clearTimeout(this.timerId_);
140         this.timerId_ = -1;
141     }
142     this.reportOk_();
143 };
144
145
146 /**
147  * Async tests use this one to report that they are completed.
148  */
149 TestSuite.prototype.reportOk_ = function()
150 {
151     window.domAutomationController.send("[OK]");
152 };
153
154
155 /**
156  * Async tests use this one to report failures.
157  */
158 TestSuite.prototype.reportFailure_ = function(error)
159 {
160     if (this.timerId_ !== -1) {
161         clearTimeout(this.timerId_);
162         this.timerId_ = -1;
163     }
164     window.domAutomationController.send("[FAILED] " + error);
165 };
166
167
168 /**
169  * Runs all global functions starting with "test" as unit tests.
170  */
171 TestSuite.prototype.runTest = function(testName)
172 {
173     try {
174         this[testName]();
175         if (!this.controlTaken_)
176             this.reportOk_();
177     } catch (e) {
178         this.reportFailure_(e);
179     }
180 };
181
182
183 /**
184  * @param {string} panelName Name of the panel to show.
185  */
186 TestSuite.prototype.showPanel = function(panelName)
187 {
188     // Open Scripts panel.
189     var button = document.getElementById("tab-" + panelName);
190     button.selectTabForTest();
191     this.assertEquals(WebInspector.panels[panelName], WebInspector.inspectorView.currentPanel());
192 };
193
194
195 /**
196  * Overrides the method with specified name until it's called first time.
197  * @param {!Object} receiver An object whose method to override.
198  * @param {string} methodName Name of the method to override.
199  * @param {!Function} override A function that should be called right after the
200  *     overridden method returns.
201  * @param {boolean} opt_sticky Whether restore original method after first run
202  *     or not.
203  */
204 TestSuite.prototype.addSniffer = function(receiver, methodName, override, opt_sticky)
205 {
206     var orig = receiver[methodName];
207     if (typeof orig !== "function")
208         this.fail("Cannot find method to override: " + methodName);
209     var test = this;
210     receiver[methodName] = function(var_args) {
211         try {
212             var result = orig.apply(this, arguments);
213         } finally {
214             if (!opt_sticky)
215                 receiver[methodName] = orig;
216         }
217         // In case of exception the override won't be called.
218         try {
219             override.apply(this, arguments);
220         } catch (e) {
221             test.fail("Exception in overriden method '" + methodName + "': " + e);
222         }
223         return result;
224     };
225 };
226
227 /**
228  * Waits for current throttler invocations, if any.
229  * @param {!WebInspector.Throttler} throttler
230  * @param {!function} callback
231  */
232 TestSuite.prototype.waitForThrottler = function(throttler, callback)
233 {
234     var test = this;
235     var scheduleShouldFail = true;
236     test.addSniffer(throttler, "schedule", onSchedule);
237
238     function hasSomethingScheduled()
239     {
240         return throttler._isRunningProcess || throttler._process;
241     }
242
243     function checkState()
244     {
245         if (!hasSomethingScheduled()) {
246             scheduleShouldFail = false;
247             callback();
248             return;
249         }
250
251         test.addSniffer(throttler, "_processCompletedForTests", checkState);
252     }
253
254     function onSchedule()
255     {
256         if (scheduleShouldFail)
257             test.fail("Unexpected Throttler.schedule");
258     }
259
260     checkState();
261 };
262
263 // UI Tests
264
265
266 /**
267  * Tests that scripts tab can be open and populated with inspected scripts.
268  */
269 TestSuite.prototype.testShowScriptsTab = function()
270 {
271     this.showPanel("sources");
272     var test = this;
273     // There should be at least main page script.
274     this._waitUntilScriptsAreParsed(["debugger_test_page.html"],
275         function() {
276             test.releaseControl();
277         });
278     // Wait until all scripts are added to the debugger.
279     this.takeControl();
280 };
281
282
283 /**
284  * Tests that scripts tab is populated with inspected scripts even if it
285  * hadn't been shown by the moment inspected paged refreshed.
286  * @see http://crbug.com/26312
287  */
288 TestSuite.prototype.testScriptsTabIsPopulatedOnInspectedPageRefresh = function()
289 {
290     var test = this;
291     this.assertEquals(WebInspector.panels.elements, WebInspector.inspectorView.currentPanel(), "Elements panel should be current one.");
292
293     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, waitUntilScriptIsParsed);
294
295     // Reload inspected page. It will reset the debugger agent.
296     test.evaluateInConsole_("window.location.reload(true);", function(resultText) {});
297
298     function waitUntilScriptIsParsed()
299     {
300         WebInspector.debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, waitUntilScriptIsParsed);
301         test.showPanel("sources");
302         test._waitUntilScriptsAreParsed(["debugger_test_page.html"],
303             function() {
304                 test.releaseControl();
305             });
306     }
307
308     // Wait until all scripts are added to the debugger.
309     this.takeControl();
310 };
311
312
313 /**
314  * Tests that scripts list contains content scripts.
315  */
316 TestSuite.prototype.testContentScriptIsPresent = function()
317 {
318     this.showPanel("sources");
319     var test = this;
320
321     test._waitUntilScriptsAreParsed(
322         ["page_with_content_script.html", "simple_content_script.js"],
323         function() {
324           test.releaseControl();
325         });
326
327     // Wait until all scripts are added to the debugger.
328     this.takeControl();
329 };
330
331
332 /**
333  * Tests that scripts are not duplicaed on Scripts tab switch.
334  */
335 TestSuite.prototype.testNoScriptDuplicatesOnPanelSwitch = function()
336 {
337     var test = this;
338
339     // There should be two scripts: one for the main page and another
340     // one which is source of console API(see
341     // InjectedScript._ensureCommandLineAPIInstalled).
342     var expectedScriptsCount = 2;
343     var parsedScripts = [];
344
345     this.showPanel("sources");
346
347     function switchToElementsTab() {
348         test.showPanel("elements");
349         setTimeout(switchToScriptsTab, 0);
350     }
351
352     function switchToScriptsTab() {
353         test.showPanel("sources");
354         setTimeout(checkScriptsPanel, 0);
355     }
356
357     function checkScriptsPanel() {
358         test.assertTrue(test._scriptsAreParsed(["debugger_test_page.html"]), "Some scripts are missing.");
359         checkNoDuplicates();
360         test.releaseControl();
361     }
362
363     function checkNoDuplicates() {
364         var uiSourceCodes = test.nonAnonymousUISourceCodes_();
365         for (var i = 0; i < uiSourceCodes.length; i++) {
366             var scriptName = uiSourceCodes[i].url;
367             for (var j = i + 1; j < uiSourceCodes.length; j++)
368                 test.assertTrue(scriptName !== uiSourceCodes[j].url, "Found script duplicates: " + test.uiSourceCodesToString_(uiSourceCodes));
369         }
370     }
371
372     test._waitUntilScriptsAreParsed(
373         ["debugger_test_page.html"],
374         function() {
375             checkNoDuplicates();
376             setTimeout(switchToElementsTab, 0);
377         });
378
379
380     // Wait until all scripts are added to the debugger.
381     this.takeControl();
382 };
383
384
385 // Tests that debugger works correctly if pause event occurs when DevTools
386 // frontend is being loaded.
387 TestSuite.prototype.testPauseWhenLoadingDevTools = function()
388 {
389     this.showPanel("sources");
390
391     // Script execution can already be paused.
392     if (WebInspector.debuggerModel.debuggerPausedDetails)
393         return;
394
395     this._waitForScriptPause(this.releaseControl.bind(this));
396     this.takeControl();
397 };
398
399
400 // Tests that pressing "Pause" will pause script execution if the script
401 // is already running.
402 TestSuite.prototype.testPauseWhenScriptIsRunning = function()
403 {
404     this.showPanel("sources");
405
406     this.evaluateInConsole_(
407         'setTimeout("handleClick()" , 0)',
408         didEvaluateInConsole.bind(this));
409
410     function didEvaluateInConsole(resultText) {
411         this.assertTrue(!isNaN(resultText), "Failed to get timer id: " + resultText);
412         // Wait for some time to make sure that inspected page is running the
413         // infinite loop.
414         setTimeout(testScriptPause.bind(this), 300);
415     }
416
417     function testScriptPause() {
418         // The script should be in infinite loop. Click "Pause" button to
419         // pause it and wait for the result.
420         WebInspector.panels.sources._pauseButton.element.click();
421
422         this._waitForScriptPause(this.releaseControl.bind(this));
423     }
424
425     this.takeControl();
426 };
427
428
429 /**
430  * Tests network size.
431  */
432 TestSuite.prototype.testNetworkSize = function()
433 {
434     var test = this;
435
436     function finishResource(resource, finishTime)
437     {
438         test.assertEquals(219, resource.transferSize, "Incorrect total encoded data length");
439         test.assertEquals(25, resource.resourceSize, "Incorrect total data length");
440         test.releaseControl();
441     }
442
443     this.addSniffer(WebInspector.NetworkDispatcher.prototype, "_finishNetworkRequest", finishResource);
444
445     // Reload inspected page to sniff network events
446     test.evaluateInConsole_("window.location.reload(true);", function(resultText) {});
447
448     this.takeControl();
449 };
450
451
452 /**
453  * Tests network sync size.
454  */
455 TestSuite.prototype.testNetworkSyncSize = function()
456 {
457     var test = this;
458
459     function finishResource(resource, finishTime)
460     {
461         test.assertEquals(219, resource.transferSize, "Incorrect total encoded data length");
462         test.assertEquals(25, resource.resourceSize, "Incorrect total data length");
463         test.releaseControl();
464     }
465
466     this.addSniffer(WebInspector.NetworkDispatcher.prototype, "_finishNetworkRequest", finishResource);
467
468     // Send synchronous XHR to sniff network events
469     test.evaluateInConsole_("var xhr = new XMLHttpRequest(); xhr.open(\"GET\", \"chunked\", false); xhr.send(null);", function() {});
470
471     this.takeControl();
472 };
473
474
475 /**
476  * Tests network raw headers text.
477  */
478 TestSuite.prototype.testNetworkRawHeadersText = function()
479 {
480     var test = this;
481
482     function finishResource(resource, finishTime)
483     {
484         if (!resource.responseHeadersText)
485             test.fail("Failure: resource does not have response headers text");
486         test.assertEquals(164, resource.responseHeadersText.length, "Incorrect response headers text length");
487         test.releaseControl();
488     }
489
490     this.addSniffer(WebInspector.NetworkDispatcher.prototype, "_finishNetworkRequest", finishResource);
491
492     // Reload inspected page to sniff network events
493     test.evaluateInConsole_("window.location.reload(true);", function(resultText) {});
494
495     this.takeControl();
496 };
497
498
499 /**
500  * Tests network timing.
501  */
502 TestSuite.prototype.testNetworkTiming = function()
503 {
504     var test = this;
505
506     function finishResource(resource, finishTime)
507     {
508         // Setting relaxed expectations to reduce flakiness.
509         // Server sends headers after 100ms, then sends data during another 100ms.
510         // We expect these times to be measured at least as 70ms.
511         test.assertTrue(resource.timing.receiveHeadersEnd - resource.timing.connectStart >= 70,
512                         "Time between receiveHeadersEnd and connectStart should be >=70ms, but was " +
513                         "receiveHeadersEnd=" + resource.timing.receiveHeadersEnd + ", connectStart=" + resource.timing.connectStart + ".");
514         test.assertTrue(resource.responseReceivedTime - resource.startTime >= 0.07,
515                 "Time between responseReceivedTime and startTime should be >=0.07s, but was " +
516                 "responseReceivedTime=" + resource.responseReceivedTime + ", startTime=" + resource.startTime + ".");
517         test.assertTrue(resource.endTime - resource.startTime >= 0.14,
518                 "Time between endTime and startTime should be >=0.14s, but was " +
519                 "endtime=" + resource.endTime + ", startTime=" + resource.startTime + ".");
520
521         test.releaseControl();
522     }
523
524     this.addSniffer(WebInspector.NetworkDispatcher.prototype, "_finishNetworkRequest", finishResource);
525
526     // Reload inspected page to sniff network events
527     test.evaluateInConsole_("window.location.reload(true);", function(resultText) {});
528
529     this.takeControl();
530 };
531
532
533 TestSuite.prototype.testConsoleOnNavigateBack = function()
534 {
535     if (WebInspector.multitargetConsoleModel.messages().length === 1)
536         firstConsoleMessageReceived.call(this);
537     else
538         WebInspector.multitargetConsoleModel.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, firstConsoleMessageReceived, this);
539
540     function firstConsoleMessageReceived() {
541         WebInspector.multitargetConsoleModel.removeEventListener(WebInspector.ConsoleModel.Events.MessageAdded, firstConsoleMessageReceived, this);
542         this.evaluateInConsole_("clickLink();", didClickLink.bind(this));
543     }
544
545     function didClickLink() {
546         // Check that there are no new messages(command is not a message).
547         this.assertEquals(3, WebInspector.multitargetConsoleModel.messages().length);
548         this.evaluateInConsole_("history.back();", didNavigateBack.bind(this));
549     }
550
551     function didNavigateBack()
552     {
553         // Make sure navigation completed and possible console messages were pushed.
554         this.evaluateInConsole_("void 0;", didCompleteNavigation.bind(this));
555     }
556
557     function didCompleteNavigation() {
558         this.assertEquals(7, WebInspector.multitargetConsoleModel.messages().length);
559         this.releaseControl();
560     }
561
562     this.takeControl();
563 };
564
565 TestSuite.prototype.testReattachAfterCrash = function()
566 {
567     PageAgent.navigate("about:crash");
568     PageAgent.navigate("about:blank");
569     WebInspector.runtimeModel.addEventListener(WebInspector.RuntimeModel.Events.ExecutionContextCreated, this.releaseControl, this);
570 };
571
572
573 TestSuite.prototype.testSharedWorker = function()
574 {
575     function didEvaluateInConsole(resultText) {
576         this.assertEquals("2011", resultText);
577         this.releaseControl();
578     }
579     this.evaluateInConsole_("globalVar", didEvaluateInConsole.bind(this));
580     this.takeControl();
581 };
582
583
584 TestSuite.prototype.testPauseInSharedWorkerInitialization = function()
585 {
586     if (WebInspector.debuggerModel.debuggerPausedDetails)
587         return;
588     this._waitForScriptPause(this.releaseControl.bind(this));
589     this.takeControl();
590 };
591
592 TestSuite.prototype.enableTouchEmulation = function()
593 {
594     WebInspector.targetManager.mainTarget().domModel.emulateTouchEventObjects(true);
595 };
596
597
598 // Regression test for crbug.com/370035.
599 TestSuite.prototype.testDeviceMetricsOverrides = function()
600 {
601     const dumpPageMetrics = function()
602     {
603         return JSON.stringify({
604             width: window.innerWidth,
605             height: window.innerHeight,
606             deviceScaleFactor: window.devicePixelRatio
607         });
608     };
609
610     var test = this;
611
612     function testOverrides(params, metrics, callback)
613     {
614         PageAgent.invoke_setDeviceMetricsOverride(params, getMetrics);
615
616         function getMetrics()
617         {
618             test.evaluateInConsole_("(" + dumpPageMetrics.toString() + ")()", checkMetrics);
619         }
620
621         function checkMetrics(consoleResult)
622         {
623             test.assertEquals('"' + JSON.stringify(metrics) + '"', consoleResult, "Wrong metrics for params: " + JSON.stringify(params));
624             callback();
625         }
626     }
627
628     function step1()
629     {
630         testOverrides({width: 1200, height: 1000, deviceScaleFactor: 1, mobile: false, fitWindow: true}, {width: 1200, height: 1000, deviceScaleFactor: 1}, step2);
631     }
632
633     function step2()
634     {
635         testOverrides({width: 1200, height: 1000, deviceScaleFactor: 1, mobile: false, fitWindow: false}, {width: 1200, height: 1000, deviceScaleFactor: 1}, step3);
636     }
637
638     function step3()
639     {
640         testOverrides({width: 1200, height: 1000, deviceScaleFactor: 3, mobile: false, fitWindow: true}, {width: 1200, height: 1000, deviceScaleFactor: 3}, step4);
641     }
642
643     function step4()
644     {
645         testOverrides({width: 1200, height: 1000, deviceScaleFactor: 3, mobile: false, fitWindow: false}, {width: 1200, height: 1000, deviceScaleFactor: 3}, finish);
646     }
647
648     function finish()
649     {
650         test.releaseControl();
651     }
652
653     WebInspector.overridesSupport._deviceMetricsChangedListenerMuted = true;
654     test.takeControl();
655     this.waitForThrottler(WebInspector.overridesSupport._deviceMetricsThrottler, step1);
656 };
657
658 TestSuite.prototype.waitForTestResultsInConsole = function()
659 {
660     var messages = WebInspector.multitargetConsoleModel.messages();
661     for (var i = 0; i < messages.length; ++i) {
662         var text = messages[i].messageText;
663         if (text === "PASS")
664             return;
665         else if (/^FAIL/.test(text))
666             this.fail(text); // This will throw.
667     }
668     // Neither PASS nor FAIL, so wait for more messages.
669     function onConsoleMessage(event)
670     {
671         var text = event.data.messageText;
672         if (text === "PASS")
673             this.releaseControl();
674         else if (/^FAIL/.test(text))
675             this.fail(text);
676     }
677
678     WebInspector.multitargetConsoleModel.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, onConsoleMessage, this);
679     this.takeControl();
680 };
681
682 TestSuite.prototype.checkLogAndErrorMessages = function()
683 {
684     var messages = WebInspector.multitargetConsoleModel.messages();
685
686     var matchesCount = 0;
687     function validMessage(message)
688     {
689         if (message.text === "log" && message.level === WebInspector.ConsoleMessage.MessageLevel.Log) {
690             ++matchesCount;
691             return true;
692         }
693
694         if (message.text === "error" && message.level === WebInspector.ConsoleMessage.MessageLevel.Error) {
695             ++matchesCount;
696             return true;
697         }
698         return false;
699     }
700
701     for (var i = 0; i < messages.length; ++i) {
702         if (validMessage(messages[i]))
703             continue;
704         this.fail(messages[i].text + ":" + messages[i].level); // This will throw.
705     }
706
707     if (matchesCount === 2)
708         return;
709
710     // Wait for more messages.
711     function onConsoleMessage(event)
712     {
713         var message = event.data;
714         if (validMessage(message)) {
715             if (matchesCount === 2) {
716                 this.releaseControl();
717                 return;
718             }
719         } else
720             this.fail(message.text + ":" + messages[i].level);
721     }
722
723     WebInspector.multitargetConsoleModel.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, onConsoleMessage, this);
724     this.takeControl();
725 };
726
727 /**
728  * Serializes array of uiSourceCodes to string.
729  * @param {!Array.<!WebInspectorUISourceCode>} uiSourceCodes
730  * @return {string}
731  */
732 TestSuite.prototype.uiSourceCodesToString_ = function(uiSourceCodes)
733 {
734     var names = [];
735     for (var i = 0; i < uiSourceCodes.length; i++)
736         names.push('"' + uiSourceCodes[i].url + '"');
737     return names.join(",");
738 };
739
740
741 /**
742  * Returns all loaded non anonymous uiSourceCodes.
743  * @return {!Array.<!WebInspectorUISourceCode>}
744  */
745 TestSuite.prototype.nonAnonymousUISourceCodes_ = function()
746 {
747     function filterOutAnonymous(uiSourceCode)
748     {
749         return !!uiSourceCode.url;
750     }
751
752     function filterOutService(uiSourceCode)
753     {
754         return !uiSourceCode.project().isServiceProject();
755     }
756
757     var uiSourceCodes = WebInspector.workspace.uiSourceCodes();
758     uiSourceCodes = uiSourceCodes.filter(filterOutService);
759     return uiSourceCodes.filter(filterOutAnonymous);
760 };
761
762
763 /*
764  * Evaluates the code in the console as if user typed it manually and invokes
765  * the callback when the result message is received and added to the console.
766  * @param {string} code
767  * @param {function(string)} callback
768  */
769 TestSuite.prototype.evaluateInConsole_ = function(code, callback)
770 {
771     function innerEvaluate()
772     {
773         WebInspector.console.show();
774         var consoleView = WebInspector.ConsolePanel._view();
775         consoleView._prompt.text = code;
776         consoleView._promptElement.dispatchEvent(TestSuite.createKeyEvent("Enter"));
777
778         this.addSniffer(WebInspector.ConsoleView.prototype, "_showConsoleMessage",
779             function(viewMessage) {
780                 callback(viewMessage.toMessageElement().textContent);
781             }.bind(this));
782     }
783
784     if (!WebInspector.context.flavor(WebInspector.ExecutionContext)) {
785         WebInspector.context.addFlavorChangeListener(WebInspector.ExecutionContext, innerEvaluate, this);
786         return;
787     }
788
789     innerEvaluate.call(this);
790 };
791
792 /**
793  * Checks that all expected scripts are present in the scripts list
794  * in the Scripts panel.
795  * @param {!Array.<string>} expected Regular expressions describing
796  *     expected script names.
797  * @return {boolean} Whether all the scripts are in "scripts-files" select
798  *     box
799  */
800 TestSuite.prototype._scriptsAreParsed = function(expected)
801 {
802     var uiSourceCodes = this.nonAnonymousUISourceCodes_();
803     // Check that at least all the expected scripts are present.
804     var missing = expected.slice(0);
805     for (var i = 0; i < uiSourceCodes.length; ++i) {
806         for (var j = 0; j < missing.length; ++j) {
807             if (uiSourceCodes[i].name().search(missing[j]) !== -1) {
808                 missing.splice(j, 1);
809                 break;
810             }
811         }
812     }
813     return missing.length === 0;
814 };
815
816
817 /**
818  * Waits for script pause, checks expectations, and invokes the callback.
819  * @param {function():void} callback
820  */
821 TestSuite.prototype._waitForScriptPause = function(callback)
822 {
823     function pauseListener(event) {
824         WebInspector.debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.DebuggerPaused, pauseListener, this);
825         callback();
826     }
827     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerPaused, pauseListener, this);
828 };
829
830
831 /**
832  * Waits until all the scripts are parsed and asynchronously executes the code
833  * in the inspected page.
834  */
835 TestSuite.prototype._executeCodeWhenScriptsAreParsed = function(code, expectedScripts)
836 {
837     var test = this;
838
839     function executeFunctionInInspectedPage() {
840         // Since breakpoints are ignored in evals' calculate() function is
841         // execute after zero-timeout so that the breakpoint is hit.
842         test.evaluateInConsole_(
843             'setTimeout("' + code + '" , 0)',
844             function(resultText) {
845                 test.assertTrue(!isNaN(resultText), "Failed to get timer id: " + resultText + ". Code: " + code);
846             });
847     }
848
849     test._waitUntilScriptsAreParsed(expectedScripts, executeFunctionInInspectedPage);
850 };
851
852
853 /**
854  * Waits until all the scripts are parsed and invokes the callback.
855  */
856 TestSuite.prototype._waitUntilScriptsAreParsed = function(expectedScripts, callback)
857 {
858     var test = this;
859
860     function waitForAllScripts() {
861         if (test._scriptsAreParsed(expectedScripts))
862             callback();
863         else
864             test.addSniffer(WebInspector.panels.sources.sourcesView(), "_addUISourceCode", waitForAllScripts);
865     }
866
867     waitForAllScripts();
868 };
869
870
871 /**
872  * Key event with given key identifier.
873  */
874 TestSuite.createKeyEvent = function(keyIdentifier)
875 {
876     var evt = document.createEvent("KeyboardEvent");
877     evt.initKeyboardEvent("keydown", true /* can bubble */, true /* can cancel */, null /* view */, keyIdentifier, "");
878     return evt;
879 };
880
881
882 /**
883  * Test runner for the test suite.
884  */
885 var uiTests = {};
886
887
888 /**
889  * Run each test from the test suit on a fresh instance of the suite.
890  */
891 uiTests.runAllTests = function()
892 {
893     // For debugging purposes.
894     for (var name in TestSuite.prototype) {
895         if (name.substring(0, 4) === "test" && typeof TestSuite.prototype[name] === "function")
896             uiTests.runTest(name);
897     }
898 };
899
900
901 /**
902  * Run specified test on a fresh instance of the test suite.
903  * @param {string} name Name of a test method from TestSuite class.
904  */
905 uiTests.runTest = function(name)
906 {
907     if (uiTests._populatedInterface)
908         new TestSuite().runTest(name);
909     else
910         uiTests._pendingTestName = name;
911 };
912
913 (function() {
914
915 function runTests()
916 {
917     uiTests._populatedInterface = true;
918     var name = uiTests._pendingTestName;
919     delete uiTests._pendingTestName;
920     if (name)
921         new TestSuite().runTest(name);
922 }
923
924 WebInspector.notifications.addEventListener(WebInspector.NotificationService.Events.InspectorAgentEnabledForTests, runTests);
925
926 })();
927
928 }