mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-27 07:34:20 +00:00
Bug 828664 - Debugger is sad when inspecting an array of > 10k elements in a variables view, r=rcampbell
This commit is contained in:
parent
f99c7e4d2c
commit
3e1128f45d
@ -15,6 +15,17 @@ const NEW_SCRIPT_DISPLAY_DELAY = 200; // ms
|
||||
const FETCH_SOURCE_RESPONSE_DELAY = 50; // ms
|
||||
const FRAME_STEP_CLEAR_DELAY = 100; // ms
|
||||
const CALL_STACK_PAGE_SIZE = 25; // frames
|
||||
const VARIABLES_VIEW_NON_SORTABLE = [
|
||||
"Array",
|
||||
"Int8Array",
|
||||
"Uint8Array",
|
||||
"Int16Array",
|
||||
"Uint16Array",
|
||||
"Int32Array",
|
||||
"Uint32Array",
|
||||
"Float32Array",
|
||||
"Float64Array"
|
||||
];
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
@ -50,7 +61,6 @@ let DebuggerController = {
|
||||
return;
|
||||
}
|
||||
this._isInitialized = true;
|
||||
|
||||
window.removeEventListener("load", this._startupDebugger, true);
|
||||
|
||||
DebuggerView.initialize(function() {
|
||||
@ -671,7 +681,7 @@ StackFrames.prototype = {
|
||||
let label = this._getScopeLabel(environment);
|
||||
let scope = DebuggerView.Variables.addScope(label);
|
||||
|
||||
// Special additions to the innermost scope.
|
||||
// Handle additions to the innermost scope.
|
||||
if (environment == frame.environment) {
|
||||
this._insertScopeFrameReferences(scope, frame);
|
||||
this._fetchScopeVariables(scope, environment);
|
||||
@ -703,7 +713,7 @@ StackFrames.prototype = {
|
||||
let callback = this._fetchScopeVariables.bind(this, aScope, aEnv);
|
||||
|
||||
// It's a good idea to be prepared in case of an expansion.
|
||||
aScope.onmouseover = callback;
|
||||
aScope.addEventListener("mouseover", callback, false);
|
||||
// Make sure that variables are always available on expansion.
|
||||
aScope.onexpand = callback;
|
||||
},
|
||||
@ -727,7 +737,7 @@ StackFrames.prototype = {
|
||||
// Some variables are likely to contain a very large number of properties.
|
||||
// It's a good idea to be prepared in case of an expansion.
|
||||
if (aVar.name == "window" || aVar.name == "this") {
|
||||
aVar.onmouseover = callback;
|
||||
aVar.addEventListener("mouseover", callback, false);
|
||||
}
|
||||
// Make sure that properties are always available on expansion.
|
||||
aVar.onexpand = callback;
|
||||
@ -742,11 +752,11 @@ StackFrames.prototype = {
|
||||
* The grip of the evaluation results.
|
||||
*/
|
||||
_fetchWatchExpressions: function SF__fetchWatchExpressions(aScope, aExp) {
|
||||
// Retrieve the expressions only once.
|
||||
if (aScope.fetched) {
|
||||
// Fetch the expressions only once.
|
||||
if (aScope._fetched) {
|
||||
return;
|
||||
}
|
||||
aScope.fetched = true;
|
||||
aScope._fetched = true;
|
||||
|
||||
// Add nodes for every watch expression in scope.
|
||||
this.activeThread.pauseGrip(aExp).getPrototypeAndProperties(function(aResponse) {
|
||||
@ -776,11 +786,11 @@ StackFrames.prototype = {
|
||||
* The scope's environment.
|
||||
*/
|
||||
_fetchScopeVariables: function SF__fetchScopeVariables(aScope, aEnv) {
|
||||
// Retrieve the variables only once.
|
||||
if (aScope.fetched) {
|
||||
// Fetch the variables only once.
|
||||
if (aScope._fetched) {
|
||||
return;
|
||||
}
|
||||
aScope.fetched = true;
|
||||
aScope._fetched = true;
|
||||
|
||||
switch (aEnv.type) {
|
||||
case "with":
|
||||
@ -799,6 +809,10 @@ StackFrames.prototype = {
|
||||
// Add nodes for every argument and every other variable in scope.
|
||||
this._insertScopeArguments(aEnv.bindings.arguments, aScope);
|
||||
this._insertScopeVariables(aEnv.bindings.variables, aScope);
|
||||
|
||||
// No need to signal that variables have been fetched, since
|
||||
// the scope arguments and variables are already attached to the
|
||||
// environment bindings, so pausing the active thread is unnecessary.
|
||||
break;
|
||||
default:
|
||||
Cu.reportError("Unknown Debugger.Environment type: " + aEnv.type);
|
||||
@ -861,11 +875,11 @@ StackFrames.prototype = {
|
||||
}
|
||||
let variableNames = Object.keys(aVariables);
|
||||
|
||||
// Sort all of the variables before adding them if preferred.
|
||||
// Sort all of the variables before adding them, if preferred.
|
||||
if (Prefs.variablesSortingEnabled) {
|
||||
variableNames.sort();
|
||||
}
|
||||
// Add the sorted variables to the specified scope.
|
||||
// Add the variables to the specified scope.
|
||||
for (let name of variableNames) {
|
||||
let varRef = aScope.addVar(name, aVariables[name]);
|
||||
let varVal = aVariables[name].value;
|
||||
@ -883,18 +897,19 @@ StackFrames.prototype = {
|
||||
* The grip of the variable.
|
||||
*/
|
||||
_fetchVarProperties: function SF__fetchVarProperties(aVar, aGrip) {
|
||||
// Retrieve the properties only once.
|
||||
if (aVar.fetched) {
|
||||
// Fetch the properties only once.
|
||||
if (aVar._fetched) {
|
||||
return;
|
||||
}
|
||||
aVar.fetched = true;
|
||||
aVar._fetched = true;
|
||||
|
||||
this.activeThread.pauseGrip(aGrip).getPrototypeAndProperties(function(aResponse) {
|
||||
let { ownProperties, prototype } = aResponse;
|
||||
let sortable = VARIABLES_VIEW_NON_SORTABLE.indexOf(aGrip.class) == -1;
|
||||
|
||||
// Add all the variable properties.
|
||||
if (ownProperties) {
|
||||
aVar.addProperties(ownProperties);
|
||||
aVar.addProperties(ownProperties, { sorted: sortable });
|
||||
// Expansion handlers must be set after the properties are added.
|
||||
for (let name in ownProperties) {
|
||||
this._addVarExpander(aVar.get(name), ownProperties[name].value);
|
||||
@ -908,6 +923,7 @@ StackFrames.prototype = {
|
||||
this._addVarExpander(aVar.get("__proto__"), prototype);
|
||||
}
|
||||
|
||||
// Mark the variable as having retrieved all its properties.
|
||||
aVar._retrieved = true;
|
||||
|
||||
// Signal that properties have been fetched.
|
||||
|
@ -34,6 +34,7 @@ MOCHITEST_BROWSER_TESTS = \
|
||||
browser_dbg_propertyview-10.js \
|
||||
browser_dbg_propertyview-edit.js \
|
||||
browser_dbg_propertyview-edit-watch.js \
|
||||
browser_dbg_propertyview-big-data.js \
|
||||
browser_dbg_propertyview-data.js \
|
||||
browser_dbg_propertyview-filter-01.js \
|
||||
browser_dbg_propertyview-filter-02.js \
|
||||
@ -102,6 +103,7 @@ MOCHITEST_BROWSER_PAGES = \
|
||||
browser_dbg_script-switching.html \
|
||||
test-script-switching-01.js \
|
||||
test-script-switching-02.js \
|
||||
browser_dbg_big-data.html \
|
||||
browser_dbg_frame-parameters.html \
|
||||
browser_dbg_update-editor-mode.html \
|
||||
test-editor-mode \
|
||||
|
27
browser/devtools/debugger/test/browser_dbg_big-data.html
Normal file
27
browser/devtools/debugger/test/browser_dbg_big-data.html
Normal file
@ -0,0 +1,27 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'/>
|
||||
<title>Debugger Big Data Test</title>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<script type="text/javascript">
|
||||
window.addEventListener("load", function() {
|
||||
function test(aNumber) {
|
||||
var buffer = new ArrayBuffer(aNumber);
|
||||
var z = new Int8Array(buffer);
|
||||
debugger;
|
||||
};
|
||||
function load() {
|
||||
test(10000);
|
||||
}
|
||||
var button = document.querySelector("button");
|
||||
button.addEventListener("click", load, false);
|
||||
});
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<button>Click me!</button>
|
||||
</body>
|
||||
</html>
|
@ -25,27 +25,15 @@ function test()
|
||||
|
||||
function testFrameParameters()
|
||||
{
|
||||
dump("Started testFrameParameters!\n");
|
||||
|
||||
gDebugger.addEventListener("Debugger:FetchedVariables", function test() {
|
||||
dump("Entered Debugger:FetchedVariables!\n");
|
||||
|
||||
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
dump("After currentThread.dispatch!\n");
|
||||
|
||||
var frames = gDebugger.DebuggerView.StackFrames._container._list,
|
||||
childNodes = frames.childNodes,
|
||||
localScope = gDebugger.DebuggerView.Variables._list.querySelector(".scope"),
|
||||
localNodes = localScope.querySelector(".details").childNodes;
|
||||
|
||||
dump("Got our variables:\n");
|
||||
dump("frames - " + frames.constructor + "\n");
|
||||
dump("childNodes - " + childNodes.constructor + "\n");
|
||||
dump("localScope - " + localScope.constructor + "\n");
|
||||
dump("localNodes - " + localNodes.constructor + "\n");
|
||||
|
||||
is(gDebugger.DebuggerController.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
|
||||
|
@ -25,27 +25,15 @@ function test()
|
||||
|
||||
function testFrameParameters()
|
||||
{
|
||||
dump("Started testFrameParameters!\n");
|
||||
|
||||
gDebugger.addEventListener("Debugger:FetchedVariables", function test() {
|
||||
dump("Entered Debugger:FetchedVariables!\n");
|
||||
|
||||
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
dump("After currentThread.dispatch!\n");
|
||||
|
||||
var frames = gDebugger.DebuggerView.StackFrames._container._list,
|
||||
localScope = gDebugger.DebuggerView.Variables._list.querySelectorAll(".scope")[0],
|
||||
localNodes = localScope.querySelector(".details").childNodes,
|
||||
localNonEnums = localScope.querySelector(".nonenum").childNodes;
|
||||
|
||||
dump("Got our variables:\n");
|
||||
dump("frames - " + frames.constructor + "\n");
|
||||
dump("localScope - " + localScope.constructor + "\n");
|
||||
dump("localNodes - " + localNodes.constructor + "\n");
|
||||
dump("localNonEnums - " + localNonEnums.constructor + "\n");
|
||||
|
||||
is(gDebugger.DebuggerController.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
|
||||
@ -57,23 +45,45 @@ function testFrameParameters()
|
||||
|
||||
is(localNodes[0].querySelector(".value").getAttribute("value"), "[object Proxy]",
|
||||
"Should have the right property value for 'this'.");
|
||||
is(localNodes[8].querySelector(".value").getAttribute("value"), "[object Arguments]",
|
||||
"Should have the right property value for 'arguments'.");
|
||||
is(localNodes[10].querySelector(".value").getAttribute("value"), "[object Object]",
|
||||
"Should have the right property value for 'c'.");
|
||||
|
||||
let thisNode, argumentsNode, cNode;
|
||||
for (let [id, scope] in gDebugger.DebuggerView.Variables) {
|
||||
if (scope.target === localScope) {
|
||||
for (let [name, variable] in scope) {
|
||||
if (variable.target === localNodes[0]) {
|
||||
thisNode = variable;
|
||||
}
|
||||
if (variable.target === localNodes[8]) {
|
||||
argumentsNode = variable;
|
||||
}
|
||||
if (variable.target === localNodes[10]) {
|
||||
cNode = variable;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let gVars = gDebugger.DebuggerView.Variables;
|
||||
|
||||
is(gVars.getScopeForNode(
|
||||
gVars._list.querySelectorAll(".scope")[0]).target,
|
||||
gVars._list.querySelectorAll(".scope")[0],
|
||||
"getScopeForNode([0]) didn't return the expected scope.");
|
||||
is(gVars.getScopeForNode(
|
||||
gVars._list.querySelectorAll(".scope")[1]).target,
|
||||
gVars._list.querySelectorAll(".scope")[1],
|
||||
"getScopeForNode([1]) didn't return the expected scope.");
|
||||
is(gVars.getScopeForNode(
|
||||
gVars._list.querySelectorAll(".scope")[2]).target,
|
||||
gVars._list.querySelectorAll(".scope")[2],
|
||||
"getScopeForNode([2]) didn't return the expected scope.");
|
||||
|
||||
is(gVars.getScopeForNode(gVars._list.querySelectorAll(".scope")[0]).expanded, true,
|
||||
"The local scope should be expanded by default.");
|
||||
is(gVars.getScopeForNode(gVars._list.querySelectorAll(".scope")[1]).expanded, false,
|
||||
"The block scope should be collapsed by default.");
|
||||
is(gVars.getScopeForNode(gVars._list.querySelectorAll(".scope")[2]).expanded, false,
|
||||
"The global scope should be collapsed by default.");
|
||||
|
||||
|
||||
let thisNode = gVars.getVariableOrPropertyForNode(localNodes[0]);
|
||||
let argumentsNode = gVars.getVariableOrPropertyForNode(localNodes[8]);
|
||||
let cNode = gVars.getVariableOrPropertyForNode(localNodes[10]);
|
||||
|
||||
is(thisNode.expanded, false,
|
||||
"The thisNode should not be expanded at this point.");
|
||||
is(argumentsNode.expanded, false,
|
||||
"The argumentsNode should not be expanded at this point.");
|
||||
is(cNode.expanded, false,
|
||||
"The cNode should not be expanded at this point.");
|
||||
|
||||
// Expand the 'this', 'arguments' and 'c' tree nodes. This causes
|
||||
// their properties to be retrieved and displayed.
|
||||
@ -81,6 +91,13 @@ function testFrameParameters()
|
||||
argumentsNode.expand();
|
||||
cNode.expand();
|
||||
|
||||
is(thisNode.expanded, true,
|
||||
"The thisNode should be expanded at this point.");
|
||||
is(argumentsNode.expanded, true,
|
||||
"The argumentsNode should be expanded at this point.");
|
||||
is(cNode.expanded, true,
|
||||
"The cNode should be expanded at this point.");
|
||||
|
||||
// Poll every few milliseconds until the properties are retrieved.
|
||||
// It's important to set the timer in the chrome window, because the
|
||||
// content window timers are disabled while the debuggee is paused.
|
||||
@ -98,52 +115,103 @@ function testFrameParameters()
|
||||
return;
|
||||
}
|
||||
window.clearInterval(intervalID);
|
||||
is(thisNode.target.querySelector(".property > .title > .name")
|
||||
.getAttribute("value"), "InstallTrigger",
|
||||
"Should have the right property name for InstallTrigger.");
|
||||
ok(thisNode.target.querySelector(".property > .title > .value")
|
||||
.getAttribute("value").search(/object/) == -1,
|
||||
"InstallTrigger should not be an object.");
|
||||
|
||||
is(thisNode.target.querySelector(".value")
|
||||
.getAttribute("value"), "[object Proxy]",
|
||||
"Should have the right property value for 'this'.");
|
||||
|
||||
is(thisNode.get("window").target.querySelector(".name")
|
||||
.getAttribute("value"), "window",
|
||||
"Should have the right property name for 'window'.");
|
||||
ok(thisNode.get("window").target.querySelector(".value")
|
||||
.getAttribute("value").search(/object/) != -1,
|
||||
"'window' should be an object.");
|
||||
|
||||
is(thisNode.get("document").target.querySelector(".name")
|
||||
.getAttribute("value"), "document",
|
||||
"Should have the right property name for 'document'.");
|
||||
ok(thisNode.get("document").target.querySelector(".value")
|
||||
.getAttribute("value").search(/object/) != -1,
|
||||
"'document' should be an object.");
|
||||
|
||||
|
||||
is(argumentsNode.target.querySelector(".value")
|
||||
.getAttribute("value"), "[object Arguments]",
|
||||
"Should have the right property value for 'arguments'.");
|
||||
ok(argumentsNode.target.querySelector(".property > .title > .value")
|
||||
.getAttribute("value").search(/object/) != -1,
|
||||
"Arguments should be an object.");
|
||||
.getAttribute("value"), "[object Arguments]",
|
||||
"Should have the right property value for 'arguments'.");
|
||||
|
||||
is(argumentsNode.target.querySelectorAll(".property > .title > .name")[0]
|
||||
.getAttribute("value"), "0",
|
||||
"Should have the right property name for 'arguments[0]'.");
|
||||
ok(argumentsNode.target.querySelectorAll(".property > .title > .value")[0]
|
||||
.getAttribute("value").search(/object/) != -1,
|
||||
"'arguments[0]' should be an object.");
|
||||
|
||||
is(argumentsNode.target.querySelectorAll(".property > .title > .name")[7]
|
||||
.getAttribute("value"), "__proto__",
|
||||
"Should have the right property name for '__proto__'.");
|
||||
.getAttribute("value"), "__proto__",
|
||||
"Should have the right property name for '__proto__'.");
|
||||
ok(argumentsNode.target.querySelectorAll(".property > .title > .value")[7]
|
||||
.getAttribute("value").search(/object/) != -1,
|
||||
"__proto__ should be an object.");
|
||||
.getAttribute("value").search(/object/) != -1,
|
||||
"'__proto__' should be an object.");
|
||||
|
||||
|
||||
is(cNode.target.querySelector(".value")
|
||||
.getAttribute("value"), "[object Object]",
|
||||
.getAttribute("value"), "[object Object]",
|
||||
"Should have the right property value for 'c'.");
|
||||
|
||||
is(cNode.target.querySelectorAll(".property > .title > .name")[0]
|
||||
.getAttribute("value"), "a",
|
||||
.getAttribute("value"), "a",
|
||||
"Should have the right property name for 'c.a'.");
|
||||
is(cNode.target.querySelectorAll(".property > .title > .value")[0]
|
||||
.getAttribute("value"), "1",
|
||||
.getAttribute("value"), "1",
|
||||
"Should have the right value for 'c.a'.");
|
||||
|
||||
is(cNode.target.querySelectorAll(".property > .title > .name")[1]
|
||||
.getAttribute("value"), "b",
|
||||
.getAttribute("value"), "b",
|
||||
"Should have the right property name for 'c.b'.");
|
||||
is(cNode.target.querySelectorAll(".property > .title > .value")[1]
|
||||
.getAttribute("value"), "\"beta\"",
|
||||
.getAttribute("value"), "\"beta\"",
|
||||
"Should have the right value for 'c.b'.");
|
||||
|
||||
is(cNode.target.querySelectorAll(".property > .title > .name")[2]
|
||||
.getAttribute("value"), "c",
|
||||
.getAttribute("value"), "c",
|
||||
"Should have the right property name for 'c.c'.");
|
||||
is(cNode.target.querySelectorAll(".property > .title > .value")[2]
|
||||
.getAttribute("value"), "true",
|
||||
.getAttribute("value"), "true",
|
||||
"Should have the right value for 'c.c'.");
|
||||
|
||||
|
||||
is(gVars.getVariableOrPropertyForNode(
|
||||
cNode.target.querySelectorAll(".property")[0]).target,
|
||||
cNode.target.querySelectorAll(".property")[0],
|
||||
"getVariableOrPropertyForNode([0]) didn't return the expected property.");
|
||||
|
||||
is(gVars.getVariableOrPropertyForNode(
|
||||
cNode.target.querySelectorAll(".property")[1]).target,
|
||||
cNode.target.querySelectorAll(".property")[1],
|
||||
"getVariableOrPropertyForNode([1]) didn't return the expected property.");
|
||||
|
||||
is(gVars.getVariableOrPropertyForNode(
|
||||
cNode.target.querySelectorAll(".property")[2]).target,
|
||||
cNode.target.querySelectorAll(".property")[2],
|
||||
"getVariableOrPropertyForNode([2]) didn't return the expected property.");
|
||||
|
||||
|
||||
is(cNode.find(
|
||||
cNode.target.querySelectorAll(".property")[0]).target,
|
||||
cNode.target.querySelectorAll(".property")[0],
|
||||
"find([0]) didn't return the expected property.");
|
||||
|
||||
is(cNode.find(
|
||||
cNode.target.querySelectorAll(".property")[1]).target,
|
||||
cNode.target.querySelectorAll(".property")[1],
|
||||
"find([1]) didn't return the expected property.");
|
||||
|
||||
is(cNode.find(
|
||||
cNode.target.querySelectorAll(".property")[2]).target,
|
||||
cNode.target.querySelectorAll(".property")[2],
|
||||
"find([2]) didn't return the expected property.");
|
||||
|
||||
|
||||
resumeAndFinish();
|
||||
}, 100);
|
||||
}}, 0);
|
||||
|
@ -0,0 +1,143 @@
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Make sure that the property view remains responsive when faced with
|
||||
* huge ammounts of data.
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "browser_dbg_big-data.html";
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebugger = null;
|
||||
|
||||
requestLongerTimeout(10);
|
||||
|
||||
function test()
|
||||
{
|
||||
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.panelWin;
|
||||
|
||||
gDebugger.DebuggerController.StackFrames.autoScopeExpand = true;
|
||||
gDebugger.DebuggerView.Variables.nonEnumVisible = false;
|
||||
gDebugger.DebuggerView.Variables.lazyAppend = true;
|
||||
testWithFrame();
|
||||
});
|
||||
}
|
||||
|
||||
function testWithFrame()
|
||||
{
|
||||
let count = 0;
|
||||
gDebugger.addEventListener("Debugger:FetchedVariables", function test1() {
|
||||
// We expect 2 Debugger:FetchedVariables events, one from the global object
|
||||
// scope and the regular one.
|
||||
if (++count < 2) {
|
||||
info("Number of received Debugger:FetchedVariables events: " + count);
|
||||
return;
|
||||
}
|
||||
gDebugger.removeEventListener("Debugger:FetchedVariables", test1, false);
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
var scopes = gDebugger.DebuggerView.Variables._list,
|
||||
innerScope = scopes.querySelectorAll(".scope")[0],
|
||||
loadScope = scopes.querySelectorAll(".scope")[1],
|
||||
globalScope = scopes.querySelectorAll(".scope")[2],
|
||||
innerNodes = innerScope.querySelector(".details").childNodes,
|
||||
arrayNodes = innerNodes[4].querySelector(".details").childNodes;
|
||||
|
||||
is(innerNodes[3].querySelector(".name").getAttribute("value"), "buffer",
|
||||
"Should have the right property name for |buffer|.");
|
||||
|
||||
is(innerNodes[3].querySelector(".value").getAttribute("value"), "[object ArrayBuffer]",
|
||||
"Should have the right property value for |buffer|.");
|
||||
|
||||
is(innerNodes[4].querySelector(".name").getAttribute("value"), "z",
|
||||
"Should have the right property name for |z|.");
|
||||
|
||||
is(innerNodes[4].querySelector(".value").getAttribute("value"), "[object Int8Array]",
|
||||
"Should have the right property value for |z|.");
|
||||
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, innerNodes[3].querySelector(".arrow"), gDebugger);
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, innerNodes[4].querySelector(".arrow"), gDebugger);
|
||||
|
||||
gDebugger.addEventListener("Debugger:FetchedProperties", function test2() {
|
||||
gDebugger.removeEventListener("Debugger:FetchedProperties", test2, false);
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
let total = 10000;
|
||||
let loaded = 0;
|
||||
let paints = 0;
|
||||
|
||||
waitForProperties(total, {
|
||||
onLoading: function(count) {
|
||||
ok(count >= loaded, "Should have loaded more properties.");
|
||||
info("Displayed " + count + " properties, not finished yet.");
|
||||
info("Remaining " + (total - count) + " properties to display.");
|
||||
loaded = count;
|
||||
paints++;
|
||||
|
||||
loadScope.hidden = true;
|
||||
globalScope.hidden = true;
|
||||
scopes.parentNode.scrollTop = scopes.parentNode.scrollHeight;
|
||||
},
|
||||
onFinished: function(count) {
|
||||
ok(count == total, "Displayed all the properties.");
|
||||
isnot(paints, 0, "Debugger was unresponsive, sad panda.");
|
||||
|
||||
for (let i = 0; i < arrayNodes.length; i++) {
|
||||
let node = arrayNodes[i];
|
||||
let name = node.querySelector(".name").getAttribute("value");
|
||||
is(name, i + "", "The array items aren't in the correct order.");
|
||||
}
|
||||
|
||||
closeDebuggerAndFinish();
|
||||
}
|
||||
});
|
||||
}}, 0);
|
||||
}, false);
|
||||
}}, 0);
|
||||
}, false);
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
content.document.querySelector("button"),
|
||||
content.window);
|
||||
}
|
||||
|
||||
function waitForProperties(total, callbacks)
|
||||
{
|
||||
var scopes = gDebugger.DebuggerView.Variables._list,
|
||||
innerScope = scopes.querySelectorAll(".scope")[0],
|
||||
innerNodes = innerScope.querySelector(".details").childNodes,
|
||||
arrayNodes = innerNodes[4].querySelector(".details").childNodes;
|
||||
|
||||
// Poll every few milliseconds until the properties are retrieved.
|
||||
let count = 0;
|
||||
let intervalID = window.setInterval(function() {
|
||||
info("count: " + count + " ");
|
||||
if (++count > total) {
|
||||
ok(false, "Timed out while polling for the properties.");
|
||||
window.clearInterval(intervalID);
|
||||
return closeDebuggerAndFinish();
|
||||
}
|
||||
// Still need to wait for a few more properties to be fetched.
|
||||
if (arrayNodes.length < total) {
|
||||
callbacks.onLoading(arrayNodes.length);
|
||||
return;
|
||||
}
|
||||
// We got all the properties, it's safe to callback.
|
||||
window.clearInterval(intervalID);
|
||||
callbacks.onFinished(arrayNodes.length);
|
||||
}, 100);
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
removeTab(gTab);
|
||||
gPane = null;
|
||||
gTab = null;
|
||||
gDebugger = null;
|
||||
});
|
@ -78,7 +78,7 @@ function testHierarchy() {
|
||||
"There should be 1 scope, 1 var, 1 proto, 8 props, 1 getter and 1 setter.");
|
||||
|
||||
gScope = gVariablesView._currHierarchy.get("");
|
||||
gVariable = gVariablesView._currHierarchy.get(".");
|
||||
gVariable = gVariablesView._currHierarchy.get("[\"\"]");
|
||||
|
||||
is(gVariablesView._store.size, 1,
|
||||
"There should be only one scope in the view");
|
||||
|
@ -70,7 +70,7 @@ function testFrameEval() {
|
||||
|
||||
is(scope.get("this")._isShown, true,
|
||||
"Should have the right visibility state for 'this'.");
|
||||
is(scope.get("this").target.querySelectorAll(".dbg-variables-delete").length, 1,
|
||||
is(scope.get("this").target.querySelectorAll(".dbg-variable-delete").length, 1,
|
||||
"Should have the one close button visible for 'this'.");
|
||||
is(scope.get("this").name, "this",
|
||||
"Should have the right name for 'this'.");
|
||||
@ -81,7 +81,7 @@ function testFrameEval() {
|
||||
|
||||
is(scope.get("ermahgerd")._isShown, true,
|
||||
"Should have the right visibility state for 'ermahgerd'.");
|
||||
is(scope.get("ermahgerd").target.querySelectorAll(".dbg-variables-delete").length, 1,
|
||||
is(scope.get("ermahgerd").target.querySelectorAll(".dbg-variable-delete").length, 1,
|
||||
"Should have the one close button visible for 'ermahgerd'.");
|
||||
is(scope.get("ermahgerd").name, "ermahgerd",
|
||||
"Should have the right name for 'ermahgerd'.");
|
||||
@ -92,7 +92,7 @@ function testFrameEval() {
|
||||
|
||||
is(scope.get("aArg")._isShown, true,
|
||||
"Should have the right visibility state for 'aArg'.");
|
||||
is(scope.get("aArg").target.querySelectorAll(".dbg-variables-delete").length, 1,
|
||||
is(scope.get("aArg").target.querySelectorAll(".dbg-variable-delete").length, 1,
|
||||
"Should have the one close button visible for 'aArg'.");
|
||||
is(scope.get("aArg").name, "aArg",
|
||||
"Should have the right name for 'aArg'.");
|
||||
@ -101,7 +101,7 @@ function testFrameEval() {
|
||||
|
||||
is(scope.get("document.title")._isShown, true,
|
||||
"Should have the right visibility state for 'document.title'.");
|
||||
is(scope.get("document.title").target.querySelectorAll(".dbg-variables-delete").length, 1,
|
||||
is(scope.get("document.title").target.querySelectorAll(".dbg-variable-delete").length, 1,
|
||||
"Should have the one close button visible for 'document.title'.");
|
||||
is(scope.get("document.title").name, "document.title",
|
||||
"Should have the right name for 'document.title'.");
|
||||
@ -112,7 +112,7 @@ function testFrameEval() {
|
||||
|
||||
is(scope.get("document.title = 42")._isShown, true,
|
||||
"Should have the right visibility state for 'document.title = 42'.");
|
||||
is(scope.get("document.title = 42").target.querySelectorAll(".dbg-variables-delete").length, 1,
|
||||
is(scope.get("document.title = 42").target.querySelectorAll(".dbg-variable-delete").length, 1,
|
||||
"Should have the one close button visible for 'document.title = 42'.");
|
||||
is(scope.get("document.title = 42").name, "document.title = 42",
|
||||
"Should have the right name for 'document.title = 42'.");
|
||||
@ -325,7 +325,7 @@ function testExprDeletion(aVar, aTest, aCallback, aArgResult,
|
||||
}
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
aVar.querySelector(".dbg-variables-delete"),
|
||||
aVar.querySelector(".dbg-variable-delete"),
|
||||
gDebugger);
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ function testSearchbox()
|
||||
ok(!gDebugger.DebuggerView.Variables._parent.parentNode.querySelector(".variables-searchinput.devtools-searchinput"),
|
||||
"The searchbox element should not be found.");
|
||||
|
||||
gDebugger.DebuggerView.Variables.enableSearch();
|
||||
gDebugger.DebuggerView.Variables._enableSearch();
|
||||
ok(gDebugger.DebuggerView.Variables._searchboxNode,
|
||||
"There should be a searchbox available after enabling.");
|
||||
ok(gDebugger.DebuggerView.Variables._searchboxContainer.hidden,
|
||||
@ -47,13 +47,13 @@ function testSearchbox()
|
||||
"The searchbox element should be found.");
|
||||
|
||||
|
||||
gDebugger.DebuggerView.Variables.disableSearch();
|
||||
gDebugger.DebuggerView.Variables._disableSearch();
|
||||
ok(!gDebugger.DebuggerView.Variables._searchboxNode,
|
||||
"There shouldn't be a searchbox available after disabling.");
|
||||
ok(!gDebugger.DebuggerView.Variables._parent.parentNode.querySelector(".variables-searchinput.devtools-searchinput"),
|
||||
"The searchbox element should not be found.");
|
||||
|
||||
gDebugger.DebuggerView.Variables.enableSearch();
|
||||
gDebugger.DebuggerView.Variables._enableSearch();
|
||||
ok(gDebugger.DebuggerView.Variables._searchboxNode,
|
||||
"There should be a searchbox available after enabling.");
|
||||
ok(gDebugger.DebuggerView.Variables._searchboxContainer.hidden,
|
||||
@ -61,20 +61,24 @@ function testSearchbox()
|
||||
ok(gDebugger.DebuggerView.Variables._parent.parentNode.querySelector(".variables-searchinput.devtools-searchinput"),
|
||||
"The searchbox element should be found.");
|
||||
|
||||
|
||||
let placeholder = "freshly squeezed mango juice";
|
||||
|
||||
gDebugger.DebuggerView.Variables.searchPlaceholder = placeholder;
|
||||
is(gDebugger.DebuggerView.Variables.searchPlaceholder, placeholder,
|
||||
"The placeholder getter didn't return the expected string");
|
||||
|
||||
ok(gDebugger.DebuggerView.Variables._searchboxNode.getAttribute("placeholder"),
|
||||
placeholder, "There correct placeholder should be applied to the searchbox.");
|
||||
|
||||
|
||||
gDebugger.DebuggerView.Variables.disableSearch();
|
||||
gDebugger.DebuggerView.Variables._disableSearch();
|
||||
ok(!gDebugger.DebuggerView.Variables._searchboxNode,
|
||||
"There shouldn't be a searchbox available after disabling again.");
|
||||
ok(!gDebugger.DebuggerView.Variables._parent.parentNode.querySelector(".variables-searchinput.devtools-searchinput"),
|
||||
"The searchbox element should not be found.");
|
||||
|
||||
gDebugger.DebuggerView.Variables.enableSearch();
|
||||
gDebugger.DebuggerView.Variables._enableSearch();
|
||||
ok(gDebugger.DebuggerView.Variables._searchboxNode,
|
||||
"There should be a searchbox available after enabling again.");
|
||||
ok(gDebugger.DebuggerView.Variables._searchboxContainer.hidden,
|
||||
|
@ -38,7 +38,7 @@ function testSearchbox()
|
||||
ok(!gDebugger.DebuggerView.Variables._parent.parentNode.querySelector(".variables-searchinput.devtools-searchinput"),
|
||||
"The searchbox element should not be found.");
|
||||
|
||||
gDebugger.DebuggerView.Variables.enableSearch();
|
||||
gDebugger.DebuggerView.Variables._enableSearch();
|
||||
ok(gDebugger.DebuggerView.Variables._searchboxNode,
|
||||
"There should be a searchbox available after enabling.");
|
||||
ok(gDebugger.DebuggerView.Variables._parent.parentNode.querySelector(".variables-searchinput.devtools-searchinput"),
|
||||
|
@ -183,6 +183,7 @@ function debug_tab_pane(aURL, aOnDebugging) {
|
||||
// Wait for the initial resume...
|
||||
dbg.panelWin.gClient.addOneTimeListener("resumed", function() {
|
||||
dbg._view.Variables.lazyEmpty = false;
|
||||
dbg._view.Variables.lazyAppend = false;
|
||||
aOnDebugging(tab, debuggee, dbg);
|
||||
});
|
||||
});
|
||||
@ -205,6 +206,7 @@ function debug_remote(aURL, aOnDebugging, aBeforeTabAdded) {
|
||||
// Wait for the initial resume...
|
||||
win.panelWin.gClient.addOneTimeListener("resumed", function() {
|
||||
win._dbgwin.DebuggerView.Variables.lazyEmpty = false;
|
||||
win._dbgwin.DebuggerView.Variables.lazyAppend = false;
|
||||
aOnDebugging(tab, debuggee, win);
|
||||
});
|
||||
}, true);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -289,11 +289,17 @@
|
||||
min-height: 10px;
|
||||
}
|
||||
|
||||
.dbg-variables-delete:not(:hover) {
|
||||
.dbg-variable-delete:not(:hover) {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.dbg-variable-throbber {
|
||||
background: url("chrome://global/skin/icons/loading_16.png");
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope element
|
||||
*/
|
||||
|
@ -291,11 +291,17 @@
|
||||
min-height: 10px;
|
||||
}
|
||||
|
||||
.dbg-variables-delete:not(:hover) {
|
||||
.dbg-variable-delete:not(:hover) {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.dbg-variable-throbber {
|
||||
background: url("chrome://global/skin/icons/loading_16.png");
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope element
|
||||
*/
|
||||
|
@ -297,11 +297,17 @@
|
||||
min-height: 10px;
|
||||
}
|
||||
|
||||
.dbg-variables-delete:not(:hover) {
|
||||
.dbg-variable-delete:not(:hover) {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.dbg-variable-throbber {
|
||||
background: url("chrome://global/skin/icons/loading_16.png");
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope element
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user