if (window.domAutomationController) {
var ___interactiveUiTestsMode = true;
TestSuite = function()
{
this.controlTaken_ = false;
this.timerId_ = -1;
};
TestSuite.prototype.fail = function(message)
{
if (this.controlTaken_)
this.reportFailure_(message);
else
throw message;
};
TestSuite.prototype.assertEquals = function(expected, actual, opt_message)
{
if (expected !== actual) {
var message = "Expected: '" + expected + "', but was '" + actual + "'";
if (opt_message)
message = opt_message + "(" + message + ")";
this.fail(message);
}
};
TestSuite.prototype.assertTrue = function(value, opt_message)
{
this.assertEquals(true, !!value, opt_message);
};
TestSuite.prototype.assertContains = function(string, substring)
{
if (string.indexOf(substring) === -1)
this.fail("Expected to: '" + string + "' to contain '" + substring + "'");
};
TestSuite.prototype.takeControl = function()
{
this.controlTaken_ = true;
var self = this;
this.timerId_ = setTimeout(function() {
self.reportFailure_("Timeout exceeded: 20 sec");
}, 20000);
};
TestSuite.prototype.releaseControl = function()
{
if (this.timerId_ !== -1) {
clearTimeout(this.timerId_);
this.timerId_ = -1;
}
this.reportOk_();
};
TestSuite.prototype.reportOk_ = function()
{
window.domAutomationController.send("[OK]");
};
TestSuite.prototype.reportFailure_ = function(error)
{
if (this.timerId_ !== -1) {
clearTimeout(this.timerId_);
this.timerId_ = -1;
}
window.domAutomationController.send("[FAILED] " + error);
};
TestSuite.prototype.runTest = function(testName)
{
try {
this[testName]();
if (!this.controlTaken_)
this.reportOk_();
} catch (e) {
this.reportFailure_(e);
}
};
TestSuite.prototype.showPanel = function(panelName)
{
var toolbar = document.getElementById("toolbar");
var button = toolbar.getElementsByClassName(panelName)[0];
button.click();
this.assertEquals(WebInspector.panels[panelName], WebInspector.currentPanel);
};
TestSuite.prototype.addSniffer = function(receiver, methodName, override, opt_sticky)
{
var orig = receiver[methodName];
if (typeof orig !== "function")
this.fail("Cannot find method to override: " + methodName);
var test = this;
receiver[methodName] = function(var_args) {
try {
var result = orig.apply(this, arguments);
} finally {
if (!opt_sticky)
receiver[methodName] = orig;
}
try {
override.apply(this, arguments);
} catch (e) {
test.fail("Exception in overriden method '" + methodName + "': " + e);
}
return result;
};
};
TestSuite.prototype.testHostIsPresent = function()
{
this.assertTrue(typeof InspectorFrontendHost === "object" && !InspectorFrontendHost.isStub);
};
TestSuite.prototype.testElementsTreeRoot = function()
{
var doc = WebInspector.domAgent.document;
this.assertEquals("HTML", doc.documentElement.nodeName);
this.assertTrue(doc.documentElement.hasChildNodes());
};
TestSuite.prototype.testMainResource = function()
{
var tokens = [];
var resources = WebInspector.resources;
for (var id in resources)
tokens.push(resources[id].lastPathComponent);
this.assertEquals("simple_page.html", tokens.join(","));
};
TestSuite.prototype.testEnableResourcesTab = function()
{
this.showPanel("resources");
var test = this;
this.addSniffer(WebInspector, "updateResource",
function(identifier, payload) {
test.assertEquals("simple_page.html", payload.lastPathComponent);
WebInspector.panels.resources.refresh();
WebInspector.panels.resources.revealAndSelectItem(WebInspector.resources[identifier]);
test.releaseControl();
});
WebInspector.panels.resources._enableResourceTracking();
this.takeControl();
};
TestSuite.prototype.testResourceContentLength = function()
{
this.showPanel("resources");
var test = this;
var png = false;
var html = false;
this.addSniffer(WebInspector, "updateResource",
function(identifier, payload) {
if (!payload.didLengthChange)
return;
var resource = WebInspector.resources[identifier];
if (!resource || !resource.url)
return;
if (resource.url.search("image.html") !== -1) {
var expectedLength = 87;
test.assertTrue(
resource.resourceSize <= expectedLength,
"image.html content length is greater thatn expected.");
if (expectedLength === resource.resourceSize)
html = true;
} else if (resource.url.search("image.png") !== -1) {
var expectedLength = 257796;
test.assertTrue(
resource.resourceSize <= expectedLength,
"image.png content length is greater than expected.");
if (expectedLength === resource.resourceSize)
png = true;
}
if (html && png) {
setTimeout(function() {
test.releaseControl();
}, 1000);
}
}, true);
WebInspector.panels.resources._enableResourceTracking();
test.evaluateInConsole_(
"window.location.reload(true);",
function(resultText) {
test.assertEquals("undefined", resultText, "Unexpected result of reload().");
});
this.takeControl();
};
TestSuite.prototype.testResourceHeaders = function()
{
this.showPanel("resources");
var test = this;
var responseOk = false;
var timingOk = false;
this.addSniffer(WebInspector, "updateResource",
function(identifier, payload) {
var resource = this.resources[identifier];
if (!resource || resource.mainResource) {
return;
}
var requestHeaders = JSON.stringify(resource.requestHeaders);
test.assertContains(requestHeaders, "Accept");
if (payload.didResponseChange) {
var responseHeaders = JSON.stringify(resource.responseHeaders);
test.assertContains(responseHeaders, "Content-type");
test.assertContains(responseHeaders, "Content-Length");
test.assertTrue(typeof resource.responseReceivedTime !== "undefined");
responseOk = true;
}
if (payload.didTimingChange) {
test.assertTrue(typeof resource.startTime !== "undefined");
timingOk = true;
}
if (payload.didCompletionChange) {
test.assertTrue(responseOk);
test.assertTrue(timingOk);
test.assertTrue(typeof resource.endTime !== "undefined");
test.releaseControl();
}
}, true);
WebInspector.panels.resources._enableResourceTracking();
this.takeControl();
};
TestSuite.prototype.testCachedResourceMimeType = function()
{
this.showPanel("resources");
var test = this;
var hasReloaded = false;
this.addSniffer(WebInspector, "updateResource",
function(identifier, payload) {
var resource = this.resources[identifier];
if (!resource || resource.mainResource) {
return;
}
if (payload.didResponseChange) {
test.assertEquals("text/html", payload.mimeType);
if (!hasReloaded) {
hasReloaded = true;
test.evaluateInConsole_("window.location.reload(true);", function() {});
} else
test.releaseControl();
}
}, true);
WebInspector.panels.resources._enableResourceTracking();
this.takeControl();
};
TestSuite.prototype.testProfilerTab = function()
{
this.showPanel("profiles");
var panel = WebInspector.panels.profiles;
var test = this;
function findDisplayedNode() {
var node = panel.visibleView.profileDataGridTree.children[0];
if (!node) {
window.setTimeout(findDisplayedNode, 100);
return;
}
while (node) {
if (node.functionName.indexOf("fib") !== -1)
test.releaseControl();
node = node.traverseNextNode(true, null, true);
}
test.fail();
}
function findVisibleView() {
if (!panel.visibleView) {
setTimeout(findVisibleView, 0);
return;
}
setTimeout(findDisplayedNode, 0);
}
findVisibleView();
this.takeControl();
};
TestSuite.prototype.testShowScriptsTab = function()
{
this.showPanel("scripts");
var test = this;
this._waitUntilScriptsAreParsed(["debugger_test_page.html"],
function() {
test.releaseControl();
});
this.takeControl();
};
TestSuite.prototype.testScriptsTabIsPopulatedOnInspectedPageRefresh = function()
{
var test = this;
this.assertEquals(WebInspector.panels.elements, WebInspector.currentPanel, "Elements panel should be current one.");
this.addSniffer(devtools.DebuggerAgent.prototype, "reset", waitUntilScriptIsParsed);
test.evaluateInConsole_(
"window.location.reload(true);",
function(resultText) {
test.assertEquals("undefined", resultText, "Unexpected result of reload().");
});
function waitUntilScriptIsParsed() {
var parsed = devtools.tools.getDebuggerAgent().parsedScripts_;
for (var id in parsed) {
var url = parsed[id].getUrl();
if (url && url.search("debugger_test_page.html") !== -1) {
checkScriptsPanel();
return;
}
}
test.addSniffer(devtools.DebuggerAgent.prototype, "addScriptInfo_", waitUntilScriptIsParsed);
}
function checkScriptsPanel() {
test.showPanel("scripts");
test.assertTrue(test._scriptsAreParsed(["debugger_test_page.html"]), "Inspected script not found in the scripts list");
test.releaseControl();
}
this.takeControl();
};
TestSuite.prototype.testContentScriptIsPresent = function()
{
this.showPanel("scripts");
var test = this;
test._waitUntilScriptsAreParsed(
["page_with_content_script.html", "simple_content_script.js"],
function() {
test.releaseControl();
});
this.takeControl();
};
TestSuite.prototype.testNoScriptDuplicatesOnPanelSwitch = function()
{
var test = this;
var expectedScriptsCount = 2;
var parsedScripts = [];
this.showPanel("scripts");
function switchToElementsTab() {
test.showPanel("elements");
setTimeout(switchToScriptsTab, 0);
}
function switchToScriptsTab() {
test.showPanel("scripts");
setTimeout(checkScriptsPanel, 0);
}
function checkScriptsPanel() {
test.assertTrue(!!WebInspector.panels.scripts.visibleView, "No visible script view.");
test.assertTrue(test._scriptsAreParsed(["debugger_test_page.html"]), "Some scripts are missing.");
checkNoDuplicates();
test.releaseControl();
}
function checkNoDuplicates() {
var scriptSelect = document.getElementById("scripts-files");
var options = scriptSelect.options;
for (var i = 0; i < options.length; i++) {
var scriptName = options[i].text;
for (var j = i + 1; j < options.length; j++)
test.assertTrue(scriptName !== options[j].text, "Found script duplicates: " + test.optionsToString_(options));
}
}
test._waitUntilScriptsAreParsed(
["debugger_test_page.html"],
function() {
checkNoDuplicates();
setTimeout(switchToElementsTab, 0);
});
this.takeControl();
};
TestSuite.prototype.testSetBreakpoint = function()
{
var test = this;
this.showPanel("scripts");
var breakpointLine = 12;
this._waitUntilScriptsAreParsed(["debugger_test_page.html"],
function() {
test.showMainPageScriptSource_(
"debugger_test_page.html",
function(view, url) {
view._addBreakpoint(breakpointLine);
RemoteDebuggerAgent.processDebugCommands();
test.waitForSetBreakpointResponse_(url, breakpointLine,
function() {
test.releaseControl();
});
});
});
this.takeControl();
};
TestSuite.prototype.testPauseOnException = function()
{
this.showPanel("scripts");
var test = this;
if (WebInspector.ScriptsPanel.PauseOnExceptionsState) {
while (WebInspector.currentPanel._pauseOnExceptionButton.state !== WebInspector.ScriptsPanel.PauseOnExceptionsState.PauseOnUncaughtExceptions)
WebInspector.currentPanel._pauseOnExceptionButton.element.click();
} else {
if (!WebInspector.currentPanel._pauseOnExceptionButton.toggled)
WebInspector.currentPanel._pauseOnExceptionButton.element.click();
}
this._executeCodeWhenScriptsAreParsed("handleClick()", ["pause_on_exception.html"]);
this._waitForScriptPause(
{
functionsOnStack: ["throwAnException", "handleClick", "(anonymous function)"],
lineNumber: 6,
lineText: " return unknown_var;"
},
function() {
test.releaseControl();
});
this.takeControl();
};
TestSuite.prototype.testPauseWhenLoadingDevTools = function()
{
this.showPanel("scripts");
var test = this;
var expectations = {
functionsOnStack: ["callDebugger"],
lineNumber: 8,
lineText: " debugger;"
};
if (WebInspector.currentPanel.paused) {
var callFrame = WebInspector.currentPanel.sidebarPanes.callstack.selectedCallFrame;
this.assertEquals(expectations.functionsOnStack[0], callFrame.functionName);
var callbackInvoked = false;
this._checkSourceFrameWhenLoaded(expectations, function() {
callbackInvoked = true;
if (test.controlTaken_)
test.releaseControl();
});
if (!callbackInvoked) {
test.takeControl();
}
return;
}
this._waitForScriptPause(
{
functionsOnStack: ["callDebugger"],
lineNumber: 8,
lineText: " debugger;"
},
function() {
test.releaseControl();
});
this.takeControl();
};
TestSuite.prototype.testPauseWhenScriptIsRunning = function()
{
this.showPanel("scripts");
var test = this;
test.evaluateInConsole_(
'setTimeout("handleClick()" , 0)',
function(resultText) {
test.assertTrue(!isNaN(resultText), "Failed to get timer id: " + resultText);
testScriptPauseAfterDelay();
});
function testScriptPauseAfterDelay() {
setTimeout(testScriptPause, 300);
}
function testScriptPause() {
WebInspector.panels.scripts.pauseButton.click();
test._waitForScriptPause(
{
functionsOnStack: ["handleClick", "(anonymous function)"],
lineNumber: 5,
lineText: " while(true) {"
},
function() {
test.releaseControl();
});
}
this.takeControl();
};
TestSuite.prototype.optionsToString_ = function(options)
{
var names = [];
for (var i = 0; i < options.length; i++)
names.push('"' + options[i].text + '"');
return names.join(",");
};
TestSuite.prototype.showMainPageScriptSource_ = function(scriptName, callback)
{
var test = this;
var scriptSelect = document.getElementById("scripts-files");
var options = scriptSelect.options;
test.assertTrue(options.length, "Scripts list is empty");
var scriptResource;
if (options[scriptSelect.selectedIndex].text === scriptName)
scriptResource = options[scriptSelect.selectedIndex].representedObject;
else {
var pageScriptIndex = -1;
for (var i = 0; i < options.length; i++) {
if (options[i].text === scriptName) {
pageScriptIndex = i;
break;
}
}
test.assertTrue(-1 !== pageScriptIndex, "Script with url " + scriptName + " not found among " + test.optionsToString_(options));
scriptResource = options[pageScriptIndex].representedObject;
WebInspector.currentPanel._showScriptOrResource(scriptResource);
test.assertEquals(pageScriptIndex, scriptSelect.selectedIndex, "Unexpected selected option index.");
}
test.assertTrue(scriptResource instanceof WebInspector.Resource,
"Unexpected resource class.");
test.assertTrue(!!scriptResource.url, "Resource URL is null.");
test.assertTrue(scriptResource.url.search(scriptName + "$") !== -1, "Main HTML resource should be selected.");
var scriptsPanel = WebInspector.panels.scripts;
var view = scriptsPanel.visibleView;
test.assertTrue(view instanceof WebInspector.SourceView);
if (!view.sourceFrame._loaded) {
test.addSniffer(view, "_sourceFrameSetupFinished", function(event) {
callback(view, scriptResource.url);
});
} else
callback(view, scriptResource.url);
};
TestSuite.prototype.evaluateInConsole_ = function(code, callback)
{
WebInspector.console.visible = true;
WebInspector.console.prompt.text = code;
WebInspector.console.promptElement.dispatchEvent( TestSuite.createKeyEvent("Enter"));
this.addSniffer(WebInspector.ConsoleView.prototype, "addMessage",
function(commandResult) {
callback(commandResult.toMessageElement().textContent);
});
};
TestSuite.prototype.waitForSetBreakpointResponse_ = function(scriptUrl, breakpointLine, callback)
{
var test = this;
test.addSniffer(
devtools.DebuggerAgent.prototype,
"handleSetBreakpointResponse_",
function(msg) {
var bps = this.urlToBreakpoints_[scriptUrl];
test.assertTrue(!!bps, "No breakpoints for line " + breakpointLine);
var line = devtools.DebuggerAgent.webkitToV8LineNumber_(breakpointLine);
test.assertTrue(!!bps[line].getV8Id(), "Breakpoint id was not assigned.");
callback();
});
};
TestSuite.prototype.testEvalOnCallFrame = function()
{
this.showPanel("scripts");
var breakpointLine = 16;
var test = this;
this.addSniffer(devtools.DebuggerAgent.prototype, "handleScriptsResponse_",
function(msg) {
test.showMainPageScriptSource_(
"debugger_test_page.html",
function(view, url) {
view._addBreakpoint(breakpointLine);
RemoteDebuggerAgent.processDebugCommands();
test.waitForSetBreakpointResponse_(url, breakpointLine, setBreakpointCallback);
});
});
function setBreakpointCallback() {
test.evaluateInConsole_(
'setTimeout("calculate(123)" , 0)',
function(resultText) {
test.assertTrue(!isNaN(resultText), "Failed to get timer id: " + resultText);
waitForBreakpointHit();
});
}
function waitForBreakpointHit() {
test.addSniffer(
devtools.DebuggerAgent.prototype,
"handleBacktraceResponse_",
function(msg) {
test.assertEquals(2, this.callFrames_.length, "Unexpected stack depth on the breakpoint. " + JSON.stringify(msg));
test.assertEquals("calculate", this.callFrames_[0].functionName, "Unexpected top frame function.");
test.evaluateInConsole_(
"e+1",
function(resultText) {
test.assertEquals("124", resultText, 'Unexpected "e+1" value.');
test.releaseControl();
});
});
}
this.takeControl();
};
TestSuite.prototype.testCompletionOnPause = function()
{
this.showPanel("scripts");
var test = this;
this._executeCodeWhenScriptsAreParsed("handleClick()", ["completion_on_pause.html"]);
this._waitForScriptPause(
{
functionsOnStack: ["innerFunction", "handleClick", "(anonymous function)"],
lineNumber: 9,
lineText: " debugger;"
},
showConsole);
function showConsole() {
test.addSniffer(WebInspector.console, "afterShow", testLocalsCompletion);
WebInspector.showConsole();
}
function testLocalsCompletion() {
checkCompletions("th", ["parameter1", "closureLocal", "p", "createClosureLocal"], testThisCompletion);
}
function testThisCompletion() {
checkCompletions("this.", ["field1", "field2", "m"], testFieldCompletion);
}
function testFieldCompletion() {
checkCompletions("this.field1.", ["id", "name"], function() { test.releaseControl(); });
}
function checkCompletions(expression, expectedProperties, callback) {
test.addSniffer(WebInspector.console, "_reportCompletions",
function(bestMatchOnly, completionsReadyCallback, dotNotation, bracketNotation, prefix, result, isException) {
test.assertTrue(!isException, "Exception while collecting completions");
for (var i = 0; i < expectedProperties.length; i++) {
var name = expectedProperties[i];
test.assertTrue(result[name], "Name " + name + " not found among the completions: " + JSON.stringify(result));
}
setTimeout(callback, 0);
});
WebInspector.console.prompt.text = expression;
WebInspector.console.prompt.autoCompleteSoon();
}
this.takeControl();
};
TestSuite.prototype.testAutoContinueOnSyntaxError = function()
{
this.showPanel("scripts");
var test = this;
function checkScriptsList() {
var scriptSelect = document.getElementById("scripts-files");
var options = scriptSelect.options;
for (var i = 0 ; i < options.length; i++) {
if (options[i].text.search("script_syntax_error.html") !== -1)
test.fail("Script with syntax error should not be in the list of parsed scripts.");
}
}
this.addSniffer(devtools.DebuggerAgent.prototype, "handleScriptsResponse_",
function(msg) {
checkScriptsList();
test.evaluateInConsole_(
"window.location.reload(true);",
function(resultText) {
test.assertEquals("undefined", resultText, "Unexpected result of reload().");
waitForExceptionEvent();
});
});
function waitForExceptionEvent() {
var exceptionCount = 0;
test.addSniffer(
devtools.DebuggerAgent.prototype,
"handleExceptionEvent_",
function(msg) {
exceptionCount++;
test.assertEquals(1, exceptionCount, "Too many exceptions.");
test.assertEquals(undefined, msg.getBody().script, "Unexpected exception: " + JSON.stringify(msg));
test.releaseControl();
});
test.addSniffer(
WebInspector,
"pausedScript",
function(callFrames) {
test.fail("Script execution should not pause on syntax error.");
});
}
this.takeControl();
};
TestSuite.prototype._checkExecutionLine = function(sourceFrame, lineNumber, lineContent)
{
this.assertEquals(lineNumber, sourceFrame.executionLine, "Unexpected execution line number.");
this.assertEquals(lineContent, sourceFrame._textModel.line(lineNumber - 1), "Unexpected execution line text.");
}
TestSuite.prototype._scriptsAreParsed = function(expected)
{
var scriptSelect = document.getElementById("scripts-files");
var options = scriptSelect.options;
var missing = expected.slice(0);
for (var i = 0 ; i < options.length; i++) {
for (var j = 0; j < missing.length; j++) {
if (options[i].text.search(missing[j]) !== -1) {
missing.splice(j, 1);
break;
}
}
}
return missing.length === 0;
};
TestSuite.prototype._waitForScriptPause = function(expectations, callback)
{
var test = this;
test.addSniffer(
WebInspector,
"pausedScript",
function(callFrames) {
var functionsOnStack = [];
for (var i = 0; i < callFrames.length; i++)
functionsOnStack.push(callFrames[i].functionName);
test.assertEquals(expectations.functionsOnStack.join(","), functionsOnStack.join(","), "Unexpected stack.");
test._checkSourceFrameWhenLoaded(expectations, callback);
});
};
TestSuite.prototype._checkSourceFrameWhenLoaded = function(expectations, callback)
{
var test = this;
var frame = WebInspector.currentPanel.visibleView.sourceFrame;
if (frame._loaded)
checkExecLine();
else {
setTimeout(function() {
test._checkSourceFrameWhenLoaded(expectations, callback);
}, 100);
}
function checkExecLine() {
test._checkExecutionLine(frame, expectations.lineNumber, expectations.lineText);
callback();
}
};
TestSuite.prototype._performSteps = function(actions)
{
var test = this;
var i = 0;
function doNextAction() {
if (i > 0)
actions[i++]();
if (i < actions.length - 1)
test._waitForScriptPause(actions[i++], doNextAction);
}
doNextAction();
};
TestSuite.prototype._executeCodeWhenScriptsAreParsed = function(code, expectedScripts)
{
var test = this;
function executeFunctionInInspectedPage() {
test.evaluateInConsole_(
'setTimeout("' + code + '" , 0)',
function(resultText) {
test.assertTrue(!isNaN(resultText), "Failed to get timer id: " + resultText);
});
}
test._waitUntilScriptsAreParsed(expectedScripts, executeFunctionInInspectedPage);
};
TestSuite.prototype._waitUntilScriptsAreParsed = function(expectedScripts, callback)
{
var test = this;
function waitForAllScripts() {
if (test._scriptsAreParsed(expectedScripts))
callback();
else
test.addSniffer(WebInspector, "parsedScriptSource", waitForAllScripts);
}
waitForAllScripts();
};
TestSuite.prototype._executeFunctionForStepTest = function()
{
this._executeCodeWhenScriptsAreParsed("a()", ["debugger_step.html", "debugger_step.js"]);
};
TestSuite.prototype.testStepOver = function()
{
this.showPanel("scripts");
var test = this;
this._executeFunctionForStepTest();
this._performSteps([
{
functionsOnStack: ["d","a","(anonymous function)"],
lineNumber: 3,
lineText: " debugger;"
},
function() {
document.getElementById("scripts-step-over").click();
},
{
functionsOnStack: ["d","a","(anonymous function)"],
lineNumber: 5,
lineText: " var y = fact(10);"
},
function() {
document.getElementById("scripts-step-over").click();
},
{
functionsOnStack: ["d","a","(anonymous function)"],
lineNumber: 6,
lineText: " return y;"
},
function() {
test.releaseControl();
}
]);
test.takeControl();
};
TestSuite.prototype.testStepOut = function()
{
this.showPanel("scripts");
var test = this;
this._executeFunctionForStepTest();
this._performSteps([
{
functionsOnStack: ["d","a","(anonymous function)"],
lineNumber: 3,
lineText: " debugger;"
},
function() {
document.getElementById("scripts-step-out").click();
},
{
functionsOnStack: ["a","(anonymous function)"],
lineNumber: 8,
lineText: " printResult(result);"
},
function() {
test.releaseControl();
}
]);
test.takeControl();
};
TestSuite.prototype.testStepIn = function()
{
this.showPanel("scripts");
var test = this;
this._executeFunctionForStepTest();
this._performSteps([
{
functionsOnStack: ["d","a","(anonymous function)"],
lineNumber: 3,
lineText: " debugger;"
},
function() {
document.getElementById("scripts-step-over").click();
},
{
functionsOnStack: ["d","a","(anonymous function)"],
lineNumber: 5,
lineText: " var y = fact(10);"
},
function() {
document.getElementById("scripts-step-into").click();
},
{
functionsOnStack: ["fact","d","a","(anonymous function)"],
lineNumber: 15,
lineText: " return r;"
},
function() {
test.releaseControl();
}
]);
test.takeControl();
};
TestSuite.prototype._evaluateXpath = function(xpath, resultType, opt_ancestor)
{
if (!opt_ancestor)
opt_ancestor = document.documentElement;
try {
return document.evaluate(xpath, opt_ancestor, null, resultType, null);
} catch(e) {
this.fail('Error in expression: "' + xpath + '".' + e);
}
};
TestSuite.prototype._findNode = function(xpath, opt_ancestor)
{
var result = this._evaluateXpath(xpath, XPathResult.FIRST_ORDERED_NODE_TYPE, opt_ancestor).singleNodeValue;
this.assertTrue(!!result, "Cannot find node on path: " + xpath);
return result;
};
TestSuite.prototype._findText = function(xpath, opt_ancestor)
{
var result = this._evaluateXpath(xpath, XPathResult.STRING_TYPE, opt_ancestor).stringValue;
this.assertTrue(!!result, "Cannot find text on path: " + xpath);
return result;
};
TestSuite.prototype._nodeIterator = function(xpath, opt_ancestor)
{
return this._evaluateXpath(xpath, XPathResult.ORDERED_NODE_ITERATOR_TYPE, opt_ancestor);
};
TestSuite.prototype._checkScopeSectionDiv = function(scopeSectionDiv, expectations)
{
var scopeTitle = this._findText('./div[@class="header"]/div[@class="title"]/text()', scopeSectionDiv);
this.assertEquals(expectations.title, scopeTitle, "Unexpected scope section title.");
if (!expectations.properties)
return;
this.assertTrue(scopeSectionDiv.hasStyleClass("expanded"), 'Section "' + scopeTitle + '" is collapsed.');
var propertyIt = this._nodeIterator("./ol/li", scopeSectionDiv);
var propertyLi;
var foundProps = [];
while (propertyLi = propertyIt.iterateNext()) {
var name = this._findText('./span[@class="name"]/text()', propertyLi);
var value = this._findText('./span[@class="value"]/text()', propertyLi);
this.assertTrue(!!name, 'Invalid variable name: "' + name + '"');
this.assertTrue(name in expectations.properties, "Unexpected property: " + name);
this.assertEquals(expectations.properties[name], value, 'Unexpected "' + name + '" property value.');
delete expectations.properties[name];
foundProps.push(name + " = " + value);
}
for (var p in expectations.properties)
this.fail('Property "' + p + '" was not found in scope "' + scopeTitle + '". Found properties: "' + foundProps.join(",") + '"');
};
TestSuite.prototype._expandScopeSections = function(filter, callback)
{
var sections = WebInspector.currentPanel.sidebarPanes.scopechain.sections;
var toBeUpdatedCount = 0;
function updateListener() {
--toBeUpdatedCount;
if (toBeUpdatedCount === 0) {
callback();
}
}
for (var i = 0; i < sections.length - 1; i++) {
var section = sections[i];
if (!filter(sections, i))
continue;
++toBeUpdatedCount;
var populated = section.populated;
this._hookGetPropertiesCallback(updateListener,
function() {
section.expand();
if (populated) {
section.update();
}
});
}
};
TestSuite.prototype.testExpandScope = function()
{
this.showPanel("scripts");
var test = this;
this._executeCodeWhenScriptsAreParsed("handleClick()", ["debugger_closure.html"]);
this._waitForScriptPause(
{
functionsOnStack: ["innerFunction", "handleClick", "(anonymous function)"],
lineNumber: 8,
lineText: " debugger;"
},
expandAllSectionsExceptGlobal);
function expandAllSectionsExceptGlobal() {
test._expandScopeSections(function(sections, i) {
return i < sections.length - 1;
},
examineScopes );
}
function examineScopes() {
var scopeVariablesSection = test._findNode('//div[@id="scripts-sidebar"]/div[div[@class="title"]/text()="Scope Variables"]');
var expectedScopes = [
{
title: "Local",
properties: {
x:"2009",
innerFunctionLocalVar:"2011",
"this": "global",
}
},
{
title: "Closure",
properties: {
n:"TextParam",
makeClosureLocalVar:"local.TextParam",
}
},
{
title: "Global",
},
];
var it = test._nodeIterator('./div[@class="body"]/div', scopeVariablesSection);
var scopeIndex = 0;
var scopeDiv;
while (scopeDiv = it.iterateNext()) {
test.assertTrue(scopeIndex < expectedScopes.length, "Too many scopes.");
test._checkScopeSectionDiv(scopeDiv, expectedScopes[scopeIndex]);
++scopeIndex;
}
test.assertEquals(expectedScopes.length, scopeIndex, "Unexpected number of scopes.");
test.releaseControl();
}
test.takeControl();
};
TestSuite.prototype._findChildProperty = function(parent, childName, objectPath)
{
var children = parent.children;
for (var i = 0; i < children.length; i++) {
var treeElement = children[i];
var property = treeElement.property;
if (property.name === childName)
return treeElement;
}
this.fail('Cannot find property "' + childName + '" in ' + objectPath);
};
TestSuite.prototype._hookGetPropertiesCallback = function(hook, code)
{
var accessor = InjectedScriptAccess.prototype;
var orig = accessor.getProperties;
accessor.getProperties = function(objectProxy, ignoreHasOwnProperty, abbreviate, callback) {
orig.call(this, objectProxy, ignoreHasOwnProperty, abbreviate,
function() {
callback.apply(this, arguments);
hook();
});
};
try {
code();
} finally {
accessor.getProperties = orig;
}
};
TestSuite.prototype.testDebugIntrinsicProperties = function()
{
this.showPanel("scripts");
var test = this;
this._executeCodeWhenScriptsAreParsed("handleClick()", ["debugger_intrinsic_properties.html"]);
this._waitForScriptPause(
{
functionsOnStack: ["callDebugger", "handleClick", "(anonymous function)"],
lineNumber: 29,
lineText: " debugger;"
},
expandLocalScope);
var localScopeSection = null;
function expandLocalScope() {
test._expandScopeSections(function(sections, i) {
if (i === 0) {
test.assertTrue(sections[i].object.isLocal, "Scope #0 is not Local.");
localScopeSection = sections[i];
return true;
}
return false;
},
examineLocalScope);
}
function examineLocalScope() {
var scopeExpectations = [
"a", "Object", [
"constructor", "function Child()", [
"constructor", "function Function()", null,
"name", "Child", null,
"prototype", "Object", [
"childProtoField", 21, null
]
],
"__proto__", "Object", [
"__proto__", "Object", [
"__proto__", "Object", [
"__proto__", "null", null,
"constructor", "function Object()", null,
],
"constructor", "function Parent()", [
"name", "Parent", null,
"prototype", "Object", [
"parentProtoField", 11, null,
]
],
"parentProtoField", 11, null,
],
"constructor", "function Child()", null,
"childProtoField", 21, null,
],
"parentField", 10, null,
"childField", 20, null,
]
];
checkProperty(localScopeSection.propertiesTreeOutline, "<Local Scope>", scopeExpectations);
}
var propQueue = [];
var index = 0;
var expectedFinalIndex = 8;
function expandAndCheckNextProperty() {
if (index === propQueue.length) {
test.assertEquals(expectedFinalIndex, index, "Unexpected number of expanded objects.");
test.releaseControl();
return;
}
var treeElement = propQueue[index].treeElement;
var path = propQueue[index].path;
var expectations = propQueue[index].expectations;
index++;
test._hookGetPropertiesCallback(function() {
checkProperty(treeElement, path, expectations);
},
function() {
treeElement.expand();
});
}
function checkProperty(treeElement, path, expectations) {
for (var i = 0; i < expectations.length; i += 3) {
var name = expectations[i];
var description = expectations[i+1];
var value = expectations[i+2];
var propertyPath = path + "." + name;
var propertyTreeElement = test._findChildProperty(treeElement, name, path);
test.assertTrue(propertyTreeElement, 'Property "' + propertyPath + '" not found.');
test.assertEquals(description, propertyTreeElement.property.value.description, 'Unexpected "' + propertyPath + '" description.');
if (value) {
propQueue.push({
treeElement: propertyTreeElement,
path: propertyPath,
expectations: value,
});
}
}
expandAndCheckNextProperty();
}
test.takeControl();
};
TestSuite.prototype.testPauseInEval = function()
{
this.showPanel("scripts");
var test = this;
var pauseButton = document.getElementById("scripts-pause");
pauseButton.click();
devtools.tools.evaluateJavaScript("fib(10)");
this.addSniffer(WebInspector, "pausedScript",
function() {
test.releaseControl();
});
test.takeControl();
};
TestSuite.createKeyEvent = function(keyIdentifier)
{
var evt = document.createEvent("KeyboardEvent");
evt.initKeyboardEvent("keydown", true , true , null , keyIdentifier, "");
return evt;
};
TestSuite.prototype.testConsoleEval = function()
{
var test = this;
this.evaluateInConsole_("123",
function(resultText) {
test.assertEquals("123", resultText);
test.releaseControl();
});
this.takeControl();
};
TestSuite.prototype.testConsoleLog = function()
{
WebInspector.console.visible = true;
var messages = WebInspector.console.messages;
var index = 0;
var test = this;
var assertNext = function(line, message, opt_class, opt_count, opt_substr) {
var elem = messages[index++].toMessageElement();
var clazz = elem.getAttribute("class");
var expectation = (opt_count || '') + 'console_test_page.html:' + line + message;
if (opt_substr)
test.assertContains(elem.textContent, expectation);
else
test.assertEquals(expectation, elem.textContent);
if (opt_class)
test.assertContains(clazz, "console-" + opt_class);
};
assertNext("5", "log", "log-level");
assertNext("7", "debug", "log-level");
assertNext("9", "info", "log-level");
assertNext("11", "warn", "warning-level");
assertNext("13", "error", "error-level");
assertNext("15", "Message format number 1, 2 and 3.5");
assertNext("17", "Message format for string");
assertNext("19", "Object Object");
assertNext("22", "repeated", "log-level", 5);
assertNext("26", "count: 1");
assertNext("26", "count: 2");
assertNext("29", "group", "group-title");
index++;
assertNext("33", "timer:", "log-level", "", true);
assertNext("35", "1 2 3", "log-level");
assertNext("37", "HTMLDocument", "log-level");
assertNext("39", "<html>", "log-level", "", true);
};
TestSuite.prototype.testEvalGlobal = function()
{
WebInspector.console.visible = true;
var inputs = ["foo", "foobar"];
var expectations = ["foo", "fooValue", "foobar", "ReferenceError: foobar is not defined"];
var initEval = function(input) {
WebInspector.console.prompt.text = input;
WebInspector.console.promptElement.dispatchEvent( TestSuite.createKeyEvent("Enter"));
};
var test = this;
var messagesCount = 0;
var inputIndex = 0;
this.addSniffer(WebInspector.ConsoleView.prototype, "addMessage",
function(commandResult) {
messagesCount++;
if (messagesCount === expectations.length) {
var messages = WebInspector.console.messages;
for (var i = 0; i < expectations; ++i) {
var elem = messages[i++].toMessageElement();
test.assertEquals(elem.textContent, expectations[i]);
}
test.releaseControl();
} else if (messagesCount % 2 === 0)
initEval(inputs[inputIndex++]);
}, true);
initEval(inputs[inputIndex++]);
this.takeControl();
};
TestSuite.prototype.testShowStoragePanel = function()
{
var test = this;
this.addSniffer(WebInspector.panels.storage, "addDOMStorage",
function(storage) {
var orig = storage.getEntries;
storage.getEntries = function(callback) {
orig.call(this, function(entries) {
callback(entries);
test.releaseControl();
});
};
try {
WebInspector.currentPanel.selectDOMStorage(storage.id);
storage.getEntries = orig;
} catch (e) {
test.fail("Exception in selectDOMStorage: " + e);
}
});
this.showPanel("storage");
this.evaluateInConsole_(
'setTimeout("localStorage.x = 10" , 0)',
function(resultText) {
test.assertTrue(!isNaN(resultText), "Failed to get timer id: " + resultText);
});
this.takeControl();
};
var uiTests = {};
uiTests.runAllTests = function()
{
for (var name in TestSuite.prototype) {
if (name.substring(0, 4) === "test" && typeof TestSuite.prototype[name] === "function")
uiTests.runTest(name);
}
};
uiTests.runTest = function(name)
{
new TestSuite().runTest(name);
};
}