Web Inspector: sometimes ReceiveResponse event is attached to wrong parent.
[WebKit-https.git] / LayoutTests / http / tests / inspector / inspector-test.js
1 var initialize_InspectorTest = function() {
2
3 var results = [];
4 var resultsSynchronized = false;
5
6 function consoleOutputHook(messageType)
7 {
8     InspectorTest.addResult(messageType + ": " + Array.prototype.slice.call(arguments, 1));
9 }
10
11 console.log = consoleOutputHook.bind(InspectorTest, "log");
12 console.error = consoleOutputHook.bind(InspectorTest, "error");
13 console.info = consoleOutputHook.bind(InspectorTest, "info");
14
15 InspectorTest.completeTest = function()
16 {
17     function testDispatchQueueIsEmpty() {
18         if (!WebInspector.dispatchQueueIsEmpty()) {
19             // Wait for unprocessed messages.
20             setTimeout(testDispatchQueueIsEmpty, 10);
21             return;
22         }
23         RuntimeAgent.evaluate("didEvaluateForTestInFrontend(" + InspectorTest.completeTestCallId + ", \"\")", "test");
24     }
25     testDispatchQueueIsEmpty();
26 }
27
28 InspectorTest.evaluateInConsole = function(code, callback)
29 {
30     callback = InspectorTest.safeWrap(callback);
31
32     WebInspector.console.visible = true;
33     WebInspector.console.prompt.text = code;
34     var event = document.createEvent("KeyboardEvent");
35     event.initKeyboardEvent("keydown", true, true, null, "Enter", "");
36     WebInspector.console.promptElement.dispatchEvent(event);
37     InspectorTest.addSniffer(WebInspector.ConsoleView.prototype, "addMessage",
38         function(commandResult) {
39             callback(commandResult.toMessageElement().textContent);
40         });
41 }
42
43 InspectorTest.evaluateInConsoleAndDump = function(code, callback)
44 {
45     callback = InspectorTest.safeWrap(callback);
46
47     function mycallback(text)
48     {
49         InspectorTest.addResult(code + " = " + text);
50         callback(text);
51     }
52     InspectorTest.evaluateInConsole(code, mycallback);
53 }
54
55 InspectorTest.evaluateInPage = function(code, callback)
56 {
57     callback = InspectorTest.safeWrap(callback);
58
59     function mycallback(error, result, wasThrown)
60     {
61         if (!error)
62             callback(WebInspector.RemoteObject.fromPayload(result), wasThrown);
63     }
64     RuntimeAgent.evaluate(code, "console", false, mycallback);
65 }
66
67 InspectorTest.evaluateInPageWithTimeout = function(code)
68 {
69     InspectorTest.evaluateInPage("setTimeout(unescape('" + escape(code) + "'))");
70 }
71
72 InspectorTest.showResource = function(resourceURL, callback)
73 {
74     callback = InspectorTest.safeWrap(callback);
75     for (var url in WebInspector.resourceTreeModel._resourcesByURL) {
76         if (url.indexOf(resourceURL) !== -1) {
77             var resource = WebInspector.resourceTreeModel._resourcesByURL[url];
78             WebInspector.panels.resources.showResource(resource, 1);
79             var sourceFrame = WebInspector.panels.resources._resourceViewForResource(resource);
80             if (sourceFrame.loaded)
81                 callback(sourceFrame);
82             else
83                 sourceFrame.addEventListener(WebInspector.SourceFrame.Events.Loaded, callback.bind(null, sourceFrame));
84             return;
85         }
86     }
87     InspectorTest.addSniffer(WebInspector.resourceTreeModel, "_bindResourceURL", InspectorTest.showResource.bind(InspectorTest, url, callback));
88 };
89
90 InspectorTest.addResult = function(text)
91 {
92     results.push(text);
93     if (resultsSynchronized)
94         addResultToPage(text);
95     else {
96         clearResults();
97         for (var i = 0; i < results.length; ++i)
98             addResultToPage(results[i]);
99         resultsSynchronized = true;
100     }
101
102     function clearResults()
103     {
104         InspectorTest.evaluateInPage("clearOutput()");
105     }
106
107     function addResultToPage(text)
108     {
109         InspectorTest.evaluateInPage("output(unescape('" + escape(text) + "'))");
110     }
111 }
112
113 InspectorTest.addResults = function(textArray)
114 {
115     if (!textArray)
116         return;
117     for (var i = 0, size = textArray.length; i < size; ++i)
118         InspectorTest.addResult(textArray[i]);
119 }
120
121 function onError(event)
122 {
123     window.removeEventListener("error", onError);
124     InspectorTest.addResult("Uncaught exception in inspector front-end: " + event.message + " [" + event.filename + ":" + event.lineno + "]");
125     InspectorTest.completeTest();
126 }
127
128 window.addEventListener("error", onError);
129
130 InspectorTest.addObject = function(object, nondeterministicProps, prefix, firstLinePrefix)
131 {
132     prefix = prefix || "";
133     firstLinePrefix = firstLinePrefix || prefix;
134     InspectorTest.addResult(firstLinePrefix + "{");
135     for (var prop in object) {
136         if (typeof object.hasOwnProperty === "function" && !object.hasOwnProperty(prop))
137             continue;
138         var prefixWithName = "    " + prefix + prop + " : ";
139         var propValue = object[prop];
140         if (nondeterministicProps && prop in nondeterministicProps)
141             InspectorTest.addResult(prefixWithName + "<" + typeof propValue + ">");
142         else
143             InspectorTest.dump(propValue, nondeterministicProps, "    " + prefix, prefixWithName);
144     }
145     InspectorTest.addResult(prefix + "}");
146 }
147
148 InspectorTest.addArray = function(array, nondeterministicProps, prefix, firstLinePrefix)
149 {
150     prefix = prefix || "";
151     firstLinePrefix = firstLinePrefix || prefix;
152     InspectorTest.addResult(firstLinePrefix + "[");
153     for (var i = 0; i < array.length; ++i)
154         InspectorTest.dump(array[i], nondeterministicProps, prefix + "    ");
155     InspectorTest.addResult(prefix + "]");
156 }
157
158 InspectorTest.dump = function(value, nondeterministicProps, prefix, prefixWithName)
159 {
160     prefixWithName = prefixWithName || prefix;
161     if (prefixWithName && prefixWithName.length > 80) {
162         InspectorTest.addResult(prefixWithName + "was skipped due to prefix length limit");
163         return;
164     }
165     if (value === null)
166         InspectorTest.addResult(prefixWithName + "null");
167     else if (value instanceof Array)
168         InspectorTest.addArray(value, nondeterministicProps, prefix, prefixWithName);
169     else if (typeof value === "object")
170         InspectorTest.addObject(value, nondeterministicProps, prefix, prefixWithName);
171     else if (typeof value === "string")
172         InspectorTest.addResult(prefixWithName + "\"" + value + "\"");
173     else
174         InspectorTest.addResult(prefixWithName + value);
175 }
176
177 InspectorTest.assertGreaterOrEqual = function(expected, actual, message)
178 {
179     if (actual < expected)
180         InspectorTest.addResult("FAILED: " + (message ? message + ": " : "") + actual + " < " + expected);
181 }
182
183 InspectorTest.navigate = function(url, callback)
184 {
185     InspectorTest._pageLoadedCallback = InspectorTest.safeWrap(callback);
186
187     if (WebInspector.panels.network)
188         WebInspector.panels.network._reset();
189     InspectorTest.evaluateInConsole("window.location = '" + url + "'");
190 }
191
192 InspectorTest.reloadPage = function(callback)
193 {
194     InspectorTest._pageLoadedCallback = InspectorTest.safeWrap(callback);
195
196     if (WebInspector.panels.network)
197         WebInspector.panels.network._reset();
198     PageAgent.reload(false);
199 }
200
201 InspectorTest.pageLoaded = function()
202 {
203     resultsSynchronized = false;
204     InspectorTest.addResult("Page reloaded.");
205     if (InspectorTest._pageLoadedCallback) {
206         var callback = InspectorTest._pageLoadedCallback;
207         delete InspectorTest._pageLoadedCallback;
208         callback();
209     }
210 }
211
212 InspectorTest.runWhenPageLoads = function(callback)
213 {
214     var oldCallback = InspectorTest._pageLoadedCallback;
215     function chainedCallback()
216     {
217         if (oldCallback)
218             oldCallback();
219         callback();
220     }
221     InspectorTest._pageLoadedCallback = InspectorTest.safeWrap(chainedCallback);
222 }
223
224 InspectorTest.runAfterPendingDispatches = function(callback)
225 {
226     callback = InspectorTest.safeWrap(callback);
227     InspectorBackend.runAfterPendingDispatches(callback);
228 }
229
230 InspectorTest.createKeyEvent = function(keyIdentifier, ctrlKey, altKey, shiftKey, metaKey)
231 {
232     var evt = document.createEvent("KeyboardEvent");
233     evt.initKeyboardEvent("keydown", true /* can bubble */, true /* can cancel */, null /* view */, keyIdentifier, "", ctrlKey, altKey, shiftKey, metaKey);
234     return evt;
235 }
236
237 InspectorTest.runTestSuite = function(testSuite)
238 {
239     var testSuiteTests = testSuite.slice();
240
241     function runner()
242     {
243         if (!testSuiteTests.length) {
244             InspectorTest.completeTest();
245             return;
246         }
247         var nextTest = testSuiteTests.shift();
248         InspectorTest.addResult("");
249         InspectorTest.addResult("Running: " + /function\s([^(]*)/.exec(nextTest)[1]);
250         InspectorTest.safeWrap(nextTest)(runner, runner);
251     }
252     runner();
253 }
254
255 InspectorTest.assertEquals = function(expected, found, message)
256 {
257     if (expected === found)
258         return;
259
260     var error;
261     if (message)
262         error = "Failure (" + message + "):";
263     else
264         error = "Failure:";
265     throw new Error(error + " expected <" + expected + "> found <" + found + ">");
266 }
267
268 InspectorTest.assertTrue = function(found, message)
269 {
270     InspectorTest.assertEquals(true, !!found, message);
271 }
272
273 InspectorTest.safeWrap = function(func, onexception)
274 {
275     function result()
276     {
277         if (!func)
278             return;
279         var wrapThis = this;
280         try {
281             return func.apply(wrapThis, arguments);
282         } catch(e) {
283             InspectorTest.addResult("Exception while running: " + func + "\n" + (e.stack || e));
284             if (onexception)
285                 InspectorTest.safeWrap(onexception)();
286             else
287                 InspectorTest.completeTest();
288         }
289     }
290     return result;
291 }
292
293 InspectorTest.addSniffer = function(receiver, methodName, override, opt_sticky)
294 {
295     override = InspectorTest.safeWrap(override);
296
297     var original = receiver[methodName];
298     if (typeof original !== "function")
299         throw ("Cannot find method to override: " + methodName);
300
301     receiver[methodName] = function(var_args) {
302         try {
303             var result = original.apply(this, arguments);
304         } finally {
305             if (!opt_sticky)
306                 receiver[methodName] = original;
307         }
308         // In case of exception the override won't be called.
309         try {
310             override.apply(this, arguments);
311         } catch (e) {
312             throw ("Exception in overriden method '" + methodName + "': " + e);
313         }
314         return result;
315     };
316 }
317
318 InspectorTest.override = function(receiver, methodName, override, opt_sticky)
319 {
320     override = InspectorTest.safeWrap(override);
321
322     var original = receiver[methodName];
323     if (typeof original !== "function")
324         throw ("Cannot find method to override: " + methodName);
325
326     receiver[methodName] = function(var_args) {
327         try {
328             try {
329                 var result = override.apply(this, arguments);
330             } catch (e) {
331                 throw ("Exception in overriden method '" + methodName + "': " + e);
332             }
333         } finally {
334             if (!opt_sticky)
335                 receiver[methodName] = original;
336         }
337         return result;
338     };
339
340     return original;
341 }
342
343 InspectorTest.textContentWithLineBreaks = function(node)
344 {
345     var buffer = "";
346     var currentNode = node;
347     while (currentNode = currentNode.traverseNextNode(node)) {
348         if (currentNode.nodeType === Node.TEXT_NODE)
349             buffer += currentNode.nodeValue;
350         else if (currentNode.nodeName === "LI")
351             buffer += "\n    ";
352         else if (currentNode.classList.contains("console-message"))
353             buffer += "\n\n";
354     }
355     return buffer;
356 }
357
358 };
359
360 var runTestCallId = 0;
361 var completeTestCallId = 1;
362 var frontendReopeningCount = 0;
363
364 function reopenFrontend()
365 {
366     closeFrontend(openFrontendAndIncrement);
367 }
368
369 function closeFrontend(callback)
370 {
371     // Do this asynchronously to allow InspectorBackendDispatcher to send response
372     // back to the frontend before it's destroyed.
373     setTimeout(function() {
374         layoutTestController.closeWebInspector();
375         callback();
376     }, 0);
377 }
378
379 function openFrontendAndIncrement()
380 {
381     frontendReopeningCount++;
382     layoutTestController.showWebInspector();
383     runTest();
384 }
385
386 function runAfterIframeIsLoaded()
387 {
388     if (window.layoutTestController)
389         layoutTestController.waitUntilDone();
390     function step()
391     {
392         if (!window.iframeLoaded)
393             setTimeout(step, 100);
394         else
395             runTest();
396     }
397     setTimeout(step, 100);
398 }
399
400 function runTest(enableWatchDogWhileDebugging)
401 {
402     if (!window.layoutTestController)
403         return;
404
405     layoutTestController.dumpAsText();
406     layoutTestController.waitUntilDone();
407
408     function runTestInFrontend(initializationFunctions, testFunction, completeTestCallId)
409     {
410         if (window.InspectorTest) {
411             InspectorTest.pageLoaded();
412             return;
413         }
414
415         InspectorTest = {};
416         InspectorTest.completeTestCallId = completeTestCallId;
417
418         for (var i = 0; i < initializationFunctions.length; ++i) {
419             try {
420                 initializationFunctions[i]();
421             } catch (e) {
422                 console.error("Exception in test initialization: " + e);
423                 InspectorTest.completeTest();
424             }
425         }
426
427         WebInspector.showPanel("audits");
428         try {
429             testFunction();
430         } catch (e) {
431             console.error("Exception during test execution: " + e);
432             InspectorTest.completeTest();
433         }
434     }
435
436     var initializationFunctions = [];
437     for (var name in window) {
438         if (name.indexOf("initialize_") === 0 && typeof window[name] === "function")
439             initializationFunctions.push(window[name].toString());
440     }
441     var parameters = ["[" + initializationFunctions + "]", test, completeTestCallId];
442     var toEvaluate = "(" + runTestInFrontend + ")(" + parameters.join(", ") + ");";
443     layoutTestController.evaluateInWebInspector(runTestCallId, toEvaluate);
444
445     if (enableWatchDogWhileDebugging) {
446         function watchDog()
447         {
448             console.log("Internal watchdog triggered at 20 seconds. Test timed out.");
449             closeInspectorAndNotifyDone();
450         }
451         window._watchDogTimer = setTimeout(watchDog, 20000);
452     }
453 }
454
455 function didEvaluateForTestInFrontend(callId)
456 {
457     if (callId !== completeTestCallId)
458         return;
459     delete window.completeTestCallId;
460     // Close inspector asynchrously to allow caller of this
461     // function send response before backend dispatcher and frontend are destroyed.
462     setTimeout(closeInspectorAndNotifyDone, 0);
463 }
464
465 function closeInspectorAndNotifyDone()
466 {
467     if (window._watchDogTimer)
468         clearTimeout(window._watchDogTimer);
469
470     layoutTestController.closeWebInspector();
471     setTimeout(function() {
472         layoutTestController.notifyDone();
473     }, 0);
474 }
475
476 var outputElement;
477
478 function output(text)
479 {
480     if (!outputElement) {
481         var intermediate = document.createElement("div");
482         document.body.appendChild(intermediate);
483
484         var intermediate2 = document.createElement("div");
485         intermediate.appendChild(intermediate2);
486
487         outputElement = document.createElement("div");
488         outputElement.className = "output";
489         outputElement.style.whiteSpace = "pre";
490         intermediate2.appendChild(outputElement);
491     }
492     outputElement.appendChild(document.createTextNode(text));
493     outputElement.appendChild(document.createElement("br"));
494 }
495
496 function clearOutput()
497 {
498     if (outputElement) {
499         outputElement.parentNode.removeChild(outputElement);
500         outputElement = null;
501     }
502 }