2 * Copyright (C) 2010 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
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.
40 if (window.domAutomationController) {
42 var ___interactiveUiTestsMode = true;
45 * Test suite for interactive UI tests.
48 TestSuite = function()
50 this.controlTaken_ = false;
56 * Reports test failure.
57 * @param {string} message Failure description.
59 TestSuite.prototype.fail = function(message)
61 if (this.controlTaken_)
62 this.reportFailure_(message);
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.
74 TestSuite.prototype.assertEquals = function(expected, actual, opt_message)
76 if (expected !== actual) {
77 var message = "Expected: '" + expected + "', but was '" + actual + "'";
79 message = opt_message + "(" + message + ")";
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.
89 TestSuite.prototype.assertTrue = function(value, opt_message)
91 this.assertEquals(true, !!value, opt_message);
96 * HasKey assertion tests that object has given key.
97 * @param {!Object} object
100 TestSuite.prototype.assertHasKey = function(object, key)
102 if (!object.hasOwnProperty(key))
103 this.fail("Expected object to contain key '" + key + "'");
108 * Contains assertion tests that string contains substring.
109 * @param {string} string Outer.
110 * @param {string} substring Inner.
112 TestSuite.prototype.assertContains = function(string, substring)
114 if (string.indexOf(substring) === -1)
115 this.fail("Expected to: '" + string + "' to contain '" + substring + "'");
120 * Takes control over execution.
122 TestSuite.prototype.takeControl = function()
124 this.controlTaken_ = true;
125 // Set up guard timer.
127 this.timerId_ = setTimeout(function() {
128 self.reportFailure_("Timeout exceeded: 20 sec");
134 * Releases control over execution.
136 TestSuite.prototype.releaseControl = function()
138 if (this.timerId_ !== -1) {
139 clearTimeout(this.timerId_);
147 * Async tests use this one to report that they are completed.
149 TestSuite.prototype.reportOk_ = function()
151 window.domAutomationController.send("[OK]");
156 * Async tests use this one to report failures.
158 TestSuite.prototype.reportFailure_ = function(error)
160 if (this.timerId_ !== -1) {
161 clearTimeout(this.timerId_);
164 window.domAutomationController.send("[FAILED] " + error);
169 * Runs all global functions starting with "test" as unit tests.
171 TestSuite.prototype.runTest = function(testName)
175 if (!this.controlTaken_)
178 this.reportFailure_(e);
184 * @param {string} panelName Name of the panel to show.
186 TestSuite.prototype.showPanel = function(panelName)
188 // Open Scripts panel.
189 var button = document.getElementById("tab-" + panelName);
190 button.selectTabForTest();
191 this.assertEquals(WebInspector.panels[panelName], WebInspector.inspectorView.currentPanel());
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
204 TestSuite.prototype.addSniffer = function(receiver, methodName, override, opt_sticky)
206 var orig = receiver[methodName];
207 if (typeof orig !== "function")
208 this.fail("Cannot find method to override: " + methodName);
210 receiver[methodName] = function(var_args) {
212 var result = orig.apply(this, arguments);
215 receiver[methodName] = orig;
217 // In case of exception the override won't be called.
219 override.apply(this, arguments);
221 test.fail("Exception in overriden method '" + methodName + "': " + e);
232 * Tests that scripts tab can be open and populated with inspected scripts.
234 TestSuite.prototype.testShowScriptsTab = function()
236 this.showPanel("sources");
238 // There should be at least main page script.
239 this._waitUntilScriptsAreParsed(["debugger_test_page.html"],
241 test.releaseControl();
243 // Wait until all scripts are added to the debugger.
249 * Tests that scripts tab is populated with inspected scripts even if it
250 * hadn't been shown by the moment inspected paged refreshed.
251 * @see http://crbug.com/26312
253 TestSuite.prototype.testScriptsTabIsPopulatedOnInspectedPageRefresh = function()
256 this.assertEquals(WebInspector.panels.elements, WebInspector.inspectorView.currentPanel(), "Elements panel should be current one.");
258 WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, waitUntilScriptIsParsed);
260 // Reload inspected page. It will reset the debugger agent.
261 test.evaluateInConsole_("window.location.reload(true);", function(resultText) {});
263 function waitUntilScriptIsParsed()
265 WebInspector.debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, waitUntilScriptIsParsed);
266 test.showPanel("sources");
267 test._waitUntilScriptsAreParsed(["debugger_test_page.html"],
269 test.releaseControl();
273 // Wait until all scripts are added to the debugger.
279 * Tests that scripts list contains content scripts.
281 TestSuite.prototype.testContentScriptIsPresent = function()
283 this.showPanel("sources");
286 test._waitUntilScriptsAreParsed(
287 ["page_with_content_script.html", "simple_content_script.js"],
289 test.releaseControl();
292 // Wait until all scripts are added to the debugger.
298 * Tests that scripts are not duplicaed on Scripts tab switch.
300 TestSuite.prototype.testNoScriptDuplicatesOnPanelSwitch = function()
304 // There should be two scripts: one for the main page and another
305 // one which is source of console API(see
306 // InjectedScript._ensureCommandLineAPIInstalled).
307 var expectedScriptsCount = 2;
308 var parsedScripts = [];
310 this.showPanel("sources");
312 function switchToElementsTab() {
313 test.showPanel("elements");
314 setTimeout(switchToScriptsTab, 0);
317 function switchToScriptsTab() {
318 test.showPanel("sources");
319 setTimeout(checkScriptsPanel, 0);
322 function checkScriptsPanel() {
323 test.assertTrue(test._scriptsAreParsed(["debugger_test_page.html"]), "Some scripts are missing.");
325 test.releaseControl();
328 function checkNoDuplicates() {
329 var uiSourceCodes = test.nonAnonymousUISourceCodes_();
330 for (var i = 0; i < uiSourceCodes.length; i++) {
331 var scriptName = uiSourceCodes[i].url;
332 for (var j = i + 1; j < uiSourceCodes.length; j++)
333 test.assertTrue(scriptName !== uiSourceCodes[j].url, "Found script duplicates: " + test.uiSourceCodesToString_(uiSourceCodes));
337 test._waitUntilScriptsAreParsed(
338 ["debugger_test_page.html"],
341 setTimeout(switchToElementsTab, 0);
345 // Wait until all scripts are added to the debugger.
350 // Tests that debugger works correctly if pause event occurs when DevTools
351 // frontend is being loaded.
352 TestSuite.prototype.testPauseWhenLoadingDevTools = function()
354 this.showPanel("sources");
356 // Script execution can already be paused.
357 if (WebInspector.debuggerModel.debuggerPausedDetails)
360 this._waitForScriptPause(this.releaseControl.bind(this));
365 // Tests that pressing "Pause" will pause script execution if the script
366 // is already running.
367 TestSuite.prototype.testPauseWhenScriptIsRunning = function()
369 this.showPanel("sources");
371 this.evaluateInConsole_(
372 'setTimeout("handleClick()" , 0)',
373 didEvaluateInConsole.bind(this));
375 function didEvaluateInConsole(resultText) {
376 this.assertTrue(!isNaN(resultText), "Failed to get timer id: " + resultText);
377 // Wait for some time to make sure that inspected page is running the
379 setTimeout(testScriptPause.bind(this), 300);
382 function testScriptPause() {
383 // The script should be in infinite loop. Click "Pause" button to
384 // pause it and wait for the result.
385 WebInspector.panels.sources._pauseButton.element.click();
387 this._waitForScriptPause(this.releaseControl.bind(this));
395 * Tests network size.
397 TestSuite.prototype.testNetworkSize = function()
401 function finishResource(resource, finishTime)
403 test.assertEquals(219, resource.transferSize, "Incorrect total encoded data length");
404 test.assertEquals(25, resource.resourceSize, "Incorrect total data length");
405 test.releaseControl();
408 this.addSniffer(WebInspector.NetworkDispatcher.prototype, "_finishNetworkRequest", finishResource);
410 // Reload inspected page to sniff network events
411 test.evaluateInConsole_("window.location.reload(true);", function(resultText) {});
418 * Tests network sync size.
420 TestSuite.prototype.testNetworkSyncSize = function()
424 function finishResource(resource, finishTime)
426 test.assertEquals(219, resource.transferSize, "Incorrect total encoded data length");
427 test.assertEquals(25, resource.resourceSize, "Incorrect total data length");
428 test.releaseControl();
431 this.addSniffer(WebInspector.NetworkDispatcher.prototype, "_finishNetworkRequest", finishResource);
433 // Send synchronous XHR to sniff network events
434 test.evaluateInConsole_("var xhr = new XMLHttpRequest(); xhr.open(\"GET\", \"chunked\", false); xhr.send(null);", function() {});
441 * Tests network raw headers text.
443 TestSuite.prototype.testNetworkRawHeadersText = function()
447 function finishResource(resource, finishTime)
449 if (!resource.responseHeadersText)
450 test.fail("Failure: resource does not have response headers text");
451 test.assertEquals(164, resource.responseHeadersText.length, "Incorrect response headers text length");
452 test.releaseControl();
455 this.addSniffer(WebInspector.NetworkDispatcher.prototype, "_finishNetworkRequest", finishResource);
457 // Reload inspected page to sniff network events
458 test.evaluateInConsole_("window.location.reload(true);", function(resultText) {});
465 * Tests network timing.
467 TestSuite.prototype.testNetworkTiming = function()
471 function finishResource(resource, finishTime)
473 // Setting relaxed expectations to reduce flakiness.
474 // Server sends headers after 100ms, then sends data during another 100ms.
475 // We expect these times to be measured at least as 70ms.
476 test.assertTrue(resource.timing.receiveHeadersEnd - resource.timing.connectStart >= 70,
477 "Time between receiveHeadersEnd and connectStart should be >=70ms, but was " +
478 "receiveHeadersEnd=" + resource.timing.receiveHeadersEnd + ", connectStart=" + resource.timing.connectStart + ".");
479 test.assertTrue(resource.responseReceivedTime - resource.startTime >= 0.07,
480 "Time between responseReceivedTime and startTime should be >=0.07s, but was " +
481 "responseReceivedTime=" + resource.responseReceivedTime + ", startTime=" + resource.startTime + ".");
482 test.assertTrue(resource.endTime - resource.startTime >= 0.14,
483 "Time between endTime and startTime should be >=0.14s, but was " +
484 "endtime=" + resource.endTime + ", startTime=" + resource.startTime + ".");
486 test.releaseControl();
489 this.addSniffer(WebInspector.NetworkDispatcher.prototype, "_finishNetworkRequest", finishResource);
491 // Reload inspected page to sniff network events
492 test.evaluateInConsole_("window.location.reload(true);", function(resultText) {});
498 TestSuite.prototype.testConsoleOnNavigateBack = function()
500 if (WebInspector.console.messages.length === 1)
501 firstConsoleMessageReceived.call(this);
503 WebInspector.console.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, firstConsoleMessageReceived, this);
505 function firstConsoleMessageReceived() {
506 WebInspector.console.removeEventListener(WebInspector.ConsoleModel.Events.MessageAdded, firstConsoleMessageReceived, this);
507 this.evaluateInConsole_("clickLink();", didClickLink.bind(this));
510 function didClickLink() {
511 // Check that there are no new messages(command is not a message).
512 this.assertEquals(3, WebInspector.console.messages.length);
513 this.evaluateInConsole_("history.back();", didNavigateBack.bind(this));
516 function didNavigateBack()
518 // Make sure navigation completed and possible console messages were pushed.
519 this.evaluateInConsole_("void 0;", didCompleteNavigation.bind(this));
522 function didCompleteNavigation() {
523 this.assertEquals(7, WebInspector.console.messages.length);
524 this.releaseControl();
530 TestSuite.prototype.testReattachAfterCrash = function()
532 PageAgent.navigate("about:crash");
533 PageAgent.navigate("about:blank");
534 WebInspector.runtimeModel.addEventListener(WebInspector.RuntimeModel.Events.ExecutionContextCreated, this.releaseControl, this);
538 TestSuite.prototype.testSharedWorker = function()
540 function didEvaluateInConsole(resultText) {
541 this.assertEquals("2011", resultText);
542 this.releaseControl();
544 this.evaluateInConsole_("globalVar", didEvaluateInConsole.bind(this));
549 TestSuite.prototype.testPauseInSharedWorkerInitialization = function()
551 if (WebInspector.debuggerModel.debuggerPausedDetails)
553 this._waitForScriptPause(this.releaseControl.bind(this));
558 * Tests that timeline receives frame signals.
560 TestSuite.prototype.testTimelineFrames = function()
566 test.recordTimeline(onTimelineRecorded);
567 test.evaluateInConsole_("runTest()", function(){});
570 function onTimelineRecorded(records)
573 var recordsInFrame = {};
575 for (var i = 0; i < records.length; ++i) {
576 var record = records[i];
577 if (record.type() !== "BeginFrame") {
578 recordsInFrame[record.type()] = (recordsInFrame[record.type()] || 0) + 1;
584 test.assertHasKey(recordsInFrame, "FireAnimationFrame");
585 test.assertHasKey(recordsInFrame, "Layout");
586 test.assertHasKey(recordsInFrame, "RecalculateStyles");
587 test.assertHasKey(recordsInFrame, "Paint");
590 test.assertTrue(frameCount >= 5, "Not enough frames");
591 test.releaseControl();
598 TestSuite.prototype.enableTouchEmulation = function()
600 WebInspector.targetManager.activeTarget().domModel.emulateTouchEventObjects(true);
603 // Regression test for http://webk.it/97466
604 TestSuite.prototype.testPageOverlayUpdate = function()
607 WebInspector.inspectorView.panel("elements");
609 function populatePage()
611 var div1 = document.createElement("div");
613 // Force accelerated compositing.
614 div1.style.webkitTransform = "translateZ(0)";
615 document.body.appendChild(div1);
616 var div2 = document.createElement("div");
618 document.body.appendChild(div2);
623 test.evaluateInConsole_(populatePage.toString() + "; populatePage();" +
624 "inspect(document.getElementById('div1'))", function() {});
625 WebInspector.notifications.addEventListener(WebInspector.NotificationService.Events.SelectedNodeChanged, step2);
630 WebInspector.notifications.removeEventListener(WebInspector.NotificationService.Events.SelectedNodeChanged, step2);
631 test.recordTimeline(onTimelineRecorded);
632 setTimeout(step3, 500);
637 test.evaluateInConsole_("inspect(document.getElementById('div2'))", function() {});
638 WebInspector.notifications.addEventListener(WebInspector.NotificationService.Events.SelectedNodeChanged, step4);
643 WebInspector.notifications.removeEventListener(WebInspector.NotificationService.Events.SelectedNodeChanged, step4);
647 function onTimelineRecorded(records)
650 for (var i = 0; i < records.length; ++i)
651 types[records[i].type] = (types[records[i].type] || 0) + 1;
653 var frameCount = types["BeginFrame"];
654 // There should be at least two updates caused by selection of nodes.
655 test.assertTrue(frameCount >= 2, "Not enough DevTools overlay updates");
656 // We normally expect up to 3 frames, but allow for a bit more in case
657 // of some unexpected invalidations.
658 test.assertTrue(frameCount < 6, "Too many updates caused by DevTools overlay");
659 test.releaseControl();
668 * Records timeline till console.timeStamp("ready"), invokes callback with resulting records.
669 * @param {function(!Array.<!Object>)} callback
671 TestSuite.prototype.recordTimeline = function(callback)
674 var dispatchOnRecordType = {}
676 WebInspector.timelineManager.addEventListener(WebInspector.TimelineManager.EventTypes.TimelineEventRecorded, addRecord);
677 WebInspector.timelineManager.start();
679 function addRecord(event)
681 innerAddRecord(event.data);
684 function innerAddRecord(record)
686 records.push(record);
687 if (record.type() === "TimeStamp" && record.data().message === "ready")
690 if (record.children())
691 record.children().forEach(innerAddRecord);
696 WebInspector.timelineManager.stop();
697 WebInspector.timelineManager.removeEventListener(WebInspector.TimelineManager.EventTypes.TimelineEventRecorded, addRecord);
703 TestSuite.prototype.stopTimeline = function()
705 this.evaluateInConsole_("console.timeStamp('ready')", function() {});
708 TestSuite.prototype.waitForTestResultsInConsole = function()
710 var messages = WebInspector.console.messages;
711 for (var i = 0; i < messages.length; ++i) {
712 var text = messages[i].messageText;
715 else if (/^FAIL/.test(text))
716 this.fail(text); // This will throw.
718 // Neither PASS nor FAIL, so wait for more messages.
719 function onConsoleMessage(event)
721 var text = event.data.messageText;
723 this.releaseControl();
724 else if (/^FAIL/.test(text))
728 WebInspector.console.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, onConsoleMessage, this);
732 TestSuite.prototype.checkLogAndErrorMessages = function()
734 var messages = WebInspector.console.messages;
736 var matchesCount = 0;
737 function validMessage(message)
739 if (message.text === "log" && message.level === WebInspector.ConsoleMessage.MessageLevel.Log) {
744 if (message.text === "error" && message.level === WebInspector.ConsoleMessage.MessageLevel.Error) {
751 for (var i = 0; i < messages.length; ++i) {
752 if (validMessage(messages[i]))
754 this.fail(messages[i].text + ":" + messages[i].level); // This will throw.
757 if (matchesCount === 2)
760 // Wait for more messages.
761 function onConsoleMessage(event)
763 var message = event.data;
764 if (validMessage(message)) {
765 if (matchesCount === 2) {
766 this.releaseControl();
770 this.fail(message.text + ":" + messages[i].level);
773 WebInspector.console.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, onConsoleMessage, this);
778 * Serializes array of uiSourceCodes to string.
779 * @param {!Array.<!WebInspectorUISourceCode>} uiSourceCodes
782 TestSuite.prototype.uiSourceCodesToString_ = function(uiSourceCodes)
785 for (var i = 0; i < uiSourceCodes.length; i++)
786 names.push('"' + uiSourceCodes[i].url + '"');
787 return names.join(",");
792 * Returns all loaded non anonymous uiSourceCodes.
793 * @return {!Array.<!WebInspectorUISourceCode>}
795 TestSuite.prototype.nonAnonymousUISourceCodes_ = function()
797 function filterOutAnonymous(uiSourceCode)
799 return !!uiSourceCode.url;
802 function filterOutService(uiSourceCode)
804 return !uiSourceCode.project().isServiceProject();
807 var uiSourceCodes = WebInspector.workspace.uiSourceCodes();
808 uiSourceCodes = uiSourceCodes.filter(filterOutService);
809 return uiSourceCodes.filter(filterOutAnonymous);
814 * Evaluates the code in the console as if user typed it manually and invokes
815 * the callback when the result message is received and added to the console.
816 * @param {string} code
817 * @param {function(string)} callback
819 TestSuite.prototype.evaluateInConsole_ = function(code, callback)
821 function innerEvaluate()
823 WebInspector.console.show();
824 var consoleView = WebInspector.ConsolePanel._view();
825 consoleView._prompt.text = code;
826 consoleView._promptElement.dispatchEvent(TestSuite.createKeyEvent("Enter"));
828 this.addSniffer(WebInspector.ConsoleView.prototype, "_showConsoleMessage",
829 function(viewMessage) {
830 callback(viewMessage.toMessageElement().textContent);
834 if (!WebInspector.context.flavor(WebInspector.ExecutionContext)) {
835 WebInspector.context.addFlavorChangeListener(WebInspector.ExecutionContext, innerEvaluate, this);
839 innerEvaluate.call(this);
843 * Checks that all expected scripts are present in the scripts list
844 * in the Scripts panel.
845 * @param {!Array.<string>} expected Regular expressions describing
846 * expected script names.
847 * @return {boolean} Whether all the scripts are in "scripts-files" select
850 TestSuite.prototype._scriptsAreParsed = function(expected)
852 var uiSourceCodes = this.nonAnonymousUISourceCodes_();
853 // Check that at least all the expected scripts are present.
854 var missing = expected.slice(0);
855 for (var i = 0; i < uiSourceCodes.length; ++i) {
856 for (var j = 0; j < missing.length; ++j) {
857 if (uiSourceCodes[i].name().search(missing[j]) !== -1) {
858 missing.splice(j, 1);
863 return missing.length === 0;
868 * Waits for script pause, checks expectations, and invokes the callback.
869 * @param {function():void} callback
871 TestSuite.prototype._waitForScriptPause = function(callback)
873 function pauseListener(event) {
874 WebInspector.debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.DebuggerPaused, pauseListener, this);
877 WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerPaused, pauseListener, this);
882 * Waits until all the scripts are parsed and asynchronously executes the code
883 * in the inspected page.
885 TestSuite.prototype._executeCodeWhenScriptsAreParsed = function(code, expectedScripts)
889 function executeFunctionInInspectedPage() {
890 // Since breakpoints are ignored in evals' calculate() function is
891 // execute after zero-timeout so that the breakpoint is hit.
892 test.evaluateInConsole_(
893 'setTimeout("' + code + '" , 0)',
894 function(resultText) {
895 test.assertTrue(!isNaN(resultText), "Failed to get timer id: " + resultText + ". Code: " + code);
899 test._waitUntilScriptsAreParsed(expectedScripts, executeFunctionInInspectedPage);
904 * Waits until all the scripts are parsed and invokes the callback.
906 TestSuite.prototype._waitUntilScriptsAreParsed = function(expectedScripts, callback)
910 function waitForAllScripts() {
911 if (test._scriptsAreParsed(expectedScripts))
914 test.addSniffer(WebInspector.panels.sources.sourcesView(), "_addUISourceCode", waitForAllScripts);
922 * Key event with given key identifier.
924 TestSuite.createKeyEvent = function(keyIdentifier)
926 var evt = document.createEvent("KeyboardEvent");
927 evt.initKeyboardEvent("keydown", true /* can bubble */, true /* can cancel */, null /* view */, keyIdentifier, "");
933 * Test runner for the test suite.
939 * Run each test from the test suit on a fresh instance of the suite.
941 uiTests.runAllTests = function()
943 // For debugging purposes.
944 for (var name in TestSuite.prototype) {
945 if (name.substring(0, 4) === "test" && typeof TestSuite.prototype[name] === "function")
946 uiTests.runTest(name);
952 * Run specified test on a fresh instance of the test suite.
953 * @param {string} name Name of a test method from TestSuite class.
955 uiTests.runTest = function(name)
957 if (uiTests._populatedInterface)
958 new TestSuite().runTest(name);
960 uiTests._pendingTestName = name;
967 uiTests._populatedInterface = true;
968 var name = uiTests._pendingTestName;
969 delete uiTests._pendingTestName;
971 new TestSuite().runTest(name);
974 var oldLoadCompleted = InspectorFrontendAPI.loadCompleted;
975 InspectorFrontendAPI.loadCompleted = function()
977 oldLoadCompleted.call(InspectorFrontendAPI);