OLD | NEW |
(Empty) | |
| 1 <!-- |
| 2 Copyright (C) 2012 Samsung Electronics. 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 |
| 8 1. Redistributions of source code must retain the above copyright |
| 9 notice, this list of conditions and the following disclaimer. |
| 10 2. Redistributions in binary form must reproduce the above copyright |
| 11 notice, this list of conditions and the following disclaimer in the |
| 12 documentation and/or other materials provided with the distribution. |
| 13 |
| 14 THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
| 15 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 16 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 17 DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
| 18 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 19 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 20 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 21 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 22 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 23 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 24 --> |
| 25 <html> |
| 26 <head> |
| 27 <script> |
| 28 |
| 29 DevToolsAPI = {}; |
| 30 |
| 31 InspectorTest = {}; |
| 32 InspectorTest._dispatchTable = []; |
| 33 InspectorTest._requestId = -1; |
| 34 InspectorTest._dumpInspectorProtocolMessages = false; |
| 35 InspectorTest._embedderRequestId = -1; |
| 36 InspectorTest.eventHandler = {}; |
| 37 |
| 38 InspectorTest.startDumpingProtocolMessages = function() |
| 39 { |
| 40 InspectorTest._dumpInspectorProtocolMessages = true; |
| 41 } |
| 42 |
| 43 /** |
| 44 * @param {string} method |
| 45 * @param {object} params |
| 46 * @param {function({object} messageObject)=} handler |
| 47 */ |
| 48 InspectorTest.sendCommand = function(method, params, handler) |
| 49 { |
| 50 this._dispatchTable[++this._requestId] = handler; |
| 51 |
| 52 var messageObject = { "method": method, |
| 53 "params": params, |
| 54 "id": this._requestId }; |
| 55 |
| 56 if (InspectorTest._dumpInspectorProtocolMessages) |
| 57 testRunner.logToStderr("frontend: " + JSON.stringify(messageObject)); |
| 58 var embedderMessage = { "id": ++this._embedderRequestId, "method": "dispatch
ProtocolMessage", "params": [JSON.stringify(messageObject)] }; |
| 59 DevToolsHost.sendMessageToEmbedder(JSON.stringify(embedderMessage)); |
| 60 return this._requestId; |
| 61 } |
| 62 |
| 63 InspectorTest.sendCommandOrDie = function(command, properties, callback) |
| 64 { |
| 65 var fulfill; |
| 66 var result = new Promise(f => fulfill = f); |
| 67 |
| 68 InspectorTest.sendCommand(command, properties || {}, commandCallback); |
| 69 function commandCallback(msg) |
| 70 { |
| 71 if (msg.error) { |
| 72 InspectorTest.log("ERROR: " + msg.error.message); |
| 73 InspectorTest.completeTest(); |
| 74 return; |
| 75 } |
| 76 if (callback) |
| 77 callback(msg.result); |
| 78 fulfill(msg.result); |
| 79 } |
| 80 return result; |
| 81 } |
| 82 |
| 83 InspectorTest.sendCommandPromise = function(method, params) |
| 84 { |
| 85 var callback; |
| 86 var promise = new Promise(fulfill => callback = fulfill); |
| 87 InspectorTest.sendCommand(method, params, callback); |
| 88 return promise; |
| 89 } |
| 90 |
| 91 InspectorTest.waitForEventPromise = function(eventName) |
| 92 { |
| 93 return new Promise(fulfill => InspectorTest.eventHandler[eventName] = fullfi
llAndClearListener.bind(null, fulfill)); |
| 94 |
| 95 function fullfillAndClearListener(fulfill, result) |
| 96 { |
| 97 fulfill(result); |
| 98 delete InspectorTest.eventHandler[eventName]; |
| 99 } |
| 100 } |
| 101 |
| 102 InspectorTest.domUndo = function(callback) |
| 103 { |
| 104 InspectorTest.sendCommandOrDie("DOM.undo", {}, callback); |
| 105 } |
| 106 |
| 107 InspectorTest.undoAndNext = function(next) |
| 108 { |
| 109 return InspectorTest.domUndo.bind(InspectorTest, next); |
| 110 } |
| 111 |
| 112 InspectorTest.runTestSuite = function(testSuite) |
| 113 { |
| 114 function nextTest() |
| 115 { |
| 116 if (!testSuite.length) { |
| 117 InspectorTest.completeTest(); |
| 118 return; |
| 119 } |
| 120 var fun = testSuite.shift(); |
| 121 InspectorTest.log("\nRunning test: " + fun.name); |
| 122 fun(nextTest); |
| 123 } |
| 124 |
| 125 nextTest(); |
| 126 } |
| 127 |
| 128 /** |
| 129 * @param {function(object)=} callback |
| 130 */ |
| 131 InspectorTest.wrapCallback = function(callback) |
| 132 { |
| 133 /** |
| 134 * @param {object} message |
| 135 */ |
| 136 function callbackWrapper(message) |
| 137 { |
| 138 if (InspectorTest.completeTestIfError(message)) |
| 139 return; |
| 140 if (!callback) |
| 141 return; |
| 142 try { |
| 143 callback(message["result"]); |
| 144 } catch (e) { |
| 145 InspectorTest.log("Exception " + e + " while invoking callback: " +
callback); |
| 146 InspectorTest.completeTest(); |
| 147 } |
| 148 } |
| 149 return callbackWrapper; |
| 150 } |
| 151 |
| 152 /** |
| 153 * @param {string} command |
| 154 * @param {function({object} messageObject)=} handler |
| 155 */ |
| 156 InspectorTest.sendRawCommand = function(command, handler) |
| 157 { |
| 158 this._dispatchTable[++this._requestId] = handler; |
| 159 var embedderMessage = { "id": ++this._embedderRequestId, "method": "dispatch
ProtocolMessage", "params": [command] }; |
| 160 DevToolsHost.sendMessageToEmbedder(JSON.stringify(embedderMessage)); |
| 161 return this._requestId; |
| 162 } |
| 163 |
| 164 InspectorTest.readyForTest = function() |
| 165 { |
| 166 var embedderMessage = { "id": ++this._embedderRequestId, "method": "readyFor
Test" }; |
| 167 DevToolsHost.sendMessageToEmbedder(JSON.stringify(embedderMessage)); |
| 168 } |
| 169 |
| 170 /** |
| 171 * @param {string|!Object} messageOrObject |
| 172 */ |
| 173 DevToolsAPI.dispatchMessage = function(messageOrObject) |
| 174 { |
| 175 var messageObject = (typeof messageOrObject === "string" ? JSON.parse(messag
eOrObject) : messageOrObject); |
| 176 if (InspectorTest._dumpInspectorProtocolMessages) |
| 177 testRunner.logToStderr("backend: " + JSON.stringify(messageObject)); |
| 178 var messageId = messageObject["id"]; |
| 179 try { |
| 180 if (typeof messageId === "number") { |
| 181 var handler = InspectorTest._dispatchTable[messageId]; |
| 182 if (handler && typeof handler === "function") |
| 183 handler(messageObject); |
| 184 } else { |
| 185 var eventName = messageObject["method"]; |
| 186 var eventHandler = InspectorTest.eventHandler[eventName]; |
| 187 if (eventHandler) |
| 188 eventHandler(messageObject); |
| 189 } |
| 190 } catch(e) { |
| 191 InspectorTest.log("Exception when dispatching message: " + e + "\n" + e.
stack + "\n message = " + JSON.stringify(messageObject, null, 2)); |
| 192 InspectorTest.completeTest(); |
| 193 } |
| 194 } |
| 195 |
| 196 /** |
| 197 * @param {number} callId |
| 198 * @param {string} script |
| 199 */ |
| 200 DevToolsAPI.evaluateForTestInFrontend = function(callId, script) |
| 201 { |
| 202 try { |
| 203 eval(script); |
| 204 } catch (e) { |
| 205 InspectorTest.log("FAIL: exception in evaluateForTestInFrontend: " + e); |
| 206 InspectorTest.completeTest(); |
| 207 } |
| 208 } |
| 209 |
| 210 /** |
| 211 * Logs message to document. |
| 212 * @param {string} message |
| 213 */ |
| 214 InspectorTest.log = function(message) |
| 215 { |
| 216 this.sendCommand("Runtime.evaluate", { "expression": "log(" + JSON.stringify
(message) + ")" } ); |
| 217 } |
| 218 |
| 219 /** |
| 220 * Formats and logs object to document. |
| 221 * @param {Object} object |
| 222 * @param {string=} title |
| 223 * @param {Array<string>=} unstableKeys |
| 224 */ |
| 225 InspectorTest.logObject = function(object, title, unstableKeys) |
| 226 { |
| 227 var lines = []; |
| 228 |
| 229 function dumpValue(value, prefix, prefixWithName) |
| 230 { |
| 231 if (typeof value === "object" && value !== null) { |
| 232 if (value instanceof Array) |
| 233 dumpItems(value, prefix, prefixWithName); |
| 234 else |
| 235 dumpProperties(value, prefix, prefixWithName); |
| 236 } else { |
| 237 lines.push(prefixWithName + String(value).replace(/\n/g, " ")); |
| 238 } |
| 239 } |
| 240 |
| 241 function dumpProperties(object, prefix, firstLinePrefix) |
| 242 { |
| 243 prefix = prefix || ""; |
| 244 firstLinePrefix = firstLinePrefix || prefix; |
| 245 lines.push(firstLinePrefix + "{"); |
| 246 |
| 247 var propertyNames = Object.keys(object); |
| 248 propertyNames.sort(); |
| 249 for (var i = 0; i < propertyNames.length; ++i) { |
| 250 var name = propertyNames[i]; |
| 251 if (!object.hasOwnProperty(name)) |
| 252 continue; |
| 253 var prefixWithName = " " + prefix + name + " : "; |
| 254 var value = object[name]; |
| 255 if (unstableKeys && unstableKeys.indexOf(name) !== -1) |
| 256 value = "<" + typeof(value) + ">"; |
| 257 dumpValue(value, " " + prefix, prefixWithName); |
| 258 } |
| 259 lines.push(prefix + "}"); |
| 260 } |
| 261 |
| 262 function dumpItems(object, prefix, firstLinePrefix) |
| 263 { |
| 264 prefix = prefix || ""; |
| 265 firstLinePrefix = firstLinePrefix || prefix; |
| 266 lines.push(firstLinePrefix + "["); |
| 267 for (var i = 0; i < object.length; ++i) |
| 268 dumpValue(object[i], " " + prefix, " " + prefix + "[" + i + "]
: "); |
| 269 lines.push(prefix + "]"); |
| 270 } |
| 271 |
| 272 dumpValue(object, "", title); |
| 273 InspectorTest.log(lines.join("\n")); |
| 274 } |
| 275 |
| 276 /** |
| 277 * Logs message directly to process stdout via alert function (hopefully followed
by flush call). |
| 278 * This message should survive process crash or kill by timeout. |
| 279 * @param {string} message |
| 280 */ |
| 281 InspectorTest.debugLog = function(message) |
| 282 { |
| 283 this.sendCommand("Runtime.evaluate", { "expression": "debugLog(" + JSON.stri
ngify(message) + ")" } ); |
| 284 } |
| 285 |
| 286 InspectorTest.completeTest = function() |
| 287 { |
| 288 this.sendCommand("Runtime.evaluate", { "expression": "closeTest();"} ); |
| 289 } |
| 290 |
| 291 /** |
| 292 * Evaluates string in page. |
| 293 * @param {string} message |
| 294 * @param {!function} callback |
| 295 */ |
| 296 InspectorTest.evaluateInPage = function(string, callback) |
| 297 { |
| 298 this.sendCommand("Runtime.evaluate", { "expression": string }, function(mess
age) { |
| 299 if (message.error) |
| 300 InspectorTest.log("Error while executing '" + string + "': " + messa
ge.error.message); |
| 301 else if (callback) |
| 302 callback(message.result.result.value); |
| 303 }); |
| 304 }; |
| 305 |
| 306 /** |
| 307 * Evaluates expression in page. |
| 308 * @param {string} expression |
| 309 * @return {!Promise<?>} |
| 310 */ |
| 311 InspectorTest.evaluateInPagePromise = function(expression) |
| 312 { |
| 313 return InspectorTest.sendCommandPromise("Runtime.evaluate", { "expression":
expression, awaitPromise: false, returnByValue: true }); |
| 314 }; |
| 315 |
| 316 InspectorTest.evaluateInPageAsync = function(expression) |
| 317 { |
| 318 return InspectorTest.sendCommandPromise("Runtime.evaluate", { "expression":
expression, awaitPromise: true, returnByValue: true }).then((message) => message
.result.result.value); |
| 319 } |
| 320 |
| 321 InspectorTest.completeTestIfError = function(messageObject) |
| 322 { |
| 323 if (messageObject.error) { |
| 324 InspectorTest.log(messageObject.error.message); |
| 325 InspectorTest.completeTest(); |
| 326 return true; |
| 327 } |
| 328 return false; |
| 329 } |
| 330 |
| 331 InspectorTest.checkExpectation = function(fail, name, messageObject) |
| 332 { |
| 333 if (fail === !!messageObject.error) { |
| 334 InspectorTest.log("PASS: " + name); |
| 335 return true; |
| 336 } |
| 337 |
| 338 InspectorTest.log("FAIL: " + name + ": " + JSON.stringify(messageObject)); |
| 339 InspectorTest.completeTest(); |
| 340 return false; |
| 341 } |
| 342 InspectorTest.expectedSuccess = InspectorTest.checkExpectation.bind(null, false)
; |
| 343 InspectorTest.expectedError = InspectorTest.checkExpectation.bind(null, true); |
| 344 |
| 345 /** |
| 346 * @param {string} scriptName |
| 347 */ |
| 348 InspectorTest.importScript = function(scriptName) |
| 349 { |
| 350 var xhr = new XMLHttpRequest(); |
| 351 xhr.open("GET", scriptName, false); |
| 352 xhr.send(null); |
| 353 window.eval(xhr.responseText + "\n//# sourceURL=" + scriptName); |
| 354 } |
| 355 |
| 356 InspectorTest.safeWrap = function(func, onexception) |
| 357 { |
| 358 function result() |
| 359 { |
| 360 if (!func) |
| 361 return; |
| 362 var wrapThis = this; |
| 363 try { |
| 364 return func.apply(wrapThis, arguments); |
| 365 } catch(e) { |
| 366 InspectorTest.log("Exception while running: " + func + "\n" + (e.sta
ck || e)); |
| 367 if (onexception) |
| 368 InspectorTest.safeWrap(onexception)(); |
| 369 else |
| 370 InspectorTest.completeTest(); |
| 371 } |
| 372 } |
| 373 return result; |
| 374 } |
| 375 |
| 376 InspectorTest.navigate = function(url, callback) |
| 377 { |
| 378 InspectorTest._pageLoadedCallback = InspectorTest.safeWrap(callback); |
| 379 InspectorTest.evaluateInPage("navigateProtocolTest('" + url + "')"); |
| 380 } |
| 381 |
| 382 InspectorTest.pageReloaded = function() |
| 383 { |
| 384 InspectorTest.log("Page reloaded."); |
| 385 var callback = InspectorTest._pageLoadedCallback; |
| 386 delete InspectorTest._pageLoadedCallback; |
| 387 if (callback) |
| 388 callback(); |
| 389 } |
| 390 |
| 391 InspectorTest.reloadProtocolTest = function(ignoreCache, callback) |
| 392 { |
| 393 InspectorTest._pageLoadedCallback = afterReload; |
| 394 // This will ensure we maintain logs after navigate. |
| 395 |
| 396 getLogs(getOldLogsCallback); |
| 397 |
| 398 function getLogs(getLogsCallback) |
| 399 { |
| 400 InspectorTest.evaluateInPage("outputElement.innerHTML", data => getLogsC
allback(data.split("<br>"))); |
| 401 } |
| 402 |
| 403 function clearLogs(clearLogsCallback) |
| 404 { |
| 405 InspectorTest.evaluateInPage("outputElement.textContent = \"\"", clearLo
gsCallback); |
| 406 } |
| 407 |
| 408 var oldLogs; |
| 409 |
| 410 function getOldLogsCallback(data) |
| 411 { |
| 412 oldLogs = data; |
| 413 prepareForReload(); |
| 414 } |
| 415 |
| 416 function prepareForReload() |
| 417 { |
| 418 InspectorTest.evaluateInPage("prepareForReload()", reload); |
| 419 } |
| 420 |
| 421 function reload() |
| 422 { |
| 423 InspectorTest.sendCommand("Page.reload", { "ignoreCache": ignoreCache })
; |
| 424 } |
| 425 |
| 426 function afterReload() |
| 427 { |
| 428 var currentLogs; |
| 429 getLogs(data => { |
| 430 currentLogs = data; |
| 431 clearLogs(addLogsBack); |
| 432 }); |
| 433 |
| 434 function addLogsBack() |
| 435 { |
| 436 for (var log of oldLogs) |
| 437 InspectorTest.log(log); |
| 438 for (var log of currentLogs) |
| 439 InspectorTest.log(log); |
| 440 callback(); |
| 441 } |
| 442 } |
| 443 } |
| 444 |
| 445 window.addEventListener("load", InspectorTest.readyForTest.bind(InspectorTest),
false); |
| 446 |
| 447 </script> |
| 448 </head> |
| 449 </html> |
OLD | NEW |