1/* 2 * Copyright (C) 2013, 2014 Apple 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 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 14 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 15 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 16 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 17 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 19 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26WebInspector.loaded = function() 27{ 28 // Register observers for events from the InspectorBackend. 29 // The initialization order should match the same in Main.js. 30 InspectorBackend.registerInspectorDispatcher(new WebInspector.InspectorObserver); 31 InspectorBackend.registerPageDispatcher(new WebInspector.PageObserver); 32 InspectorBackend.registerDOMDispatcher(new WebInspector.DOMObserver); 33 InspectorBackend.registerNetworkDispatcher(new WebInspector.NetworkObserver); 34 InspectorBackend.registerDebuggerDispatcher(new WebInspector.DebuggerObserver); 35 InspectorBackend.registerTimelineDispatcher(new WebInspector.TimelineObserver); 36 InspectorBackend.registerCSSDispatcher(new WebInspector.CSSObserver); 37 InspectorBackend.registerRuntimeDispatcher(new WebInspector.RuntimeObserver); 38 if (InspectorBackend.registerReplayDispatcher) 39 InspectorBackend.registerReplayDispatcher(new WebInspector.ReplayObserver); 40 41 // Instantiate controllers used by tests. 42 this.frameResourceManager = new WebInspector.FrameResourceManager; 43 this.domTreeManager = new WebInspector.DOMTreeManager; 44 this.cssStyleManager = new WebInspector.CSSStyleManager; 45 this.runtimeManager = new WebInspector.RuntimeManager; 46 this.timelineManager = new WebInspector.TimelineManager; 47 this.debuggerManager = new WebInspector.DebuggerManager; 48 this.probeManager = new WebInspector.ProbeManager; 49 this.replayManager = new WebInspector.ReplayManager; 50 51 document.addEventListener("DOMContentLoaded", this.contentLoaded.bind(this)); 52 53 // Enable agents. 54 InspectorAgent.enable(); 55 56 // Establish communication with the InspectorBackend. 57 InspectorFrontendHost.loaded(); 58} 59 60WebInspector.contentLoaded = function() { 61 // Signal that the frontend is now ready to receive messages. 62 InspectorFrontendAPI.loadCompleted(); 63} 64 65// Add stubs that are called by the frontend API. 66WebInspector.updateDockedState = function() 67{ 68} 69 70// InspectorTest contains extra methods that are only available to test code running 71// in the Web Inspector page. They rely on equivalents in the actual test page 72// which are provided by `inspector-test.js`. 73InspectorTest = {}; 74 75// This is a workaround for the fact that it would be hard to set up a constructor, 76// prototype, and prototype chain for the singleton InspectorTest. 77InspectorTest.EventDispatcher = function() 78{ 79 WebInspector.Object.call(this); 80}; 81 82InspectorTest.EventDispatcher.Event = { 83 TestPageDidLoad: "inspector-test-test-page-did-load" 84}; 85 86InspectorTest.EventDispatcher.prototype = { 87 __proto__: WebInspector.Object.prototype, 88 constructor: InspectorTest.EventDispatcher, 89 90 dispatchEvent: function(event) 91 { 92 this.dispatchEventToListeners(event); 93 } 94}; 95 96InspectorTest.eventDispatcher = new InspectorTest.EventDispatcher; 97 98// Note: Additional InspectorTest methods are included on a per-test basis from 99// files like `debugger-test.js`. 100 101// Appends a log message in the test document. 102InspectorTest.log = function(message) 103{ 104 var stringifiedMessage = typeof message !== "object" ? message : JSON.stringify(message); 105 InspectorTest.addResult(stringifiedMessage); 106} 107 108// Appends a message in the test document only if the condition is false. 109InspectorTest.assert = function(condition, message) 110{ 111 if (condition) 112 return; 113 114 var stringifiedMessage = typeof message !== "object" ? message : JSON.stringify(message); 115 InspectorTest.addResult("ASSERT: " + stringifiedMessage); 116} 117 118// Appends a message in the test document whether the condition is true or not. 119InspectorTest.expectThat = function(condition, message) 120{ 121 var prefix = condition ? "PASS" : "FAIL"; 122 var stringifiedMessage = typeof message !== "object" ? message : JSON.stringify(message); 123 InspectorTest.addResult(prefix + ": " + stringifiedMessage); 124} 125 126// This function should only be used to debug tests and not to produce normal test output. 127InspectorTest.debugLog = function(message) 128{ 129 this.evaluateInPage("InspectorTestProxy.debugLog(unescape('" + escape(JSON.stringify(message)) + "'))"); 130} 131 132InspectorTest.completeTest = function() 133{ 134 function signalCompletionToTestPage() { 135 InspectorBackend.runAfterPendingDispatches(this.evaluateInPage.bind(this, "InspectorTestProxy.completeTest()")); 136 } 137 138 // Wait for results to be resent before requesting completeTest(). Otherwise, messages will be 139 // queued after pending dispatches run to zero and the test page will quit before processing them. 140 if (this._shouldResendResults) 141 this._resendResults(signalCompletionToTestPage.bind(this)); 142 else 143 signalCompletionToTestPage.call(this); 144} 145 146InspectorTest.evaluateInPage = function(codeString, callback) 147{ 148 // If we load this page outside of the inspector, or hit an early error when loading 149 // the test frontend, then defer evaluating the commands (indefinitely in the former case). 150 if (!RuntimeAgent) { 151 this._originalConsoleMethods["error"]("Tried to evaluate in test page, but connection not yet established:", codeString); 152 return; 153 } 154 155 RuntimeAgent.evaluate.invoke({expression: codeString, objectGroup: "test", includeCommandLineAPI: false}, callback); 156} 157 158InspectorTest.addResult = function(text) 159{ 160 this._results.push(text); 161 162 if (!this._testPageIsReloading) 163 this.evaluateInPage("InspectorTestProxy.addResult(unescape('" + escape(text) + "'))"); 164} 165 166InspectorTest._resendResults = function(callback) 167{ 168 console.assert(this._shouldResendResults); 169 delete this._shouldResendResults; 170 171 var pendingResponseCount = 1 + this._results.length; 172 function decrementPendingResponseCount() { 173 pendingResponseCount--; 174 if (!pendingResponseCount && typeof callback === "function") 175 callback(); 176 } 177 178 this.evaluateInPage("InspectorTestProxy.clearResults()", decrementPendingResponseCount); 179 for (var result of this._results) 180 this.evaluateInPage("InspectorTestProxy.addResult(unescape('" + escape(result) + "'))", decrementPendingResponseCount); 181} 182 183InspectorTest.testPageDidLoad = function() 184{ 185 this._testPageIsReloading = false; 186 this._resendResults(); 187 188 this.eventDispatcher.dispatchEvent(InspectorTest.EventDispatcher.Event.TestPageDidLoad); 189} 190 191InspectorTest.reloadPage = function(shouldIgnoreCache) 192{ 193 return PageAgent.reload.promise(!!shouldIgnoreCache) 194 .then(function() { 195 this._shouldResendResults = true; 196 this._testPageIsReloading = true; 197 198 return Promise.resolve(null); 199 }); 200} 201 202InspectorTest.reportUncaughtException = function(message, url, lineNumber) 203{ 204 var result = "Uncaught exception in inspector page: " + message + " [" + url + ":" + lineNumber + "]"; 205 206 // If the connection to the test page is not set up, then just dump to console and give up. 207 // Errors encountered this early can be debugged by loading Test.html in a normal browser page. 208 if (!InspectorFrontendHost || !InspectorBackend) { 209 this._originalConsoleMethods["error"](result); 210 return false; 211 } 212 213 this.addResult(result); 214 this.completeTest(); 215 // Stop default handler so we can empty InspectorBackend's message queue. 216 return true; 217} 218 219// Initialize reporting mechanisms before loading the rest of the inspector page. 220InspectorTest._results = []; 221InspectorTest._shouldResendResults = true; 222InspectorTest._originalConsoleMethods = {}; 223 224// Catch syntax errors, type errors, and other exceptions. 225window.onerror = InspectorTest.reportUncaughtException.bind(InspectorTest); 226 227for (var logType of ["log", "error", "info"]) { 228 // Redirect console methods to log messages into the test page's DOM. 229 InspectorTest._originalConsoleMethods[logType] = console[logType].bind(console); 230 console[logType] = function() { 231 InspectorTest.addResult(logType.toUpperCase() + ": " + Array.prototype.slice.call(arguments).toString()); 232 }; 233} 234