import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,13 @@
var { Cc, Ci } = require("chrome");
var { once } = require("sdk/system/events");
var observerService = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
var observer = {
observe: function () {
debugger;
}
};
once("sdk:loader:destroy", () => observerService.removeObserver(observer, "debuggerAttached"));
observerService.addObserver(observer, "debuggerAttached", false);

View file

@ -0,0 +1,9 @@
{
"name": "browser_dbg_addon3",
"title": "browser_dbg_addon3",
"id": "jid1-ami3akps3baaeg",
"description": "a basic add-on",
"author": "",
"license": "MPL 2.0",
"version": "0.1"
}

View file

@ -0,0 +1,36 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
var { interfaces: Ci, utils: Cu } = Components;
function notify() {
// Log objects so makeDebuggeeValue can get the global to use
console.log({ msg: "Hello again" });
}
function startup(aParams, aReason) {
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
let res = Services.io.getProtocolHandler("resource")
.QueryInterface(Ci.nsIResProtocolHandler);
res.setSubstitution("browser_dbg_addon4", aParams.resourceURI);
// Load a JS module
Cu.import("resource://browser_dbg_addon4/test.jsm"); // eslint-disable-line mozilla/no-single-arg-cu-import
// Log objects so makeDebuggeeValue can get the global to use
console.log({ msg: "Hello from the test add-on" });
Services.obs.addObserver(notify, "addon-test-ping", false);
}
function shutdown(aParams, aReason) {
Services.obs.removeObserver(notify, "addon-test-ping");
// Unload the JS module
Cu.unload("resource://browser_dbg_addon4/test.jsm");
let res = Services.io.getProtocolHandler("resource")
.QueryInterface(Ci.nsIResProtocolHandler);
res.setSubstitution("browser_dbg_addon4", null);
}

View file

@ -0,0 +1 @@
content browser_dbg_addon4 .

View file

@ -0,0 +1,19 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>browser_dbg_addon4@tests.mozilla.org</em:id>
<em:version>1.0</em:version>
<em:name>Test add-on with JS Modules</em:name>
<em:bootstrap>true</em:bootstrap>
<em:targetApplication>
<Description>
<em:id>toolkit@mozilla.org</em:id>
<em:minVersion>0</em:minVersion>
<em:maxVersion>*</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

View file

@ -0,0 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const EXPORTED_SYMBOLS = ["Foo"];
const Foo = {};

View file

@ -0,0 +1,8 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="text/javascript" src="testxul.js"/>
<label value="test.xul"/>
</window>

View file

@ -0,0 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const EXPORTED_SYMBOLS = ["Bar"];
const Bar = {};

View file

@ -0,0 +1,8 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="text/javascript" src="testxul2.js"/>
<label value="test2.xul"/>
</window>

View file

@ -0,0 +1,4 @@
// Define something in here or the script may get collected
window.addEventListener("unload", function () {
window.foo = "bar";
});

View file

@ -0,0 +1,4 @@
// Define something in here or the script may get collected
window.addEventListener("unload", function () {
window.foo = "bar";
});

View file

@ -0,0 +1,23 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var { interfaces: Ci, classes: Cc } = Components;
function startup(aParams, aReason) {
Components.utils.import("resource://gre/modules/Services.jsm");
let res = Services.io.getProtocolHandler("resource")
.QueryInterface(Ci.nsIResProtocolHandler);
res.setSubstitution("browser_dbg_addon5", aParams.resourceURI);
// Load a JS module
Components.utils.import("resource://browser_dbg_addon5/test.jsm");
}
function shutdown(aParams, aReason) {
// Unload the JS module
Components.utils.unload("resource://browser_dbg_addon5/test.jsm");
let res = Services.io.getProtocolHandler("resource")
.QueryInterface(Ci.nsIResProtocolHandler);
res.setSubstitution("browser_dbg_addon5", null);
}

View file

@ -0,0 +1 @@
content browser_dbg_addon5 .

View file

@ -0,0 +1,20 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>browser_dbg_addon5@tests.mozilla.org</em:id>
<em:version>1.0</em:version>
<em:name>Test unpacked add-on with JS Modules</em:name>
<em:bootstrap>true</em:bootstrap>
<em:unpack>true</em:unpack>
<em:targetApplication>
<Description>
<em:id>toolkit@mozilla.org</em:id>
<em:minVersion>0</em:minVersion>
<em:maxVersion>*</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

View file

@ -0,0 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const EXPORTED_SYMBOLS = ["Foo"];
const Foo = {};

View file

@ -0,0 +1,8 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="text/javascript" src="testxul.js"/>
<label value="test.xul"/>
</window>

View file

@ -0,0 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const EXPORTED_SYMBOLS = ["Bar"];
const Bar = {};

View file

@ -0,0 +1,8 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="text/javascript" src="testxul2.js"/>
<label value="test2.xul"/>
</window>

View file

@ -0,0 +1,4 @@
// Define something in here or the script may get collected
window.addEventListener("unload", function () {
window.foo = "bar";
});

View file

@ -0,0 +1,4 @@
// Define something in here or the script may get collected
window.addEventListener("unload", function () {
window.foo = "bar";
});

View file

@ -0,0 +1,18 @@
{
"manifest_version": 2,
"name": "test content script sources",
"description": "test content script sources",
"version": "0.1.0",
"applications": {
"gecko": {
"id": "test-contentscript-sources@mozilla.com"
}
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["webext-content-script.js"],
"run_at": "document_start"
}
]
}

View file

@ -0,0 +1 @@
console.log("CONTENT SCRIPT LOADED");

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,317 @@
# Tests in this directory are split into two manifests (this and browser2.ini)
# to facilitate better chunking; see bug 1294489.
[DEFAULT]
tags = devtools
subsuite = devtools
skip-if = (os == 'linux' && debug && bits == 32)
support-files =
addon1.xpi
addon2.xpi
addon3.xpi
addon4.xpi
addon5.xpi
addon-webext-contentscript.xpi
addon-source/browser_dbg_addon5/*
code_binary_search.coffee
code_binary_search.js
code_binary_search.map
code_blackboxing_blackboxme.js
code_blackboxing_one.js
code_blackboxing_three.js
code_blackboxing_two.js
code_blackboxing_unblackbox.min.js
code_breakpoints-break-on-last-line-of-script-on-reload.js
code_breakpoints-other-tabs.js
code_bug-896139.js
code_frame-script.js
code_function-jump-01.js
code_function-search-01.js
code_function-search-02.js
code_function-search-03.js
code_location-changes.js
code_listworkers-worker1.js
code_listworkers-worker2.js
code_math.js
code_math.map
code_math.min.js
code_math_bogus_map.js
code_same-line-functions.js
code_script-eval.js
code_script-switching-01.js
code_script-switching-02.js
code_test-editor-mode
code_ugly.js
code_ugly-2.js
code_ugly-3.js
code_ugly-4.js
code_ugly-5.js
code_ugly-6.js
code_ugly-7.js
code_ugly-8
code_ugly-8^headers^
code_worker-source-map.coffee
code_worker-source-map.js
code_worker-source-map.js.map
code_WorkerActor.attach-worker1.js
code_WorkerActor.attach-worker2.js
code_WorkerActor.attachThread-worker.js
doc_auto-pretty-print-01.html
doc_auto-pretty-print-02.html
doc_binary_search.html
doc_blackboxing.html
doc_blackboxing_unblackbox.html
doc_breakpoints-break-on-last-line-of-script-on-reload.html
doc_breakpoints-other-tabs.html
doc_breakpoints-reload.html
doc_bug-896139.html
doc_closures.html
doc_closure-optimized-out.html
doc_cmd-break.html
doc_cmd-dbg.html
doc_breakpoint-move.html
doc_conditional-breakpoints.html
doc_domnode-variables.html
doc_editor-mode.html
doc_empty-tab-01.html
doc_empty-tab-02.html
doc_event-listeners-01.html
doc_event-listeners-02.html
doc_event-listeners-03.html
doc_event-listeners-04.html
doc_frame-parameters.html
doc_function-display-name.html
doc_function-jump.html
doc_function-search.html
doc_global-method-override.html
doc_iframes.html
doc_included-script.html
doc_inline-debugger-statement.html
doc_inline-script.html
doc_large-array-buffer.html
doc_listworkers-tab.html
doc_map-set.html
doc_minified.html
doc_minified_bogus_map.html
doc_native-event-handler.html
doc_no-page-sources.html
doc_pause-exceptions.html
doc_pretty-print.html
doc_pretty-print-2.html
doc_pretty-print-3.html
doc_pretty-print-on-paused.html
doc_promise-get-allocation-stack.html
doc_promise-get-fulfillment-stack.html
doc_promise-get-rejection-stack.html
doc_promise.html
doc_proxy.html
doc_random-javascript.html
doc_recursion-stack.html
doc_scope-variable.html
doc_scope-variable-2.html
doc_scope-variable-3.html
doc_scope-variable-4.html
doc_script-eval.html
doc_script-bookmarklet.html
doc_script-switching-01.html
doc_script-switching-02.html
doc_script_webext_contentscript.html
doc_split-console-paused-reload.html
doc_step-many-statements.html
doc_step-out.html
doc_terminate-on-tab-close.html
doc_watch-expressions.html
doc_watch-expression-button.html
doc_whitespace-property-names.html
doc_with-frame.html
doc_worker-source-map.html
doc_WorkerActor.attach-tab1.html
doc_WorkerActor.attach-tab2.html
doc_WorkerActor.attachThread-tab.html
head.js
sjs_post-page.sjs
sjs_random-javascript.sjs
testactors.js
!/devtools/client/commandline/test/helpers.js
!/devtools/client/framework/test/shared-head.js
[browser_dbg_aaa_run_first_leaktest.js]
skip-if = e10s && debug
[browser_dbg_addonactor.js]
tags = addons
[browser_dbg_addon-sources.js]
tags = addons
[browser_dbg_addon-workers-dbg-enabled.js]
tags = addons
[browser_dbg_addon-modules.js]
skip-if = e10s # TODO
tags = addons
[browser_dbg_addon-modules-unpacked.js]
skip-if = e10s # TODO
tags = addons
[browser_dbg_addon-panels.js]
tags = addons
[browser_dbg_addon-console.js]
skip-if = e10s && debug || os == 'win' # bug 1005274
tags = addons
[browser_dbg_auto-pretty-print-01.js]
[browser_dbg_auto-pretty-print-02.js]
[browser_dbg_auto-pretty-print-03.js]
[browser_dbg_bfcache.js]
skip-if = e10s || true # bug 1113935
[browser_dbg_blackboxing-01.js]
[browser_dbg_blackboxing-02.js]
[browser_dbg_blackboxing-03.js]
[browser_dbg_blackboxing-04.js]
[browser_dbg_blackboxing-05.js]
[browser_dbg_blackboxing-06.js]
[browser_dbg_blackboxing-07.js]
[browser_dbg_breadcrumbs-access.js]
[browser_dbg_break-in-anon.js]
[browser_dbg_break-on-next.js]
[browser_dbg_break-on-next-console.js]
[browser_dbg_break-on-dom-01.js]
[browser_dbg_break-on-dom-02.js]
[browser_dbg_break-on-dom-03.js]
[browser_dbg_break-on-dom-04.js]
[browser_dbg_break-on-dom-05.js]
[browser_dbg_break-on-dom-06.js]
[browser_dbg_break-on-dom-07.js]
[browser_dbg_break-on-dom-08.js]
[browser_dbg_break-on-dom-event-01.js]
skip-if = e10s || os == "mac" || e10s # Bug 895426
[browser_dbg_break-on-dom-event-02.js]
skip-if = e10s # TODO
[browser_dbg_break-on-dom-event-03.js]
skip-if = e10s # TODO
[browser_dbg_break-unselected.js]
[browser_dbg_breakpoints-actual-location.js]
[browser_dbg_breakpoints-actual-location2.js]
[browser_dbg_breakpoints-break-on-last-line-of-script-on-reload.js]
skip-if = e10s # Bug 1093535
[browser_dbg_breakpoints-button-01.js]
[browser_dbg_breakpoints-button-02.js]
[browser_dbg_breakpoints-condition-thrown-message.js]
skip-if = e10s && debug
[browser_dbg_breakpoints-contextmenu-add.js]
[browser_dbg_breakpoints-contextmenu.js]
[browser_dbg_breakpoints-disabled-reload.js]
skip-if = e10s # Bug 1093535
[browser_dbg_breakpoints-editor.js]
skip-if = e10s && debug
[browser_dbg_breakpoints-eval.js]
skip-if = e10s && debug
[browser_dbg_breakpoints-highlight.js]
skip-if = e10s && debug
[browser_dbg_breakpoints-new-script.js]
skip-if = e10s && debug
[browser_dbg_breakpoints-other-tabs.js]
skip-if = e10s && debug
[browser_dbg_breakpoints-pane.js]
skip-if = e10s && debug
[browser_dbg_breakpoints-reload.js]
skip-if = e10s && debug
[browser_dbg_bug-896139.js]
skip-if = e10s && debug
[browser_dbg_chrome-create.js]
skip-if = e10s && debug
[browser_dbg_chrome-debugging.js]
skip-if = e10s && debug
[browser_dbg_clean-exit-window.js]
skip-if = true # Bug 933950 (leaky test)
[browser_dbg_clean-exit.js]
skip-if = true # Bug 1044985 (racy test)
[browser_dbg_closure-inspection.js]
skip-if = e10s && debug
[browser_dbg_cmd-blackbox.js]
skip-if = e10s && debug
[browser_dbg_cmd-break.js]
skip-if = e10s # TODO
[browser_dbg_cmd-dbg.js]
skip-if = e10s # TODO
[browser_dbg_conditional-breakpoints-01.js]
skip-if = e10s && debug
[browser_dbg_conditional-breakpoints-02.js]
skip-if = e10s && debug
[browser_dbg_conditional-breakpoints-03.js]
skip-if = e10s && debug
[browser_dbg_conditional-breakpoints-04.js]
skip-if = e10s && debug
[browser_dbg_conditional-breakpoints-05.js]
skip-if = e10s && debug
[browser_dbg_console-eval.js]
skip-if = e10s && debug
[browser_dbg_console-named-eval.js]
skip-if = e10s && debug
[browser_dbg_server-conditional-bp-01.js]
skip-if = e10s && debug
[browser_dbg_server-conditional-bp-02.js]
skip-if = e10s && debug
[browser_dbg_server-conditional-bp-03.js]
skip-if = e10s && debug
[browser_dbg_server-conditional-bp-04.js]
skip-if = e10s && debug
[browser_dbg_server-conditional-bp-05.js]
skip-if = e10s && debug
[browser_dbg_controller-evaluate-01.js]
skip-if = e10s && debug
[browser_dbg_controller-evaluate-02.js]
skip-if = e10s && debug
[browser_dbg_debugger-statement.js]
skip-if = e10s && debug
[browser_dbg_editor-contextmenu.js]
skip-if = e10s && debug
[browser_dbg_editor-mode.js]
skip-if = e10s && debug
[browser_dbg_event-listeners-01.js]
skip-if = e10s && debug
[browser_dbg_event-listeners-02.js]
skip-if = e10s && debug
[browser_dbg_event-listeners-03.js]
skip-if = e10s && debug
[browser_dbg_event-listeners-04.js]
skip-if = debug || e10s # debug bug 1142597, e10s bug 1146603.
[browser_dbg_file-reload.js]
skip-if = e10s && debug
[browser_dbg_function-display-name.js]
skip-if = e10s && debug
[browser_dbg_global-method-override.js]
skip-if = e10s && debug
[browser_dbg_globalactor.js]
skip-if = e10s # TODO
[browser_dbg_hide-toolbar-buttons.js]
skip-if = e10s
[browser_dbg_host-layout.js]
skip-if = e10s && debug
[browser_dbg_jump-to-function-definition.js]
skip-if = e10s && debug
[browser_dbg_iframes.js]
skip-if = e10s # TODO
[browser_dbg_instruments-pane-collapse.js]
skip-if = e10s && debug
[browser_dbg_instruments-pane-collapse_keyboard.js]
skip-if = (os == 'mac' && e10s && debug) # Full keyboard navigation on OSX only works if Full Keyboard Access setting is set to All Control
[browser_dbg_interrupts.js]
skip-if = e10s && debug
[browser_dbg_listaddons.js]
skip-if = e10s && debug
tags = addons
[browser_dbg_listtabs-01.js]
skip-if = e10s # TODO
[browser_dbg_listtabs-02.js]
skip-if = true # Never worked for remote frames, needs a mock DebuggerServerConnection
[browser_dbg_listtabs-03.js]
skip-if = e10s && debug
[browser_dbg_listworkers.js]
[browser_dbg_location-changes-01-simple.js]
skip-if = e10s && debug
[browser_dbg_location-changes-02-blank.js]
skip-if = e10s && debug
[browser_dbg_location-changes-03-new.js]
skip-if = e10s # TODO
[browser_dbg_location-changes-04-breakpoint.js]
skip-if = e10s # TODO
[browser_dbg_multiple-windows.js]
skip-if = e10s # TODO
[browser_dbg_navigation.js]
skip-if = e10s && debug

View file

@ -0,0 +1,460 @@
# Tests in this directory are split into two manifests (this and browser.ini)
# to facilitate better chunking; see bug 1294489.
[DEFAULT]
tags = devtools
subsuite = devtools
skip-if = (os == 'linux' && debug && bits == 32)
support-files =
addon1.xpi
addon2.xpi
addon3.xpi
addon4.xpi
addon5.xpi
addon-webext-contentscript.xpi
addon-source/browser_dbg_addon5/*
code_binary_search.coffee
code_binary_search.js
code_binary_search.map
code_blackboxing_blackboxme.js
code_blackboxing_one.js
code_blackboxing_three.js
code_blackboxing_two.js
code_blackboxing_unblackbox.min.js
code_breakpoints-break-on-last-line-of-script-on-reload.js
code_breakpoints-other-tabs.js
code_bug-896139.js
code_frame-script.js
code_function-jump-01.js
code_function-search-01.js
code_function-search-02.js
code_function-search-03.js
code_location-changes.js
code_listworkers-worker1.js
code_listworkers-worker2.js
code_math.js
code_math.map
code_math.min.js
code_math_bogus_map.js
code_same-line-functions.js
code_script-eval.js
code_script-switching-01.js
code_script-switching-02.js
code_test-editor-mode
code_ugly.js
code_ugly-2.js
code_ugly-3.js
code_ugly-4.js
code_ugly-5.js
code_ugly-6.js
code_ugly-7.js
code_ugly-8
code_ugly-8^headers^
code_worker-source-map.coffee
code_worker-source-map.js
code_worker-source-map.js.map
code_WorkerActor.attach-worker1.js
code_WorkerActor.attach-worker2.js
code_WorkerActor.attachThread-worker.js
doc_auto-pretty-print-01.html
doc_auto-pretty-print-02.html
doc_binary_search.html
doc_blackboxing.html
doc_blackboxing_unblackbox.html
doc_breakpoints-break-on-last-line-of-script-on-reload.html
doc_breakpoints-other-tabs.html
doc_breakpoints-reload.html
doc_bug-896139.html
doc_closures.html
doc_closure-optimized-out.html
doc_cmd-break.html
doc_cmd-dbg.html
doc_breakpoint-move.html
doc_conditional-breakpoints.html
doc_domnode-variables.html
doc_editor-mode.html
doc_empty-tab-01.html
doc_empty-tab-02.html
doc_event-listeners-01.html
doc_event-listeners-02.html
doc_event-listeners-03.html
doc_event-listeners-04.html
doc_frame-parameters.html
doc_function-display-name.html
doc_function-jump.html
doc_function-search.html
doc_global-method-override.html
doc_iframes.html
doc_included-script.html
doc_inline-debugger-statement.html
doc_inline-script.html
doc_large-array-buffer.html
doc_listworkers-tab.html
doc_map-set.html
doc_minified.html
doc_minified_bogus_map.html
doc_native-event-handler.html
doc_no-page-sources.html
doc_pause-exceptions.html
doc_pretty-print.html
doc_pretty-print-2.html
doc_pretty-print-3.html
doc_pretty-print-on-paused.html
doc_promise-get-allocation-stack.html
doc_promise-get-fulfillment-stack.html
doc_promise-get-rejection-stack.html
doc_promise.html
doc_proxy.html
doc_random-javascript.html
doc_recursion-stack.html
doc_scope-variable.html
doc_scope-variable-2.html
doc_scope-variable-3.html
doc_scope-variable-4.html
doc_script-eval.html
doc_script-bookmarklet.html
doc_script-switching-01.html
doc_script-switching-02.html
doc_script_webext_contentscript.html
doc_split-console-paused-reload.html
doc_step-many-statements.html
doc_step-out.html
doc_terminate-on-tab-close.html
doc_watch-expressions.html
doc_watch-expression-button.html
doc_whitespace-property-names.html
doc_with-frame.html
doc_worker-source-map.html
doc_WorkerActor.attach-tab1.html
doc_WorkerActor.attach-tab2.html
doc_WorkerActor.attachThread-tab.html
head.js
sjs_post-page.sjs
sjs_random-javascript.sjs
testactors.js
!/devtools/client/commandline/test/helpers.js
!/devtools/client/framework/test/shared-head.js
[browser_dbg_no-dangling-breakpoints.js]
skip-if = e10s && debug
[browser_dbg_no-page-sources.js]
skip-if = e10s && debug
[browser_dbg_on-pause-highlight.js]
skip-if = e10s && debug
[browser_dbg_on-pause-raise.js]
skip-if = e10s && debug || os == "linux" # Bug 888811 & bug 891176
[browser_dbg_optimized-out-vars.js]
skip-if = e10s && debug
[browser_dbg_panel-size.js]
skip-if = e10s && debug
[browser_dbg_parser-01.js]
skip-if = e10s && debug
[browser_dbg_parser-02.js]
skip-if = e10s && debug
[browser_dbg_parser-03.js]
skip-if = e10s && debug
[browser_dbg_parser-04.js]
skip-if = e10s && debug
[browser_dbg_parser-05.js]
skip-if = e10s && debug
[browser_dbg_parser-06.js]
skip-if = e10s && debug
[browser_dbg_parser-07.js]
skip-if = e10s && debug
[browser_dbg_parser-08.js]
skip-if = e10s && debug
[browser_dbg_parser-09.js]
skip-if = e10s && debug
[browser_dbg_parser-10.js]
skip-if = e10s && debug
[browser_dbg_parser-11.js]
[browser_dbg_parser-computed-name.js]
[browser_dbg_parser-function-defaults.js]
[browser_dbg_parser-spread-expression.js]
[browser_dbg_parser-template-strings.js]
skip-if = e10s && debug
[browser_dbg_pause-exceptions-01.js]
skip-if = e10s && debug
[browser_dbg_pause-exceptions-02.js]
skip-if = e10s && debug
[browser_dbg_pause-no-step.js]
skip-if = e10s && debug
[browser_dbg_pause-resume.js]
skip-if = e10s && debug
[browser_dbg_pause-warning.js]
skip-if = e10s && debug
[browser_dbg_paused-keybindings.js]
skip-if = e10s
[browser_dbg_post-page.js]
[browser_dbg_pretty-print-01.js]
skip-if = e10s && debug
[browser_dbg_pretty-print-02.js]
skip-if = e10s && debug
[browser_dbg_pretty-print-03.js]
skip-if = e10s && debug
[browser_dbg_pretty-print-04.js]
skip-if = e10s && debug
[browser_dbg_pretty-print-05.js]
skip-if = e10s && debug
[browser_dbg_pretty-print-06.js]
skip-if = e10s && debug
[browser_dbg_pretty-print-07.js]
skip-if = e10s && debug
[browser_dbg_pretty-print-08.js]
skip-if = e10s && debug
[browser_dbg_pretty-print-09.js]
skip-if = e10s && debug
[browser_dbg_pretty-print-10.js]
skip-if = e10s && debug
[browser_dbg_pretty-print-11.js]
skip-if = e10s && debug
[browser_dbg_pretty-print-12.js]
skip-if = e10s && debug
[browser_dbg_pretty-print-13.js]
skip-if = e10s && debug
[browser_dbg_pretty-print-on-paused.js]
skip-if = e10s && debug
[browser_dbg_progress-listener-bug.js]
skip-if = e10s && debug
[browser_dbg_promises-allocation-stack.js]
skip-if = e10s && debug
[browser_dbg_promises-chrome-allocation-stack.js]
skip-if = true # Bug 1177730
[browser_dbg_promises-fulfillment-stack.js]
skip-if = e10s && debug
[browser_dbg_promises-rejection-stack.js]
skip-if = e10s && debug
[browser_dbg_reload-preferred-script-02.js]
skip-if = e10s && debug
[browser_dbg_reload-preferred-script-03.js]
skip-if = e10s && debug
[browser_dbg_reload-same-script.js]
skip-if = e10s && debug
[browser_dbg_scripts-switching-01.js]
skip-if = e10s && debug
[browser_dbg_scripts-switching-02.js]
skip-if = e10s && debug
[browser_dbg_scripts-switching-03.js]
skip-if = e10s && debug
[browser_dbg_search-autofill-identifier.js]
skip-if = e10s && debug
[browser_dbg_search-basic-01.js]
skip-if = e10s && debug
[browser_dbg_search-basic-02.js]
skip-if = e10s && debug
[browser_dbg_search-basic-03.js]
skip-if = e10s && debug
[browser_dbg_search-basic-04.js]
skip-if = e10s && debug
[browser_dbg_search-global-01.js]
skip-if = e10s && debug
[browser_dbg_search-global-02.js]
skip-if = e10s && debug
[browser_dbg_search-global-03.js]
skip-if = e10s # Bug 1093535
[browser_dbg_search-global-04.js]
skip-if = e10s && debug
[browser_dbg_search-global-05.js]
skip-if = e10s && debug
[browser_dbg_search-global-06.js]
skip-if = e10s && debug
[browser_dbg_search-popup-jank.js]
skip-if = e10s && debug
[browser_dbg_search-sources-01.js]
skip-if = e10s && debug
[browser_dbg_search-sources-02.js]
skip-if = e10s && debug
[browser_dbg_search-sources-03.js]
skip-if = e10s && debug
[browser_dbg_search-symbols.js]
skip-if = (e10s && debug) || os == "linux" # Bug 1132375
[browser_dbg_searchbox-help-popup-01.js]
skip-if = e10s && debug
[browser_dbg_searchbox-help-popup-02.js]
skip-if = e10s && debug
[browser_dbg_searchbox-parse.js]
skip-if = (debug) || (os == 'linux' && asan) # asan, bug 1313861, debug: bug 1313861
[browser_dbg_source-maps-01.js]
skip-if = e10s && debug
[browser_dbg_source-maps-02.js]
skip-if = e10s && debug
[browser_dbg_source-maps-03.js]
skip-if = e10s && debug
[browser_dbg_source-maps-04.js]
skip-if = e10s # Bug 1093535
[browser_dbg_sources-cache.js]
[browser_dbg_sources-contextmenu-01.js]
subsuite = clipboard
[browser_dbg_sources-contextmenu-02.js]
skip-if = e10s && debug
[browser_dbg_sources-eval-01.js]
skip-if = true # non-named eval sources turned off for now, bug 1124106
[browser_dbg_sources-eval-02.js]
[browser_dbg_sources-iframe-reload.js]
[browser_dbg_sources-keybindings.js]
subsuite = clipboard
skip-if = e10s && debug
[browser_dbg_sources-labels.js]
skip-if = e10s && debug
[browser_dbg_sources-large.js]
[browser_dbg_sources-sorting.js]
skip-if = e10s && debug
[browser_dbg_sources-bookmarklet.js]
skip-if = e10s && debug
[browser_dbg_sources-webext-contentscript.js]
[browser_dbg_split-console-paused-reload.js]
skip-if = true # Bug 1288348 - previously e10s && debug
[browser_dbg_stack-01.js]
skip-if = e10s && debug
[browser_dbg_stack-02.js]
skip-if = e10s && debug
[browser_dbg_stack-03.js]
skip-if = e10s # TODO
[browser_dbg_stack-04.js]
skip-if = e10s && debug
[browser_dbg_stack-05.js]
skip-if = e10s && (debug || asan) # timeouts
[browser_dbg_stack-06.js]
skip-if = e10s && debug
[browser_dbg_stack-07.js]
skip-if = e10s && debug
[browser_dbg_stack-contextmenu-01.js]
skip-if = e10s && debug
[browser_dbg_stack-contextmenu-02.js]
subsuite = clipboard
skip-if = e10s && debug
[browser_dbg_step-out.js]
skip-if = e10s && debug
[browser_dbg_tabactor-01.js]
skip-if = e10s # TODO
[browser_dbg_tabactor-02.js]
skip-if = e10s # TODO
[browser_dbg_terminate-on-tab-close.js]
skip-if = e10s && debug
[browser_dbg_variables-view-01.js]
skip-if = e10s && debug
[browser_dbg_variables-view-02.js]
skip-if = e10s && debug
[browser_dbg_variables-view-03.js]
skip-if = e10s && debug
[browser_dbg_variables-view-04.js]
skip-if = e10s && debug
[browser_dbg_variables-view-05.js]
skip-if = e10s && debug
[browser_dbg_variables-view-06.js]
skip-if = e10s && debug
[browser_dbg_variables-view-07.js]
skip-if = e10s && debug
[browser_dbg_variables-view-08.js]
skip-if = e10s && debug
[browser_dbg_variables-view-accessibility.js]
subsuite = clipboard
skip-if = e10s && debug
[browser_dbg_variables-view-data.js]
skip-if = e10s && debug
[browser_dbg_variables-view-edit-cancel.js]
skip-if = e10s && debug
[browser_dbg_variables-view-edit-click.js]
skip-if = e10s || (os == 'mac' || os == 'win') && (debug == false) # Bug 986166
[browser_dbg_variables-view-edit-getset-01.js]
skip-if = e10s && debug
[browser_dbg_variables-view-edit-getset-02.js]
skip-if = e10s && debug
[browser_dbg_variables-view-edit-value.js]
skip-if = e10s && debug
[browser_dbg_variables-view-edit-watch.js]
skip-if = e10s && debug
[browser_dbg_variables-view-filter-01.js]
skip-if = e10s && debug
[browser_dbg_variables-view-filter-02.js]
skip-if = e10s && debug
[browser_dbg_variables-view-filter-03.js]
skip-if = e10s && debug
[browser_dbg_variables-view-filter-04.js]
skip-if = e10s && debug
[browser_dbg_variables-view-filter-05.js]
skip-if = e10s && debug
[browser_dbg_variables-view-filter-pref.js]
skip-if = e10s && debug
[browser_dbg_variables-view-filter-searchbox.js]
skip-if = e10s && debug
[browser_dbg_variables-view-frame-parameters-01.js]
skip-if = e10s && debug
[browser_dbg_variables-view-frame-parameters-02.js]
skip-if = e10s && debug
[browser_dbg_variables-view-frame-parameters-03.js]
skip-if = e10s && debug
[browser_dbg_variables-view-frame-with.js]
skip-if = e10s && debug
[browser_dbg_variables-view-frozen-sealed-nonext.js]
skip-if = e10s && debug
[browser_dbg_variables-view-hide-non-enums.js]
[browser_dbg_variables-view-large-array-buffer.js]
[browser_dbg_variables-view-map-set.js]
skip-if = e10s && debug
[browser_dbg_variables-view-override-01.js]
skip-if = e10s && debug
[browser_dbg_variables-view-override-02.js]
skip-if = e10s && debug
[browser_dbg_variables-view-popup-01.js]
skip-if = e10s && debug
[browser_dbg_variables-view-popup-02.js]
skip-if = e10s && debug
[browser_dbg_variables-view-popup-03.js]
skip-if = e10s && debug
[browser_dbg_variables-view-popup-04.js]
skip-if = e10s && debug
[browser_dbg_variables-view-popup-05.js]
skip-if = e10s && debug
[browser_dbg_variables-view-popup-06.js]
skip-if = e10s && debug
[browser_dbg_variables-view-popup-07.js]
skip-if = e10s && debug
[browser_dbg_variables-view-popup-08.js]
skip-if = e10s && debug
[browser_dbg_variables-view-popup-09.js]
skip-if = e10s && debug
[browser_dbg_variables-view-popup-10.js]
skip-if = e10s && debug
[browser_dbg_variables-view-popup-11.js]
skip-if = e10s && debug
[browser_dbg_variables-view-popup-12.js]
skip-if = e10s && debug
[browser_dbg_variables-view-popup-13.js]
skip-if = e10s && debug
[browser_dbg_variables-view-popup-14.js]
skip-if = true # Bug 1029545
[browser_dbg_variables-view-popup-15.js]
skip-if = e10s && debug
[browser_dbg_variables-view-popup-16.js]
skip-if = e10s && debug
[browser_dbg_variables-view-popup-17.js]
skip-if = e10s && debug
[browser_dbg_variables-view-reexpand-01.js]
skip-if = e10s && debug
[browser_dbg_variables-view-reexpand-02.js]
skip-if = e10s && debug
[browser_dbg_variables-view-reexpand-03.js]
skip-if = e10s && debug
[browser_dbg_variables-view-webidl.js]
skip-if = e10s && debug
[browser_dbg_watch-expressions-01.js]
skip-if = e10s && debug
[browser_dbg_watch-expressions-02.js]
skip-if = e10s && debug
[browser_dbg_worker-console-01.js]
skip-if = e10s && debug
[browser_dbg_worker-console-02.js]
skip-if = e10s && debug
[browser_dbg_worker-console-03.js]
skip-if = e10s && debug
[browser_dbg_worker-source-map.js]
skip-if = e10s && debug
[browser_dbg_worker-window.js]
skip-if = e10s && debug
[browser_dbg_WorkerActor.attach.js]
skip-if = e10s && debug
[browser_dbg_WorkerActor.attachThread.js]
skip-if = e10s && debug
[browser_dbg_split-console-keypress.js]
skip-if = e10s && (debug || os == "linux") # Bug 1214439

View file

@ -0,0 +1,62 @@
var MAX_TOTAL_VIEWERS = "browser.sessionhistory.max_total_viewers";
var TAB1_URL = EXAMPLE_URL + "doc_WorkerActor.attach-tab1.html";
var TAB2_URL = EXAMPLE_URL + "doc_WorkerActor.attach-tab2.html";
var WORKER1_URL = "code_WorkerActor.attach-worker1.js";
var WORKER2_URL = "code_WorkerActor.attach-worker2.js";
function test() {
Task.spawn(function* () {
let oldMaxTotalViewers = SpecialPowers.getIntPref(MAX_TOTAL_VIEWERS);
SpecialPowers.setIntPref(MAX_TOTAL_VIEWERS, 10);
DebuggerServer.init();
DebuggerServer.addBrowserActors();
let client = new DebuggerClient(DebuggerServer.connectPipe());
yield connect(client);
let tab = yield addTab(TAB1_URL);
let { tabs } = yield listTabs(client);
let [, tabClient] = yield attachTab(client, findTab(tabs, TAB1_URL));
yield listWorkers(tabClient);
// If a page still has pending network requests, it will not be moved into
// the bfcache. Consequently, we cannot use waitForWorkerListChanged here,
// because the worker is not guaranteed to have finished loading when it is
// registered. Instead, we have to wait for the promise returned by
// createWorker in the tab to be resolved.
yield createWorkerInTab(tab, WORKER1_URL);
let { workers } = yield listWorkers(tabClient);
let [, workerClient1] = yield attachWorker(tabClient,
findWorker(workers, WORKER1_URL));
is(workerClient1.isClosed, false, "worker in tab 1 should not be closed");
executeSoon(() => {
tab.linkedBrowser.loadURI(TAB2_URL);
});
yield waitForWorkerClose(workerClient1);
is(workerClient1.isClosed, true, "worker in tab 1 should be closed");
yield createWorkerInTab(tab, WORKER2_URL);
({ workers } = yield listWorkers(tabClient));
let [, workerClient2] = yield attachWorker(tabClient,
findWorker(workers, WORKER2_URL));
is(workerClient2.isClosed, false, "worker in tab 2 should not be closed");
executeSoon(() => {
tab.linkedBrowser.contentWindow.history.back();
});
yield waitForWorkerClose(workerClient2);
is(workerClient2.isClosed, true, "worker in tab 2 should be closed");
({ workers } = yield listWorkers(tabClient));
[, workerClient1] = yield attachWorker(tabClient,
findWorker(workers, WORKER1_URL));
is(workerClient1.isClosed, false, "worker in tab 1 should not be closed");
yield close(client);
SpecialPowers.setIntPref(MAX_TOTAL_VIEWERS, oldMaxTotalViewers);
finish();
});
}

View file

@ -0,0 +1,100 @@
var TAB_URL = EXAMPLE_URL + "doc_WorkerActor.attachThread-tab.html";
var WORKER_URL = "code_WorkerActor.attachThread-worker.js";
function test() {
Task.spawn(function* () {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
let client1 = new DebuggerClient(DebuggerServer.connectPipe());
yield connect(client1);
let client2 = new DebuggerClient(DebuggerServer.connectPipe());
yield connect(client2);
let tab = yield addTab(TAB_URL);
let { tabs: tabs1 } = yield listTabs(client1);
let [, tabClient1] = yield attachTab(client1, findTab(tabs1, TAB_URL));
let { tabs: tabs2 } = yield listTabs(client2);
let [, tabClient2] = yield attachTab(client2, findTab(tabs2, TAB_URL));
yield listWorkers(tabClient1);
yield listWorkers(tabClient2);
yield createWorkerInTab(tab, WORKER_URL);
let { workers: workers1 } = yield listWorkers(tabClient1);
let [, workerClient1] = yield attachWorker(tabClient1,
findWorker(workers1, WORKER_URL));
let { workers: workers2 } = yield listWorkers(tabClient2);
let [, workerClient2] = yield attachWorker(tabClient2,
findWorker(workers2, WORKER_URL));
let location = { line: 5 };
let [, threadClient1] = yield attachThread(workerClient1);
let sources1 = yield getSources(threadClient1);
let sourceClient1 = threadClient1.source(findSource(sources1,
EXAMPLE_URL + WORKER_URL));
let [, breakpointClient1] = yield setBreakpoint(sourceClient1, location);
yield resume(threadClient1);
let [, threadClient2] = yield attachThread(workerClient2);
let sources2 = yield getSources(threadClient2);
let sourceClient2 = threadClient2.source(findSource(sources2,
EXAMPLE_URL + WORKER_URL));
let [, breakpointClient2] = yield setBreakpoint(sourceClient2, location);
yield resume(threadClient2);
let packet = yield source(sourceClient1);
let text = (yield new Promise(function (resolve) {
let request = new XMLHttpRequest();
request.open("GET", EXAMPLE_URL + WORKER_URL, true);
request.send();
request.onload = function () {
resolve(request.responseText);
};
}));
is(packet.source, text);
postMessageToWorkerInTab(tab, WORKER_URL, "ping");
yield Promise.all([
waitForPause(threadClient1).then((packet) => {
is(packet.type, "paused");
let why = packet.why;
is(why.type, "breakpoint");
is(why.actors.length, 1);
is(why.actors[0], breakpointClient1.actor);
let frame = packet.frame;
let where = frame.where;
is(where.source.actor, sourceClient1.actor);
is(where.line, location.line);
let variables = frame.environment.bindings.variables;
is(variables.a.value, 1);
is(variables.b.value.type, "undefined");
is(variables.c.value.type, "undefined");
return resume(threadClient1);
}),
waitForPause(threadClient2).then((packet) => {
is(packet.type, "paused");
let why = packet.why;
is(why.type, "breakpoint");
is(why.actors.length, 1);
is(why.actors[0], breakpointClient2.actor);
let frame = packet.frame;
let where = frame.where;
is(where.source.actor, sourceClient2.actor);
is(where.line, location.line);
let variables = frame.environment.bindings.variables;
is(variables.a.value, 1);
is(variables.b.value.type, "undefined");
is(variables.c.value.type, "undefined");
return resume(threadClient2);
}),
]);
terminateWorkerInTab(tab, WORKER_URL);
yield waitForWorkerClose(workerClient1);
yield waitForWorkerClose(workerClient2);
yield close(client1);
yield close(client2);
finish();
});
}

View file

@ -0,0 +1,33 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* This tests if the debugger leaks on initialization and sudden destruction.
* You can also use this initialization format as a template for other tests.
* If leaks happen here, there's something very, very fishy going on.
*/
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
// Wait longer for this very simple test that comes first, to make sure that
// GC from previous tests does not interfere with the debugger suite.
requestLongerTimeout(2);
let options = {
source: EXAMPLE_URL + "code_script-switching-01.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
ok(aTab, "Should have a tab available.");
ok(aPanel, "Should have a debugger pane available.");
waitForSourceAndCaretAndScopes(aPanel, "-02.js", 1).then(() => {
resumeDebuggerThenCloseAndFinish(aPanel);
});
callInTab(aTab, "firstCall");
});
}

View file

@ -0,0 +1,47 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Test that the we can see console messages from the add-on
const ADDON_ID = "browser_dbg_addon4@tests.mozilla.org";
const ADDON_PATH = "addon4.xpi";
function getCachedMessages(webConsole) {
let deferred = promise.defer();
webConsole.getCachedMessages(["ConsoleAPI"], (aResponse) => {
if (aResponse.error) {
deferred.reject(aResponse.error);
return;
}
deferred.resolve(aResponse.messages);
});
return deferred.promise;
}
function test() {
Task.spawn(function* () {
let addon = yield addTemporaryAddon(ADDON_PATH);
let addonDebugger = yield initAddonDebugger(ADDON_ID);
let webConsole = addonDebugger.webConsole;
let messages = yield getCachedMessages(webConsole);
is(messages.length, 1, "Should be one cached message");
is(messages[0].arguments[0].type, "object", "Should have logged an object");
is(messages[0].arguments[0].preview.ownProperties.msg.value, "Hello from the test add-on", "Should have got the right message");
let consolePromise = addonDebugger.once("console");
console.log("Bad message");
Services.obs.notifyObservers(null, "addon-test-ping", "");
let messageGrip = yield consolePromise;
is(messageGrip.arguments[0].type, "object", "Should have logged an object");
is(messageGrip.arguments[0].preview.ownProperties.msg.value, "Hello again", "Should have got the right message");
yield addonDebugger.destroy();
yield removeAddon(addon);
finish();
});
}

View file

@ -0,0 +1,67 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Make sure the add-on actor can see loaded JS Modules from an add-on
const ADDON_ID = "browser_dbg_addon5@tests.mozilla.org";
const ADDON_PATH = "addon-source/browser_dbg_addon5/";
const ADDON_URL = getTemporaryAddonURLFromPath(ADDON_PATH);
function test() {
Task.spawn(function* () {
let addon = yield addTemporaryAddon(ADDON_PATH);
let tab1 = yield addTab("chrome://browser_dbg_addon5/content/test.xul");
let addonDebugger = yield initAddonDebugger(ADDON_ID);
is(addonDebugger.title,
`Developer Tools - Test unpacked add-on with JS Modules - ${ADDON_URL}`,
"Saw the right toolbox title.");
// Check the inital list of sources is correct
let groups = yield addonDebugger.getSourceGroups();
is(groups[0].name, "browser_dbg_addon5@tests.mozilla.org", "Add-on code should be the first group");
is(groups[1].name, "chrome://global", "XUL code should be the second group");
is(groups.length, 2, "Should be only two groups.");
let sources = groups[0].sources;
is(sources.length, 3, "Should be three sources");
ok(sources[0].url.endsWith("/browser_dbg_addon5/bootstrap.js"), "correct url for bootstrap code");
is(sources[0].label, "bootstrap.js", "correct label for bootstrap code");
is(sources[1].url, "resource://browser_dbg_addon5/test.jsm", "correct url for addon code");
is(sources[1].label, "test.jsm", "correct label for addon code");
is(sources[2].url, "chrome://browser_dbg_addon5/content/testxul.js", "correct url for addon tab code");
is(sources[2].label, "testxul.js", "correct label for addon tab code");
// Load a new module and tab and check they appear in the list of sources
Cu.import("resource://browser_dbg_addon5/test2.jsm", {});
let tab2 = yield addTab("chrome://browser_dbg_addon5/content/test2.xul");
groups = yield addonDebugger.getSourceGroups();
is(groups[0].name, "browser_dbg_addon5@tests.mozilla.org", "Add-on code should be the first group");
is(groups[1].name, "chrome://global", "XUL code should be the second group");
is(groups.length, 2, "Should be only two groups.");
sources = groups[0].sources;
is(sources.length, 5, "Should be five sources");
ok(sources[0].url.endsWith("/browser_dbg_addon5/bootstrap.js"), "correct url for bootstrap code");
is(sources[0].label, "bootstrap.js", "correct label for bootstrap code");
is(sources[1].url, "resource://browser_dbg_addon5/test.jsm", "correct url for addon code");
is(sources[1].label, "test.jsm", "correct label for addon code");
is(sources[2].url, "chrome://browser_dbg_addon5/content/testxul.js", "correct url for addon tab code");
is(sources[2].label, "testxul.js", "correct label for addon tab code");
is(sources[3].url, "resource://browser_dbg_addon5/test2.jsm", "correct url for addon code");
is(sources[3].label, "test2.jsm", "correct label for addon code");
is(sources[4].url, "chrome://browser_dbg_addon5/content/testxul2.js", "correct url for addon tab code");
is(sources[4].label, "testxul2.js", "correct label for addon tab code");
Cu.unload("resource://browser_dbg_addon5/test2.jsm");
yield addonDebugger.destroy();
yield removeTab(tab1);
yield removeTab(tab2);
yield removeAddon(addon);
finish();
});
}

View file

@ -0,0 +1,66 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Make sure the add-on actor can see loaded JS Modules from an add-on
const ADDON_ID = "browser_dbg_addon4@tests.mozilla.org";
const ADDON_PATH = "addon4.xpi";
const ADDON_URL = getTemporaryAddonURLFromPath(ADDON_PATH);
function test() {
Task.spawn(function* () {
let addon = yield addTemporaryAddon(ADDON_PATH);
let tab1 = yield addTab("chrome://browser_dbg_addon4/content/test.xul");
let addonDebugger = yield initAddonDebugger(ADDON_ID);
is(addonDebugger.title, `Developer Tools - Test add-on with JS Modules - ${ADDON_URL}`,
"Saw the right toolbox title.");
// Check the inital list of sources is correct
let groups = yield addonDebugger.getSourceGroups();
is(groups[0].name, "browser_dbg_addon4@tests.mozilla.org", "Add-on code should be the first group");
is(groups[1].name, "chrome://global", "XUL code should be the second group");
is(groups.length, 2, "Should be only two groups.");
let sources = groups[0].sources;
is(sources.length, 3, "Should be three sources");
ok(sources[0].url.endsWith("/addon4.xpi!/bootstrap.js"), "correct url for bootstrap code");
is(sources[0].label, "bootstrap.js", "correct label for bootstrap code");
is(sources[1].url, "resource://browser_dbg_addon4/test.jsm", "correct url for addon code");
is(sources[1].label, "test.jsm", "correct label for addon code");
is(sources[2].url, "chrome://browser_dbg_addon4/content/testxul.js", "correct url for addon tab code");
is(sources[2].label, "testxul.js", "correct label for addon tab code");
// Load a new module and tab and check they appear in the list of sources
Cu.import("resource://browser_dbg_addon4/test2.jsm", {});
let tab2 = yield addTab("chrome://browser_dbg_addon4/content/test2.xul");
groups = yield addonDebugger.getSourceGroups();
is(groups[0].name, "browser_dbg_addon4@tests.mozilla.org", "Add-on code should be the first group");
is(groups[1].name, "chrome://global", "XUL code should be the second group");
is(groups.length, 2, "Should be only two groups.");
sources = groups[0].sources;
is(sources.length, 5, "Should be five sources");
ok(sources[0].url.endsWith("/addon4.xpi!/bootstrap.js"), "correct url for bootstrap code");
is(sources[0].label, "bootstrap.js", "correct label for bootstrap code");
is(sources[1].url, "resource://browser_dbg_addon4/test.jsm", "correct url for addon code");
is(sources[1].label, "test.jsm", "correct label for addon code");
is(sources[2].url, "chrome://browser_dbg_addon4/content/testxul.js", "correct url for addon tab code");
is(sources[2].label, "testxul.js", "correct label for addon tab code");
is(sources[3].url, "resource://browser_dbg_addon4/test2.jsm", "correct url for addon code");
is(sources[3].label, "test2.jsm", "correct label for addon code");
is(sources[4].url, "chrome://browser_dbg_addon4/content/testxul2.js", "correct url for addon tab code");
is(sources[4].label, "testxul2.js", "correct label for addon tab code");
Cu.unload("resource://browser_dbg_addon4/test2.jsm");
yield addonDebugger.destroy();
yield removeTab(tab1);
yield removeTab(tab2);
yield removeAddon(addon);
finish();
});
}

View file

@ -0,0 +1,49 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Ensure that only panels that are relevant to the addon debugger
// display in the toolbox
const ADDON_ID = "jid1-ami3akps3baaeg@jetpack";
const ADDON_PATH = "addon3.xpi";
var gAddon, gClient, gThreadClient, gDebugger, gSources;
var PREFS = [
["devtools.canvasdebugger.enabled", true],
["devtools.shadereditor.enabled", true],
["devtools.performance.enabled", true],
["devtools.netmonitor.enabled", true],
["devtools.scratchpad.enabled", true]
];
function test() {
Task.spawn(function* () {
// Store and enable all optional dev tools panels
yield pushPrefs(...PREFS);
let addon = yield addTemporaryAddon(ADDON_PATH);
let addonDebugger = yield initAddonDebugger(ADDON_ID);
// Check only valid tabs are shown
let tabs = addonDebugger.frame.contentDocument.getElementById("toolbox-tabs").children;
let expectedTabs = ["webconsole", "jsdebugger", "scratchpad"];
is(tabs.length, expectedTabs.length, "displaying only " + expectedTabs.length + " tabs in addon debugger");
Array.forEach(tabs, (tab, i) => {
let toolName = expectedTabs[i];
is(tab.getAttribute("toolid"), toolName, "displaying " + toolName);
});
// Check no toolbox buttons are shown
let buttons = addonDebugger.frame.contentDocument.getElementById("toolbox-buttons").children;
Array.forEach(buttons, (btn, i) => {
is(btn.hidden, true, "no toolbox buttons for the addon debugger -- " + btn.className);
});
yield addonDebugger.destroy();
yield removeAddon(addon);
finish();
});
}

View file

@ -0,0 +1,42 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Ensure that the sources listed when debugging an addon are either from the
// addon itself, or the SDK, with proper groups and labels.
const ADDON_ID = "jid1-ami3akps3baaeg@jetpack";
const ADDON_PATH = "addon3.xpi";
const ADDON_URL = getTemporaryAddonURLFromPath(ADDON_PATH);
var gClient;
function test() {
Task.spawn(function* () {
let addon = yield addTemporaryAddon(ADDON_PATH);
let addonDebugger = yield initAddonDebugger(ADDON_ID);
is(addonDebugger.title, `Developer Tools - browser_dbg_addon3 - ${ADDON_URL}`,
"Saw the right toolbox title.");
// Check the inital list of sources is correct
let groups = yield addonDebugger.getSourceGroups();
is(groups[0].name, "jid1-ami3akps3baaeg@jetpack", "Add-on code should be the first group");
is(groups[1].name, "Add-on SDK", "Add-on SDK should be the second group");
is(groups.length, 2, "Should be only two groups.");
let sources = groups[0].sources;
is(sources.length, 2, "Should be two sources");
ok(sources[0].url.endsWith("/addon3.xpi!/bootstrap.js"), "correct url for bootstrap code");
is(sources[0].label, "bootstrap.js", "correct label for bootstrap code");
is(sources[1].url, "resource://jid1-ami3akps3baaeg-at-jetpack/browser_dbg_addon3/lib/main.js", "correct url for add-on code");
is(sources[1].label, "resources/browser_dbg_addon3/lib/main.js", "correct label for add-on code");
ok(groups[1].sources.length > 10, "SDK modules are listed");
yield addonDebugger.destroy();
yield removeAddon(addon);
finish();
});
}

View file

@ -0,0 +1,41 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the Addon Debugger works when devtools.debugger.workers is enabled.
// Workers controller cannot be used when debugging an Addon actor.
const ADDON_ID = "jid1-ami3akps3baaeg@jetpack";
const ADDON_PATH = "addon3.xpi";
const ADDON_URL = getTemporaryAddonURLFromPath(ADDON_PATH);
function test() {
Task.spawn(function* () {
info("Enable worker debugging.");
yield new Promise(resolve => {
SpecialPowers.pushPrefEnv({
"set": [["devtools.debugger.workers", true]]
}, resolve);
});
let addon = yield addTemporaryAddon(ADDON_PATH);
let addonDebugger = yield initAddonDebugger(ADDON_ID);
is(addonDebugger.title,
`Developer Tools - browser_dbg_addon3 - ${ADDON_URL}`,
"Saw the right toolbox title.");
info("Check that groups and sources are displayed.");
let groups = yield addonDebugger.getSourceGroups();
is(groups.length, 2, "Should be only two groups.");
let sources = groups[0].sources;
is(sources.length, 2, "Should be two sources");
yield addonDebugger.destroy();
yield removeAddon(addon);
finish();
});
}

View file

@ -0,0 +1,95 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Make sure we can attach to addon actors.
const ADDON3_PATH = "addon3.xpi";
const ADDON3_ID = "jid1-ami3akps3baaeg@jetpack";
const ADDON_MODULE_URL = "resource://jid1-ami3akps3baaeg-at-jetpack/browser_dbg_addon3/lib/main.js";
var gAddon, gClient, gThreadClient;
function test() {
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect().then(([aType, aTraits]) => {
is(aType, "browser",
"Root actor should identify itself as a browser.");
installAddon()
.then(attachAddonActorForId.bind(null, gClient, ADDON3_ID))
.then(attachAddonThread)
.then(testDebugger)
.then(testSources)
.then(() => gClient.close())
.then(uninstallAddon)
.then(finish)
.then(null, aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
});
}
function installAddon() {
return addTemporaryAddon(ADDON3_PATH).then(aAddon => {
gAddon = aAddon;
});
}
function attachAddonThread([aGrip, aResponse]) {
info("attached addon actor for Addon ID");
let deferred = promise.defer();
gClient.attachThread(aResponse.threadActor, (aResponse, aThreadClient) => {
info("attached thread");
gThreadClient = aThreadClient;
gThreadClient.resume(deferred.resolve);
});
return deferred.promise;
}
function testDebugger() {
info("Entering testDebugger");
let deferred = promise.defer();
once(gClient, "paused").then(() => {
ok(true, "Should be able to attach to addon actor");
gThreadClient.resume(deferred.resolve);
});
Services.obs.notifyObservers(null, "debuggerAttached", null);
return deferred.promise;
}
function testSources() {
let deferred = promise.defer();
gThreadClient.getSources(aResponse => {
// source URLs contain launch-specific temporary directory path,
// hence the ".contains" call.
const matches = aResponse.sources.filter(s => s.url.includes(ADDON_MODULE_URL));
ok(matches.length > 0,
"the main script of the addon is present in the source list");
deferred.resolve();
});
return deferred.promise;
}
function uninstallAddon() {
return removeAddon(gAddon);
}
registerCleanupFunction(function () {
gClient = null;
gAddon = null;
gThreadClient = null;
});

View file

@ -0,0 +1,117 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Test auto pretty printing.
const TAB_URL = EXAMPLE_URL + "doc_auto-pretty-print-01.html";
var gTab, gPanel, gDebugger;
var gEditor, gSources, gPrefs, gOptions, gView;
var gFirstSource = EXAMPLE_URL + "code_ugly-5.js";
var gSecondSource = EXAMPLE_URL + "code_ugly-6.js";
var gOriginalPref = Services.prefs.getBoolPref("devtools.debugger.auto-pretty-print");
function test() {
let options = {
source: gFirstSource,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;
gSources = gDebugger.DebuggerView.Sources;
gPrefs = gDebugger.Prefs;
gOptions = gDebugger.DebuggerView.Options;
gView = gDebugger.DebuggerView;
Task.spawn(function* () {
testSourceIsUgly();
enableAutoPrettyPrint();
testAutoPrettyPrintOn();
reload(gPanel);
yield waitForSourceShown(gPanel, gFirstSource);
testSourceIsUgly();
yield waitForSourceShown(gPanel, gFirstSource);
testSourceIsPretty();
disableAutoPrettyPrint();
testAutoPrettyPrintOff();
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN);
gSources.selectedIndex = 1;
yield finished;
testSecondSourceLabel();
testSourceIsUgly();
enableAutoPrettyPrint();
yield closeDebuggerAndFinish(gPanel);
});
});
}
function testSourceIsUgly() {
ok(!gEditor.getText().includes("\n "),
"The source shouldn't be pretty printed yet.");
}
function testSecondSourceLabel() {
let source = gSources.selectedItem.attachment.source;
ok(source.url === gSecondSource,
"Second source url is correct.");
}
function testProgressBarShown() {
const deck = gDebugger.document.getElementById("editor-deck");
is(deck.selectedIndex, 2, "The progress bar should be shown");
}
function testAutoPrettyPrintOn() {
is(gPrefs.autoPrettyPrint, true,
"The auto-pretty-print pref should be on.");
is(gOptions._autoPrettyPrint.getAttribute("checked"), "true",
"The Auto pretty print menu item should be checked.");
}
function disableAutoPrettyPrint() {
gOptions._autoPrettyPrint.setAttribute("checked", "false");
gOptions._toggleAutoPrettyPrint();
gOptions._onPopupHidden();
}
function enableAutoPrettyPrint() {
gOptions._autoPrettyPrint.setAttribute("checked", "true");
gOptions._toggleAutoPrettyPrint();
gOptions._onPopupHidden();
}
function testAutoPrettyPrintOff() {
is(gPrefs.autoPrettyPrint, false,
"The auto-pretty-print pref should be off.");
isnot(gOptions._autoPrettyPrint.getAttribute("checked"), "true",
"The Auto pretty print menu item should not be checked.");
}
function testSourceIsPretty() {
ok(gEditor.getText().includes("\n "),
"The source should be pretty printed.");
}
registerCleanupFunction(function () {
gTab = null;
gPanel = null;
gDebugger = null;
gEditor = null;
gSources = null;
gOptions = null;
gPrefs = null;
gView = null;
Services.prefs.setBoolPref("devtools.debugger.auto-pretty-print", gOriginalPref);
});

View file

@ -0,0 +1,126 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that auto pretty printing doesn't accidentally toggle
* pretty printing off when we switch to a minified source
* that is already pretty printed.
*/
const TAB_URL = EXAMPLE_URL + "doc_auto-pretty-print-02.html";
var gTab, gDebuggee, gPanel, gDebugger;
var gEditor, gSources, gPrefs, gOptions, gView;
var gFirstSource = EXAMPLE_URL + "code_ugly-6.js";
var gSecondSource = EXAMPLE_URL + "code_ugly-7.js";
var gOriginalPref = Services.prefs.getBoolPref("devtools.debugger.auto-pretty-print");
Services.prefs.setBoolPref("devtools.debugger.auto-pretty-print", true);
function test() {
let options = {
source: gFirstSource,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aDebuggee, aPanel]) => {
const gTab = aTab;
const gDebuggee = aDebuggee;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gEditor = gDebugger.DebuggerView.editor;
const gSources = gDebugger.DebuggerView.Sources;
const gPrefs = gDebugger.Prefs;
const gOptions = gDebugger.DebuggerView.Options;
const gView = gDebugger.DebuggerView;
// Should be on by default.
testAutoPrettyPrintOn();
Task.spawn(function* () {
testSourceIsUgly();
yield waitForSourceShown(gPanel, gFirstSource);
testSourceIsPretty();
testPrettyPrintButtonOn();
// select second source
yield selectSecondSource();
testSecondSourceLabel();
// select first source
yield selectFirstSource();
testFirstSourceLabel();
testPrettyPrintButtonOn();
// Disable auto pretty printing so it does not affect the following tests.
yield disableAutoPrettyPrint();
closeDebuggerAndFinish(gPanel)
.then(null, aError => {
ok(false, "Got an error: " + DevToolsUtils.safeErrorString(aError));
});
});
function selectSecondSource() {
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN, 2);
gSources.selectedIndex = 1;
return finished;
}
function selectFirstSource() {
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN);
gSources.selectedIndex = 0;
return finished;
}
function testSourceIsUgly() {
ok(!gEditor.getText().includes("\n "),
"The source shouldn't be pretty printed yet.");
}
function testFirstSourceLabel() {
let source = gSources.selectedItem.attachment.source;
ok(source.url === gFirstSource,
"First source url is correct.");
}
function testSecondSourceLabel() {
let source = gSources.selectedItem.attachment.source;
ok(source.url === gSecondSource,
"Second source url is correct.");
}
function testAutoPrettyPrintOn() {
is(gPrefs.autoPrettyPrint, true,
"The auto-pretty-print pref should be on.");
is(gOptions._autoPrettyPrint.getAttribute("checked"), "true",
"The Auto pretty print menu item should be checked.");
}
function testPrettyPrintButtonOn() {
is(gDebugger.document.getElementById("pretty-print").checked, true,
"The button should be checked when the source is selected.");
}
function disableAutoPrettyPrint() {
gOptions._autoPrettyPrint.setAttribute("checked", "false");
gOptions._toggleAutoPrettyPrint();
gOptions._onPopupHidden();
info("Disabled auto pretty printing.");
}
function testSourceIsPretty() {
ok(gEditor.getText().includes("\n "),
"The source should be pretty printed.");
}
registerCleanupFunction(function () {
Services.prefs.setBoolPref("devtools.debugger.auto-pretty-print", gOriginalPref);
});
});
}

View file

@ -0,0 +1,58 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* If auto pretty-printing it enabled, make sure that if
* pretty-printing fails that it still properly shows the original
* source.
*/
const TAB_URL = EXAMPLE_URL + "doc_auto-pretty-print-02.html";
var FIRST_SOURCE = EXAMPLE_URL + "code_ugly-6.js";
var SECOND_SOURCE = EXAMPLE_URL + "code_ugly-7.js";
function test() {
let options = {
source: FIRST_SOURCE,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aDebuggee, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gController = gDebugger.DebuggerController;
const gEditor = gDebugger.DebuggerView.editor;
const constants = gDebugger.require("./content/constants");
const queries = gDebugger.require("./content/queries");
const actions = bindActionCreators(gPanel);
Task.spawn(function* () {
const secondSource = queries.getSourceByURL(gController.getState(), SECOND_SOURCE);
actions.selectSource(secondSource);
// It should be showing the loading text
is(gEditor.getText(), gDebugger.DebuggerView._loadingText,
"The editor loading text is shown");
gController.dispatch({
type: constants.TOGGLE_PRETTY_PRINT,
status: "error",
source: secondSource,
});
is(gEditor.getText(), gDebugger.DebuggerView._loadingText,
"The editor loading text is shown");
yield waitForSourceShown(gPanel, SECOND_SOURCE);
ok(gEditor.getText().includes("function foo"),
"The second source is shown");
yield closeDebuggerAndFinish(gPanel);
});
});
}

View file

@ -0,0 +1,95 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that the debugger is updated with the correct sources when moving
* back and forward in the tab.
*/
const TAB_URL_1 = EXAMPLE_URL + "doc_script-switching-01.html";
const TAB_URL_2 = EXAMPLE_URL + "doc_recursion-stack.html";
var gTab, gDebuggee, gPanel, gDebugger;
var gSources;
const test = Task.async(function* () {
info("Starting browser_dbg_bfcache.js's `test`.");
let options = {
source: EXAMPLE_URL + "code_script-switching-01.js",
line: 1
};
([gTab, gDebuggee, gPanel]) = yield initDebugger(TAB_URL_1, options);
gDebugger = gPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;
yield testFirstPage();
yield testLocationChange();
yield testBack();
yield testForward();
return closeDebuggerAndFinish(gPanel);
});
function testFirstPage() {
info("Testing first page.");
// Spin the event loop before causing the debuggee to pause, to allow
// this function to return first.
executeSoon(() => gDebuggee.firstCall());
return waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1)
.then(validateFirstPage);
}
function testLocationChange() {
info("Navigating to a different page.");
return navigateActiveTabTo(gPanel,
TAB_URL_2,
gDebugger.EVENTS.SOURCES_ADDED)
.then(validateSecondPage);
}
function testBack() {
info("Going back.");
return navigateActiveTabInHistory(gPanel,
"back",
gDebugger.EVENTS.SOURCES_ADDED)
.then(validateFirstPage);
}
function testForward() {
info("Going forward.");
return navigateActiveTabInHistory(gPanel,
"forward",
gDebugger.EVENTS.SOURCES_ADDED)
.then(validateSecondPage);
}
function validateFirstPage() {
is(gSources.itemCount, 2,
"Found the expected number of sources.");
ok(gSources.getItemForAttachment(e => e.label == "code_script-switching-01.js"),
"Found the first source label.");
ok(gSources.getItemForAttachment(e => e.label == "code_script-switching-02.js"),
"Found the second source label.");
}
function validateSecondPage() {
is(gSources.itemCount, 1,
"Found the expected number of sources.");
ok(gSources.getItemForAttachment(e => e.label == "doc_recursion-stack.html"),
"Found the single source label.");
}
registerCleanupFunction(function () {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gSources = null;
});

View file

@ -0,0 +1,57 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that if we black box a source and then refresh, it is still black boxed.
*/
const TAB_URL = EXAMPLE_URL + "doc_binary_search.html";
var gTab, gPanel, gDebugger;
function test() {
let options = {
source: EXAMPLE_URL + "code_binary_search.coffee",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
testBlackBoxSource()
.then(testBlackBoxReload)
.then(() => closeDebuggerAndFinish(gPanel))
.then(null, aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
});
}
function testBlackBoxSource() {
const bbButton = getBlackBoxButton(gPanel);
ok(!bbButton.checked, "Should not be black boxed by default");
return toggleBlackBoxing(gPanel).then(source => {
ok(source.isBlackBoxed, "The source should be black boxed now.");
ok(bbButton.checked, "The checkbox should no longer be checked.");
});
}
function testBlackBoxReload() {
return reloadActiveTab(gPanel, gDebugger.EVENTS.SOURCE_SHOWN).then(() => {
const bbButton = getBlackBoxButton(gPanel);
const selectedSource = getSelectedSourceElement(gPanel);
ok(bbButton.checked, "Should still be black boxed.");
ok(selectedSource.classList.contains("black-boxed"),
"'black-boxed' class should still be applied");
});
}
registerCleanupFunction(function () {
gTab = null;
gPanel = null;
gDebugger = null;
});

View file

@ -0,0 +1,60 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that black boxed frames are compressed into a single frame on the stack
* view.
*/
const TAB_URL = EXAMPLE_URL + "doc_blackboxing.html";
const BLACKBOXME_URL = EXAMPLE_URL + "code_blackboxing_blackboxme.js";
var gTab, gPanel, gDebugger;
var gFrames;
function test() {
let options = {
source: BLACKBOXME_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gFrames = gDebugger.DebuggerView.StackFrames;
testBlackBoxSource()
.then(testBlackBoxStack)
.then(() => resumeDebuggerThenCloseAndFinish(gPanel))
.then(null, aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
});
}
function testBlackBoxSource() {
return toggleBlackBoxing(gPanel).then(source => {
ok(source.isBlackBoxed, "The source should be black boxed now.");
});
}
function testBlackBoxStack() {
let finished = waitForSourceAndCaretAndScopes(gPanel, ".html", 21).then(() => {
is(gFrames.itemCount, 3,
"Should only get 3 frames.");
is(gDebugger.document.querySelectorAll(".dbg-stackframe-black-boxed").length, 1,
"And one of them should be the combined black boxed frames.");
});
callInTab(gTab, "runTest");
return finished;
}
registerCleanupFunction(function () {
gTab = null;
gPanel = null;
gDebugger = null;
gFrames = null;
});

View file

@ -0,0 +1,65 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that black boxed frames are compressed into a single frame on the stack
* view when we are already paused.
*/
const TAB_URL = EXAMPLE_URL + "doc_blackboxing.html";
const BLACKBOXME_URL = EXAMPLE_URL + "code_blackboxing_blackboxme.js";
var gTab, gPanel, gDebugger;
var gFrames, gSources;
function test() {
let options = {
source: BLACKBOXME_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gFrames = gDebugger.DebuggerView.StackFrames;
gSources = gDebugger.DebuggerView.Sources;
waitForSourceAndCaretAndScopes(gPanel, ".html", 21)
.then(testBlackBoxStack)
.then(testBlackBoxSource)
.then(() => resumeDebuggerThenCloseAndFinish(gPanel))
.then(null, aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
callInTab(gTab, "runTest");
});
}
function testBlackBoxStack() {
is(gFrames.itemCount, 6,
"Should get 6 frames.");
is(gDebugger.document.querySelectorAll(".dbg-stackframe-black-boxed").length, 0,
"And none of them are black boxed.");
}
function testBlackBoxSource() {
return toggleBlackBoxing(gPanel, getSourceActor(gSources, BLACKBOXME_URL)).then(aSource => {
ok(aSource.isBlackBoxed, "The source should be black boxed now.");
is(gFrames.itemCount, 3,
"Should only get 3 frames.");
is(gDebugger.document.querySelectorAll(".dbg-stackframe-black-boxed").length, 1,
"And one of them should be the combined black boxed frames.");
});
}
registerCleanupFunction(function () {
gTab = null;
gPanel = null;
gDebugger = null;
gFrames = null;
gSources = null;
});

View file

@ -0,0 +1,65 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that we get a stack frame for each black boxed source, not a single one
* for all of them.
*/
const TAB_URL = EXAMPLE_URL + "doc_blackboxing.html";
const BLACKBOXME_URL = EXAMPLE_URL + "code_blackboxing_blackboxme.js";
var gTab, gPanel, gDebugger;
var gFrames, gSources;
function test() {
let options = {
source: BLACKBOXME_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gFrames = gDebugger.DebuggerView.StackFrames;
gSources = gDebugger.DebuggerView.Sources;
blackBoxSources()
.then(testBlackBoxStack)
.then(() => resumeDebuggerThenCloseAndFinish(gPanel))
.then(null, aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
});
}
function blackBoxSources() {
let finished = waitForThreadEvents(gPanel, "blackboxchange", 3);
toggleBlackBoxing(gPanel, getSourceActor(gSources, EXAMPLE_URL + "code_blackboxing_one.js"));
toggleBlackBoxing(gPanel, getSourceActor(gSources, EXAMPLE_URL + "code_blackboxing_two.js"));
toggleBlackBoxing(gPanel, getSourceActor(gSources, EXAMPLE_URL + "code_blackboxing_three.js"));
return finished;
}
function testBlackBoxStack() {
let finished = waitForSourceAndCaretAndScopes(gPanel, ".html", 21).then(() => {
is(gFrames.itemCount, 4,
"Should get 4 frames (one -> two -> three -> doDebuggerStatement).");
is(gDebugger.document.querySelectorAll(".dbg-stackframe-black-boxed").length, 3,
"And 'one', 'two', and 'three' should each have their own black boxed frame.");
});
callInTab(gTab, "one");
return finished;
}
registerCleanupFunction(function () {
gTab = null;
gPanel = null;
gDebugger = null;
gFrames = null;
gSources = null;
});

View file

@ -0,0 +1,74 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that a "this source is blackboxed" message is shown when necessary
* and can be properly dismissed.
*/
const TAB_URL = EXAMPLE_URL + "doc_binary_search.html";
var gTab, gPanel, gDebugger;
var gDeck;
function test() {
let options = {
source: EXAMPLE_URL + "code_binary_search.coffee",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gDeck = gDebugger.document.getElementById("editor-deck");
testSourceEditorShown();
toggleBlackBoxing(gPanel)
.then(testBlackBoxMessageShown)
.then(clickStopBlackBoxingButton)
.then(testSourceEditorShownAgain)
.then(() => closeDebuggerAndFinish(gPanel))
.then(null, aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
});
}
function testSourceEditorShown() {
is(gDeck.selectedIndex, "0",
"The first item in the deck should be selected (the source editor).");
}
function testBlackBoxMessageShown() {
is(gDeck.selectedIndex, "1",
"The second item in the deck should be selected (the black box message).");
}
function clickStopBlackBoxingButton() {
// Give the test a chance to finish before triggering the click event.
executeSoon(() => getEditorBlackboxMessageButton().click());
return waitForDispatch(gPanel, gDebugger.constants.BLACKBOX);
}
function testSourceEditorShownAgain() {
// Wait a tick for the final check to make sure the frontend's click handlers
// have finished.
return new Promise(resolve => {
is(gDeck.selectedIndex, "0",
"The first item in the deck should be selected again (the source editor).");
resolve();
});
}
function getEditorBlackboxMessageButton() {
return gDebugger.document.getElementById("black-boxed-message-button");
}
registerCleanupFunction(function () {
gTab = null;
gPanel = null;
gDebugger = null;
gDeck = null;
});

View file

@ -0,0 +1,61 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that clicking the black box checkbox when paused doesn't re-select the
* currently paused frame's source.
*/
const TAB_URL = EXAMPLE_URL + "doc_blackboxing.html";
var gTab, gPanel, gDebugger;
var gSources;
function test() {
let options = {
source: EXAMPLE_URL + "code_blackboxing_blackboxme.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;
waitForCaretAndScopes(gPanel, 21)
.then(testBlackBox)
.then(() => resumeDebuggerThenCloseAndFinish(gPanel))
.then(null, aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
callInTab(gTab, "runTest");
});
}
function testBlackBox() {
const selectedActor = gSources.selectedValue;
let finished = waitForSourceShown(gPanel, "blackboxme.js").then(() => {
const newSelectedActor = gSources.selectedValue;
isnot(selectedActor, newSelectedActor,
"Should not have the same url selected.");
return toggleBlackBoxing(gPanel).then(() => {
is(gSources.selectedValue, newSelectedActor,
"The selected source did not change.");
});
});
gSources.selectedIndex = 0;
return finished;
}
registerCleanupFunction(function () {
gTab = null;
gPanel = null;
gDebugger = null;
gSources = null;
});

View file

@ -0,0 +1,53 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that if we unblackbox a source which has been automatically blackboxed
* and then refresh, it is still unblackboxed.
*/
const TAB_URL = EXAMPLE_URL + "doc_blackboxing_unblackbox.html";
var gTab, gPanel, gDebugger;
function test() {
let options = {
source: EXAMPLE_URL + "code_blackboxing_unblackbox.min.js",
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
testBlackBoxSource()
.then(testBlackBoxReload)
.then(() => closeDebuggerAndFinish(gPanel))
.then(null, aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
});
}
function testBlackBoxSource() {
const bbButton = getBlackBoxButton(gPanel);
ok(bbButton.checked, "Should be black boxed by default");
return toggleBlackBoxing(gPanel).then(aSource => {
ok(!aSource.isBlackBoxed, "The source should no longer be blackboxed.");
});
}
function testBlackBoxReload() {
return reloadActiveTab(gPanel, gDebugger.EVENTS.SOURCE_SHOWN).then(() => {
const selectedSource = getSelectedSourceElement(gPanel);
ok(!selectedSource.isBlackBoxed, "The source should not be blackboxed.");
});
}
registerCleanupFunction(function () {
gTab = null;
gPanel = null;
gDebugger = null;
});

View file

@ -0,0 +1,98 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if the stackframe breadcrumbs are keyboard accessible.
*/
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
let gTab, gPanel, gDebugger;
let gSources, gFrames;
let options = {
source: EXAMPLE_URL + "code_script-switching-01.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;
gFrames = gDebugger.DebuggerView.StackFrames;
waitForSourceAndCaretAndScopes(gPanel, "-02.js", 6)
.then(checkNavigationWhileNotFocused)
.then(focusCurrentStackFrame)
.then(checkNavigationWhileFocused)
.then(() => resumeDebuggerThenCloseAndFinish(gPanel))
.then(null, aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
callInTab(gTab, "firstCall");
});
function checkNavigationWhileNotFocused() {
checkState({ frame: 1, source: 1, line: 6 });
return Task.spawn(function* () {
EventUtils.sendKey("DOWN", gDebugger);
checkState({ frame: 1, source: 1, line: 7 });
EventUtils.sendKey("UP", gDebugger);
checkState({ frame: 1, source: 1, line: 6 });
});
}
function focusCurrentStackFrame() {
EventUtils.sendMouseEvent({ type: "mousedown" },
gFrames.selectedItem.target,
gDebugger);
}
function checkNavigationWhileFocused() {
return Task.spawn(function* () {
yield promise.all([
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES),
waitForSourceAndCaret(gPanel, "-01.js", 5),
EventUtils.sendKey("UP", gDebugger)
]);
checkState({ frame: 0, source: 0, line: 5 });
// Need to refocus the stack frame due to a focus bug in e10s
// (See Bug 1205482)
focusCurrentStackFrame();
yield promise.all([
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES),
waitForSourceAndCaret(gPanel, "-02.js", 6),
EventUtils.sendKey("END", gDebugger)
]);
checkState({ frame: 1, source: 1, line: 6 });
// Need to refocus the stack frame due to a focus bug in e10s
// (See Bug 1205482)
focusCurrentStackFrame();
yield promise.all([
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES),
waitForSourceAndCaret(gPanel, "-01.js", 5),
EventUtils.sendKey("HOME", gDebugger)
]);
checkState({ frame: 0, source: 0, line: 5 });
});
}
function checkState({ frame, source, line, column }) {
is(gFrames.selectedIndex, frame,
"The currently selected stackframe is incorrect.");
is(gSources.selectedIndex, source,
"The currently selected source is incorrect.");
ok(isCaretPos(gPanel, line, column),
"The source editor caret position was incorrect.");
}
}

View file

@ -0,0 +1,40 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure anonymous eval scripts can still break with a `debugger`
* statement
*/
const TAB_URL = EXAMPLE_URL + "doc_script-eval.html";
function test() {
const options = {
source: EXAMPLE_URL + "code_script-eval.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gSources = gDebugger.DebuggerView.Sources;
return Task.spawn(function* () {
is(gSources.values.length, 1, "Should have 1 source");
callInTab(gTab, "evalSourceWithDebugger");
yield waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN);
is(gSources.values.length, 2, "Should have 2 sources");
let item = gSources.getItemForAttachment(e => e.label.indexOf("SCRIPT") === 0);
ok(item, "Source label is incorrect.");
is(item.attachment.group, gDebugger.L10N.getStr("anonymousSourcesLabel"),
"Source group is incorrect");
yield resumeDebuggerThenCloseAndFinish(gPanel);
});
});
}

View file

@ -0,0 +1,58 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Whitelisting this test.
// As part of bug 1077403, the leaking uncaught rejections should be fixed.
thisTestLeaksUncaughtRejectionsAndShouldBeFixed("[object Object]");
thisTestLeaksUncaughtRejectionsAndShouldBeFixed(
"TypeError: this.transport is null");
/**
* Tests that event listeners aren't fetched when the events tab isn't selected.
*/
const TAB_URL = EXAMPLE_URL + "doc_event-listeners-02.html";
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
let gPanel = aPanel;
let gDebugger = aPanel.panelWin;
let gView = gDebugger.DebuggerView;
let gEvents = gView.EventListeners;
let gController = gDebugger.DebuggerController;
let constants = gDebugger.require("./content/constants");
gDebugger.on(gDebugger.EVENTS.EVENT_LISTENERS_FETCHED, () => {
ok(false, "Shouldn't have fetched any event listeners.");
});
gDebugger.on(gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED, () => {
ok(false, "Shouldn't have updated any event breakpoints.");
});
gView.toggleInstrumentsPane({ visible: true, animated: false });
is(gView.instrumentsPaneHidden, false,
"The instruments pane should be visible now.");
is(gView.instrumentsPaneTab, "variables-tab",
"The variables tab should be selected by default.");
Task.spawn(function* () {
is(gEvents.itemCount, 0, "There should be no events before reloading.");
let reloaded = waitForNavigation(gPanel);
gDebugger.DebuggerController._target.activeTab.reload();
is(gEvents.itemCount, 0, "There should be no events while reloading.");
yield reloaded;
is(gEvents.itemCount, 0, "There should be no events after reloading.");
yield closeDebuggerAndFinish(aPanel);
});
});
}

View file

@ -0,0 +1,135 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that event listeners are fetched when the events tab is selected
* or while sources are fetched and the events tab is focused.
*/
const TAB_URL = EXAMPLE_URL + "doc_event-listeners-02.html";
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
let gPanel = aPanel;
let gDebugger = aPanel.panelWin;
let gView = gDebugger.DebuggerView;
let gEvents = gView.EventListeners;
let gController = gDebugger.DebuggerController;
let constants = gDebugger.require("./content/constants");
Task.spawn(function* () {
yield testFetchOnFocus();
yield testFetchOnReloadWhenFocused();
yield testFetchOnReloadWhenNotFocused();
yield closeDebuggerAndFinish(aPanel);
});
function testFetchOnFocus() {
return Task.spawn(function* () {
let fetched = waitForDispatch(aPanel, constants.FETCH_EVENT_LISTENERS);
gView.toggleInstrumentsPane({ visible: true, animated: false }, 1);
is(gView.instrumentsPaneHidden, false,
"The instruments pane should be visible now.");
is(gView.instrumentsPaneTab, "events-tab",
"The events tab should be selected.");
yield fetched;
ok(true,
"Event listeners were fetched when the events tab was selected");
is(gEvents.itemCount, 4,
"There should be 4 events displayed in the view.");
});
}
function testFetchOnReloadWhenFocused() {
return Task.spawn(function* () {
let fetched = waitForDispatch(aPanel, constants.FETCH_EVENT_LISTENERS);
let reloading = once(gDebugger.gTarget, "will-navigate");
let reloaded = waitForNavigation(gPanel);
gDebugger.DebuggerController._target.activeTab.reload();
yield reloading;
is(gEvents.itemCount, 0,
"There should be no events displayed in the view while reloading.");
ok(true,
"Event listeners were removed when the target started navigating.");
yield reloaded;
is(gView.instrumentsPaneHidden, false,
"The instruments pane should still be visible.");
is(gView.instrumentsPaneTab, "events-tab",
"The events tab should still be selected.");
yield fetched;
is(gEvents.itemCount, 4,
"There should be 4 events displayed in the view after reloading.");
ok(true,
"Event listeners were added back after the target finished navigating.");
});
}
function testFetchOnReloadWhenNotFocused() {
return Task.spawn(function* () {
gController.dispatch({
type: gDebugger.services.WAIT_UNTIL,
predicate: action => {
return (action.type === constants.FETCH_EVENT_LISTENERS ||
action.type === constants.UPDATE_EVENT_BREAKPOINTS);
},
run: (dispatch, getState, action) => {
if (action.type === constants.FETCH_EVENT_LISTENERS) {
ok(false, "Shouldn't have fetched any event listeners.");
}
else if (action.type === constants.UPDATE_EVENT_BREAKPOINTS) {
ok(false, "Shouldn't have updated any event breakpoints.");
}
}
});
gView.toggleInstrumentsPane({ visible: true, animated: false }, 0);
is(gView.instrumentsPaneHidden, false,
"The instruments pane should still be visible.");
is(gView.instrumentsPaneTab, "variables-tab",
"The variables tab should be selected.");
let reloading = once(gDebugger.gTarget, "will-navigate");
let reloaded = waitForNavigation(gPanel);
gDebugger.DebuggerController._target.activeTab.reload();
yield reloading;
is(gEvents.itemCount, 0,
"There should be no events displayed in the view while reloading.");
ok(true,
"Event listeners were removed when the target started navigating.");
yield reloaded;
is(gView.instrumentsPaneHidden, false,
"The instruments pane should still be visible.");
is(gView.instrumentsPaneTab, "variables-tab",
"The variables tab should still be selected.");
// Just to be really sure that the events will never ever fire.
yield waitForTime(1000);
is(gEvents.itemCount, 0,
"There should be no events displayed in the view after reloading.");
ok(true,
"Event listeners were not added after the target finished navigating.");
});
}
});
}

View file

@ -0,0 +1,102 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that event listeners are properly displayed in the view.
*/
const TAB_URL = EXAMPLE_URL + "doc_event-listeners-02.html";
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
let gDebugger = aPanel.panelWin;
let gView = gDebugger.DebuggerView;
let gEvents = gView.EventListeners;
let gController = gDebugger.DebuggerController;
let constants = gDebugger.require("./content/constants");
Task.spawn(function* () {
let fetched = waitForDispatch(aPanel, constants.FETCH_EVENT_LISTENERS);
gView.toggleInstrumentsPane({ visible: true, animated: false }, 1);
yield fetched;
is(gEvents.widget._parent.querySelectorAll(".side-menu-widget-group").length, 3,
"There should be 3 groups shown in the view.");
let groupCheckboxes = gEvents.widget._parent.querySelectorAll(
".side-menu-widget-group-checkbox");
is(groupCheckboxes.length, 3,
"There should be a checkbox for each group shown in the view.");
for (let cb of groupCheckboxes) {
isnot(cb.getAttribute("tooltiptext"), "undefined",
"A valid tooltip text should be defined on group checkboxes");
}
is(gEvents.widget._parent.querySelectorAll(".side-menu-widget-item").length, 4,
"There should be 4 items shown in the view.");
is(gEvents.widget._parent.querySelectorAll(".side-menu-widget-item-checkbox").length, 4,
"There should be a checkbox for each item shown in the view.");
testEventItem(0, "doc_event-listeners-02.html", "change", ["body > input:nth-child(2)"], false);
testEventItem(1, "doc_event-listeners-02.html", "click", ["body > button:nth-child(1)"], false);
testEventItem(2, "doc_event-listeners-02.html", "keydown", ["window", "body"], false);
testEventItem(3, "doc_event-listeners-02.html", "keyup", ["body > input:nth-child(2)"], false);
testEventGroup("interactionEvents", false);
testEventGroup("keyboardEvents", false);
testEventGroup("mouseEvents", false);
is(gEvents.getAllEvents().toString(), "change,click,keydown,keyup",
"The getAllEvents() method returns the correct stuff.");
is(gEvents.getCheckedEvents().toString(), "",
"The getCheckedEvents() method returns the correct stuff.");
yield ensureThreadClientState(aPanel, "attached");
yield closeDebuggerAndFinish(aPanel);
});
function testEventItem(index, label, type, selectors, checked) {
let item = gEvents.items[index];
let node = item.target;
ok(item.attachment.url.includes(label),
"The event at index " + index + " has the correct url.");
is(item.attachment.type, type,
"The event at index " + index + " has the correct type.");
is(item.attachment.selectors.toString(), selectors,
"The event at index " + index + " has the correct selectors.");
is(item.attachment.checkboxState, checked,
"The event at index " + index + " has the correct checkbox state.");
let targets = selectors.length > 1
? gDebugger.L10N.getFormatStr("eventNodes", selectors.length)
: selectors.toString();
is(node.querySelector(".dbg-event-listener-type").getAttribute("value"), type,
"The correct type is shown for this event.");
is(node.querySelector(".dbg-event-listener-targets").getAttribute("value"), targets,
"The correct target is shown for this event.");
is(node.querySelector(".dbg-event-listener-location").getAttribute("value"), label,
"The correct location is shown for this event.");
is(node.parentNode.querySelector(".side-menu-widget-item-checkbox").checked, checked,
"The correct checkbox state is shown for this event.");
}
function testEventGroup(string, checked) {
let name = gDebugger.L10N.getStr(string);
let group = gEvents.widget._parent
.querySelector(".side-menu-widget-group[name=" + name + "]");
is(group.querySelector(".side-menu-widget-group-title > .name").value, name,
"The correct label is shown for the group named " + name + ".");
is(group.querySelector(".side-menu-widget-group-checkbox").checked, checked,
"The correct checkbox state is shown for the group named " + name + ".");
}
});
}

View file

@ -0,0 +1,101 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that checking/unchecking an event listener in the view correctly
* causes the active thread to get updated with the new event breakpoints.
*/
const TAB_URL = EXAMPLE_URL + "doc_event-listeners-02.html";
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
let gDebugger = aPanel.panelWin;
let gView = gDebugger.DebuggerView;
let gController = gDebugger.DebuggerController;
let gEvents = gView.EventListeners;
let constants = gDebugger.require("./content/constants");
Task.spawn(function* () {
let fetched = waitForDispatch(aPanel, constants.FETCH_EVENT_LISTENERS);
gView.toggleInstrumentsPane({ visible: true, animated: false }, 1);
yield fetched;
testEventItem(0, false);
testEventItem(1, false);
testEventItem(2, false);
testEventItem(3, false);
testEventGroup("interactionEvents", false);
testEventGroup("keyboardEvents", false);
testEventGroup("mouseEvents", false);
testEventArrays("change,click,keydown,keyup", "");
let updated = waitForDispatch(aPanel, constants.UPDATE_EVENT_BREAKPOINTS);
EventUtils.sendMouseEvent({ type: "click" }, getItemCheckboxNode(0), gDebugger);
yield updated;
testEventItem(0, true);
testEventItem(1, false);
testEventItem(2, false);
testEventItem(3, false);
testEventGroup("interactionEvents", false);
testEventGroup("keyboardEvents", false);
testEventGroup("mouseEvents", false);
testEventArrays("change,click,keydown,keyup", "change");
updated = waitForDispatch(aPanel, constants.UPDATE_EVENT_BREAKPOINTS);
EventUtils.sendMouseEvent({ type: "click" }, getItemCheckboxNode(0), gDebugger);
yield updated;
testEventItem(0, false);
testEventItem(1, false);
testEventItem(2, false);
testEventItem(3, false);
testEventGroup("interactionEvents", false);
testEventGroup("keyboardEvents", false);
testEventGroup("mouseEvents", false);
testEventArrays("change,click,keydown,keyup", "");
yield ensureThreadClientState(aPanel, "attached");
yield closeDebuggerAndFinish(aPanel);
});
function getItemCheckboxNode(index) {
return gEvents.items[index].target.parentNode
.querySelector(".side-menu-widget-item-checkbox");
}
function getGroupCheckboxNode(string) {
return gEvents.widget._parent
.querySelector(".side-menu-widget-group[name=" + gDebugger.L10N.getStr(string) + "]")
.querySelector(".side-menu-widget-group-checkbox");
}
function testEventItem(index, checked) {
is(gEvents.attachments[index].checkboxState, checked,
"The event at index " + index + " has the correct checkbox state.");
is(getItemCheckboxNode(index).checked, checked,
"The correct checkbox state is shown for this event.");
}
function testEventGroup(string, checked) {
is(getGroupCheckboxNode(string).checked, checked,
"The correct checkbox state is shown for the group " + string + ".");
}
function testEventArrays(all, checked) {
is(gEvents.getAllEvents().toString(), all,
"The getAllEvents() method returns the correct stuff.");
is(gEvents.getCheckedEvents().toString(), checked,
"The getCheckedEvents() method returns the correct stuff.");
is(gController.getState().eventListeners.activeEventNames.toString(), checked,
"The correct event names are listed as being active breakpoints.");
}
});
}

View file

@ -0,0 +1,128 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that checking/unchecking an event listener's group in the view will
* cause the active thread to get updated with the new event breakpoints for
* all children inside that group.
*/
const TAB_URL = EXAMPLE_URL + "doc_event-listeners-02.html";
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
let gDebugger = aPanel.panelWin;
let gView = gDebugger.DebuggerView;
let gController = gDebugger.DebuggerController;
let gEvents = gView.EventListeners;
let constants = gDebugger.require("./content/constants");
Task.spawn(function* () {
let fetched = waitForDispatch(aPanel, constants.FETCH_EVENT_LISTENERS);
gView.toggleInstrumentsPane({ visible: true, animated: false }, 1);
yield fetched;
testEventItem(0, false);
testEventItem(1, false);
testEventItem(2, false);
testEventItem(3, false);
testEventGroup("interactionEvents", false);
testEventGroup("keyboardEvents", false);
testEventGroup("mouseEvents", false);
testEventArrays("change,click,keydown,keyup", "");
let updated = waitForDispatch(aPanel, constants.UPDATE_EVENT_BREAKPOINTS);
EventUtils.sendMouseEvent({ type: "click" }, getGroupCheckboxNode("interactionEvents"), gDebugger);
yield updated;
testEventItem(0, true);
testEventItem(1, false);
testEventItem(2, false);
testEventItem(3, false);
testEventGroup("interactionEvents", true);
testEventGroup("keyboardEvents", false);
testEventGroup("mouseEvents", false);
testEventArrays("change,click,keydown,keyup", "change");
updated = waitForDispatch(aPanel, constants.UPDATE_EVENT_BREAKPOINTS);
EventUtils.sendMouseEvent({ type: "click" }, getGroupCheckboxNode("interactionEvents"), gDebugger);
yield updated;
testEventItem(0, false);
testEventItem(1, false);
testEventItem(2, false);
testEventItem(3, false);
testEventGroup("interactionEvents", false);
testEventGroup("keyboardEvents", false);
testEventGroup("mouseEvents", false);
testEventArrays("change,click,keydown,keyup", "");
updated = waitForDispatch(aPanel, constants.UPDATE_EVENT_BREAKPOINTS);
EventUtils.sendMouseEvent({ type: "click" }, getGroupCheckboxNode("keyboardEvents"), gDebugger);
yield updated;
testEventItem(0, false);
testEventItem(1, false);
testEventItem(2, true);
testEventItem(3, true);
testEventGroup("interactionEvents", false);
testEventGroup("keyboardEvents", true);
testEventGroup("mouseEvents", false);
testEventArrays("change,click,keydown,keyup", "keydown,keyup");
updated = waitForDispatch(aPanel, constants.UPDATE_EVENT_BREAKPOINTS);
EventUtils.sendMouseEvent({ type: "click" }, getGroupCheckboxNode("keyboardEvents"), gDebugger);
yield updated;
testEventItem(0, false);
testEventItem(1, false);
testEventItem(2, false);
testEventItem(3, false);
testEventGroup("interactionEvents", false);
testEventGroup("keyboardEvents", false);
testEventGroup("mouseEvents", false);
testEventArrays("change,click,keydown,keyup", "");
yield ensureThreadClientState(aPanel, "attached");
yield closeDebuggerAndFinish(aPanel);
});
function getItemCheckboxNode(index) {
return gEvents.items[index].target.parentNode
.querySelector(".side-menu-widget-item-checkbox");
}
function getGroupCheckboxNode(string) {
return gEvents.widget._parent
.querySelector(".side-menu-widget-group[name=" + gDebugger.L10N.getStr(string) + "]")
.querySelector(".side-menu-widget-group-checkbox");
}
function testEventItem(index, checked) {
is(gEvents.attachments[index].checkboxState, checked,
"The event at index " + index + " has the correct checkbox state.");
is(getItemCheckboxNode(index).checked, checked,
"The correct checkbox state is shown for this event.");
}
function testEventGroup(string, checked) {
is(getGroupCheckboxNode(string).checked, checked,
"The correct checkbox state is shown for the group " + string + ".");
}
function testEventArrays(all, checked) {
is(gEvents.getAllEvents().toString(), all,
"The getAllEvents() method returns the correct stuff.");
is(gEvents.getCheckedEvents().toString(), checked,
"The getCheckedEvents() method returns the correct stuff.");
is(gController.getState().eventListeners.activeEventNames.toString(), checked,
"The correct event names are listed as being active breakpoints.");
}
});
}

View file

@ -0,0 +1,130 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that the event listener states are preserved in the view after the
* target navigates.
*/
const TAB_URL = EXAMPLE_URL + "doc_event-listeners-02.html";
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
let gDebugger = aPanel.panelWin;
let gView = gDebugger.DebuggerView;
let gController = gDebugger.DebuggerController;
let gEvents = gView.EventListeners;
let gBreakpoints = gController.Breakpoints;
let constants = gDebugger.require("./content/constants");
Task.spawn(function* () {
let fetched = waitForDispatch(aPanel, constants.FETCH_EVENT_LISTENERS);
gView.toggleInstrumentsPane({ visible: true, animated: false }, 1);
yield fetched;
testEventItem(0, false);
testEventItem(1, false);
testEventItem(2, false);
testEventItem(3, false);
testEventGroup("interactionEvents", false);
testEventGroup("keyboardEvents", false);
testEventGroup("mouseEvents", false);
testEventArrays("change,click,keydown,keyup", "");
let updated = waitForDispatch(aPanel, constants.UPDATE_EVENT_BREAKPOINTS);
EventUtils.sendMouseEvent({ type: "click" }, getItemCheckboxNode(0), gDebugger);
EventUtils.sendMouseEvent({ type: "click" }, getItemCheckboxNode(1), gDebugger);
EventUtils.sendMouseEvent({ type: "click" }, getItemCheckboxNode(2), gDebugger);
yield updated;
testEventItem(0, true);
testEventItem(1, true);
testEventItem(2, true);
testEventItem(3, false);
testEventGroup("interactionEvents", false);
testEventGroup("keyboardEvents", false);
testEventGroup("mouseEvents", false);
testEventArrays("change,click,keydown,keyup", "change,click,keydown");
reload(aPanel);
yield waitForDispatch(aPanel, constants.FETCH_EVENT_LISTENERS);
testEventItem(0, true);
testEventItem(1, true);
testEventItem(2, true);
testEventItem(3, false);
testEventGroup("interactionEvents", false);
testEventGroup("keyboardEvents", false);
testEventGroup("mouseEvents", false);
testEventArrays("change,click,keydown,keyup", "change,click,keydown");
updated = waitForDispatch(aPanel, constants.UPDATE_EVENT_BREAKPOINTS);
EventUtils.sendMouseEvent({ type: "click" }, getItemCheckboxNode(0), gDebugger);
EventUtils.sendMouseEvent({ type: "click" }, getItemCheckboxNode(1), gDebugger);
EventUtils.sendMouseEvent({ type: "click" }, getItemCheckboxNode(2), gDebugger);
yield updated;
testEventItem(0, false);
testEventItem(1, false);
testEventItem(2, false);
testEventItem(3, false);
testEventGroup("interactionEvents", false);
testEventGroup("keyboardEvents", false);
testEventGroup("mouseEvents", false);
testEventArrays("change,click,keydown,keyup", "");
reload(aPanel);
yield waitForDispatch(aPanel, constants.FETCH_EVENT_LISTENERS);
testEventItem(0, false);
testEventItem(1, false);
testEventItem(2, false);
testEventItem(3, false);
testEventGroup("interactionEvents", false);
testEventGroup("keyboardEvents", false);
testEventGroup("mouseEvents", false);
testEventArrays("change,click,keydown,keyup", "");
yield ensureThreadClientState(aPanel, "attached");
yield closeDebuggerAndFinish(aPanel);
});
function getItemCheckboxNode(index) {
return gEvents.items[index].target.parentNode
.querySelector(".side-menu-widget-item-checkbox");
}
function getGroupCheckboxNode(string) {
return gEvents.widget._parent
.querySelector(".side-menu-widget-group[name=" + gDebugger.L10N.getStr(string) + "]")
.querySelector(".side-menu-widget-group-checkbox");
}
function testEventItem(index, checked) {
is(gEvents.attachments[index].checkboxState, checked,
"The event at index " + index + " has the correct checkbox state.");
is(getItemCheckboxNode(index).checked, checked,
"The correct checkbox state is shown for this event.");
}
function testEventGroup(string, checked) {
is(getGroupCheckboxNode(string).checked, checked,
"The correct checkbox state is shown for the group " + string + ".");
}
function testEventArrays(all, checked) {
is(gEvents.getAllEvents().toString(), all,
"The getAllEvents() method returns the correct stuff.");
is(gEvents.getCheckedEvents().toString(), checked,
"The getCheckedEvents() method returns the correct stuff.");
is(gController.getState().eventListeners.activeEventNames.toString(), checked,
"The correct event names are listed as being active breakpoints.");
}
});
}

View file

@ -0,0 +1,106 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that system event listeners don't get duplicated in the view.
*/
function test() {
initDebugger().then(([aTab,, aPanel]) => {
let gDebugger = aPanel.panelWin;
let gView = gDebugger.DebuggerView;
let gEvents = gView.EventListeners;
let gL10N = gDebugger.L10N;
is(gEvents.itemCount, 0,
"There are no events displayed in the corresponding pane yet.");
gEvents.addListener({
type: "foo",
node: { selector: "#first" },
function: { url: null }
});
is(gEvents.itemCount, 1,
"There was a system event listener added in the view.");
is(gEvents.attachments[0].url, gL10N.getStr("eventNative"),
"The correct string is used as the event's url.");
is(gEvents.attachments[0].type, "foo",
"The correct string is used as the event's type.");
is(gEvents.attachments[0].selectors.toString(), "#first",
"The correct array of selectors is used as the event's target.");
gEvents.addListener({
type: "bar",
node: { selector: "#second" },
function: { url: null }
});
is(gEvents.itemCount, 2,
"There was another system event listener added in the view.");
is(gEvents.attachments[1].url, gL10N.getStr("eventNative"),
"The correct string is used as the event's url.");
is(gEvents.attachments[1].type, "bar",
"The correct string is used as the event's type.");
is(gEvents.attachments[1].selectors.toString(), "#second",
"The correct array of selectors is used as the event's target.");
gEvents.addListener({
type: "foo",
node: { selector: "#first" },
function: { url: null }
});
is(gEvents.itemCount, 2,
"There wasn't another system event listener added in the view.");
is(gEvents.attachments[0].url, gL10N.getStr("eventNative"),
"The correct string is used as the event's url.");
is(gEvents.attachments[0].type, "foo",
"The correct string is used as the event's type.");
is(gEvents.attachments[0].selectors.toString(), "#first",
"The correct array of selectors is used as the event's target.");
gEvents.addListener({
type: "foo",
node: { selector: "#second" },
function: { url: null }
});
is(gEvents.itemCount, 2,
"There still wasn't another system event listener added in the view.");
is(gEvents.attachments[0].url, gL10N.getStr("eventNative"),
"The correct string is used as the event's url.");
is(gEvents.attachments[0].type, "foo",
"The correct string is used as the event's type.");
is(gEvents.attachments[0].selectors.toString(), "#first,#second",
"The correct array of selectors is used as the event's target.");
gEvents.addListener({
type: null,
node: { selector: "#bogus" },
function: { url: null }
});
is(gEvents.itemCount, 2,
"No bogus system event listener was added in the view.");
is(gEvents.attachments[0].url, gL10N.getStr("eventNative"),
"The correct string is used as the first event's url.");
is(gEvents.attachments[0].type, "foo",
"The correct string is used as the first event's type.");
is(gEvents.attachments[0].selectors.toString(), "#first,#second",
"The correct array of selectors is used as the first event's target.");
is(gEvents.attachments[1].url, gL10N.getStr("eventNative"),
"The correct string is used as the second event's url.");
is(gEvents.attachments[1].type, "bar",
"The correct string is used as the second event's type.");
is(gEvents.attachments[1].selectors.toString(), "#second",
"The correct array of selectors is used as the second event's target.");
closeDebuggerAndFinish(aPanel);
});
}

View file

@ -0,0 +1,61 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that breaking on an event selects the variables view tab.
*/
const TAB_URL = EXAMPLE_URL + "doc_event-listeners-02.html";
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
let gTab = aTab;
let gDebugger = aPanel.panelWin;
let gView = gDebugger.DebuggerView;
let gEvents = gView.EventListeners;
let gController = gDebugger.DebuggerController;
let constants = gDebugger.require("./content/constants");
Task.spawn(function* () {
yield callInTab(gTab, "addBodyClickEventListener");
let fetched = waitForDispatch(aPanel, constants.FETCH_EVENT_LISTENERS);
gView.toggleInstrumentsPane({ visible: true, animated: false }, 1);
yield fetched;
yield ensureThreadClientState(aPanel, "attached");
is(gView.instrumentsPaneHidden, false,
"The instruments pane should be visible.");
is(gView.instrumentsPaneTab, "events-tab",
"The events tab should be selected.");
let updated = waitForDispatch(aPanel, constants.UPDATE_EVENT_BREAKPOINTS);
EventUtils.sendMouseEvent({ type: "click" }, getItemCheckboxNode(1), gDebugger);
yield updated;
yield ensureThreadClientState(aPanel, "attached");
let paused = waitForCaretAndScopes(aPanel, 48);
generateMouseClickInTab(gTab, "content.document.body");
yield paused;
yield ensureThreadClientState(aPanel, "paused");
is(gView.instrumentsPaneHidden, false,
"The instruments pane should be visible.");
is(gView.instrumentsPaneTab, "variables-tab",
"The variables tab should be selected.");
yield resumeDebuggerThenCloseAndFinish(aPanel);
});
function getItemCheckboxNode(index) {
return gEvents.items[index].target.parentNode
.querySelector(".side-menu-widget-item-checkbox");
}
});
}

View file

@ -0,0 +1,225 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that the break-on-dom-events request works.
*/
const TAB_URL = EXAMPLE_URL + "doc_event-listeners-01.html";
var gClient, gThreadClient, gInput, gButton;
function test() {
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect().then(([aType, aTraits]) => {
is(aType, "browser",
"Root actor should identify itself as a browser.");
addTab(TAB_URL)
.then(() => attachThreadActorForUrl(gClient, TAB_URL))
.then(setupGlobals)
.then(pauseDebuggee)
.then(testBreakOnAll)
.then(testBreakOnDisabled)
.then(testBreakOnNone)
.then(testBreakOnClick)
.then(() => gClient.close())
.then(finish)
.then(null, aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
});
}
function setupGlobals(aThreadClient) {
gThreadClient = aThreadClient;
gInput = content.document.querySelector("input");
gButton = content.document.querySelector("button");
}
function pauseDebuggee() {
let deferred = promise.defer();
gClient.addOneTimeListener("paused", (aEvent, aPacket) => {
is(aPacket.type, "paused",
"We should now be paused.");
is(aPacket.why.type, "debuggerStatement",
"The debugger statement was hit.");
deferred.resolve();
});
// Spin the event loop before causing the debuggee to pause, to allow
// this function to return first.
executeSoon(triggerButtonClick);
return deferred.promise;
}
// Test pause on all events.
function testBreakOnAll() {
let deferred = promise.defer();
// Test calling pauseOnDOMEvents from a paused state.
gThreadClient.pauseOnDOMEvents("*", (aPacket) => {
is(aPacket.error, undefined,
"The pause-on-any-event request completed successfully.");
gClient.addOneTimeListener("paused", (aEvent, aPacket) => {
is(aPacket.why.type, "pauseOnDOMEvents",
"A hidden breakpoint was hit.");
is(aPacket.frame.callee.name, "keyupHandler",
"The keyupHandler is entered.");
gClient.addOneTimeListener("paused", (aEvent, aPacket) => {
is(aPacket.why.type, "pauseOnDOMEvents",
"A hidden breakpoint was hit.");
is(aPacket.frame.callee.name, "clickHandler",
"The clickHandler is entered.");
gClient.addOneTimeListener("paused", (aEvent, aPacket) => {
is(aPacket.why.type, "pauseOnDOMEvents",
"A hidden breakpoint was hit.");
is(aPacket.frame.callee.name, "onchange",
"The onchange handler is entered.");
gThreadClient.resume(deferred.resolve);
});
gThreadClient.resume(triggerInputChange);
});
gThreadClient.resume(triggerButtonClick);
});
gThreadClient.resume(triggerInputKeyup);
});
return deferred.promise;
}
// Test that removing events from the array disables them.
function testBreakOnDisabled() {
let deferred = promise.defer();
// Test calling pauseOnDOMEvents from a running state.
gThreadClient.pauseOnDOMEvents(["click"], (aPacket) => {
is(aPacket.error, undefined,
"The pause-on-click-only request completed successfully.");
gClient.addListener("paused", unexpectedListener);
// This non-capturing event listener is guaranteed to run after the page's
// capturing one had a chance to execute and modify window.foobar.
once(gInput, "keyup").then(() => {
is(content.wrappedJSObject.foobar, "keyupHandler",
"No hidden breakpoint was hit.");
gClient.removeListener("paused", unexpectedListener);
deferred.resolve();
});
triggerInputKeyup();
});
return deferred.promise;
}
// Test that specifying an empty event array clears all hidden breakpoints.
function testBreakOnNone() {
let deferred = promise.defer();
// Test calling pauseOnDOMEvents from a running state.
gThreadClient.pauseOnDOMEvents([], (aPacket) => {
is(aPacket.error, undefined,
"The pause-on-none request completed successfully.");
gClient.addListener("paused", unexpectedListener);
// This non-capturing event listener is guaranteed to run after the page's
// capturing one had a chance to execute and modify window.foobar.
once(gInput, "keyup").then(() => {
is(content.wrappedJSObject.foobar, "keyupHandler",
"No hidden breakpoint was hit.");
gClient.removeListener("paused", unexpectedListener);
deferred.resolve();
});
triggerInputKeyup();
});
return deferred.promise;
}
// Test pause on a single event.
function testBreakOnClick() {
let deferred = promise.defer();
// Test calling pauseOnDOMEvents from a running state.
gThreadClient.pauseOnDOMEvents(["click"], (aPacket) => {
is(aPacket.error, undefined,
"The pause-on-click request completed successfully.");
gClient.addOneTimeListener("paused", (aEvent, aPacket) => {
is(aPacket.why.type, "pauseOnDOMEvents",
"A hidden breakpoint was hit.");
is(aPacket.frame.callee.name, "clickHandler",
"The clickHandler is entered.");
gThreadClient.resume(deferred.resolve);
});
triggerButtonClick();
});
return deferred.promise;
}
function unexpectedListener() {
gClient.removeListener("paused", unexpectedListener);
ok(false, "An unexpected hidden breakpoint was hit.");
gThreadClient.resume(testBreakOnClick);
}
function triggerInputKeyup() {
// Make sure that the focus is not on the input box so that a focus event
// will be triggered.
window.focus();
gBrowser.selectedBrowser.focus();
gButton.focus();
// Focus the element and wait for focus event.
once(gInput, "focus").then(() => {
executeSoon(() => {
EventUtils.synthesizeKey("e", { shiftKey: 1 }, content);
});
});
gInput.focus();
}
function triggerButtonClick() {
EventUtils.sendMouseEvent({ type: "click" }, gButton);
}
function triggerInputChange() {
gInput.focus();
gInput.value = "foo";
gInput.blur();
}
registerCleanupFunction(function () {
gClient = null;
gThreadClient = null;
gInput = null;
gButton = null;
});

View file

@ -0,0 +1,105 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that the break-on-dom-events request works even for bound event
* listeners and handler objects with 'handleEvent' methods.
*/
const TAB_URL = EXAMPLE_URL + "doc_event-listeners-03.html";
var gClient, gThreadClient;
function test() {
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect().then(([aType, aTraits]) => {
is(aType, "browser",
"Root actor should identify itself as a browser.");
addTab(TAB_URL)
.then(() => attachThreadActorForUrl(gClient, TAB_URL))
.then(aThreadClient => gThreadClient = aThreadClient)
.then(pauseDebuggee)
.then(testBreakOnClick)
.then(() => gClient.close())
.then(finish)
.then(null, aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
});
}
function pauseDebuggee() {
let deferred = promise.defer();
gClient.addOneTimeListener("paused", (aEvent, aPacket) => {
is(aPacket.type, "paused",
"We should now be paused.");
is(aPacket.why.type, "debuggerStatement",
"The debugger statement was hit.");
gThreadClient.resume(deferred.resolve);
});
// Spin the event loop before causing the debuggee to pause, to allow
// this function to return first.
executeSoon(() => triggerButtonClick("initialSetup"));
return deferred.promise;
}
// Test pause on a single event.
function testBreakOnClick() {
let deferred = promise.defer();
// Test calling pauseOnDOMEvents from a running state.
gThreadClient.pauseOnDOMEvents(["click"], (aPacket) => {
is(aPacket.error, undefined,
"The pause-on-click request completed successfully.");
let handlers = ["clicker"];
gClient.addListener("paused", function tester(aEvent, aPacket) {
is(aPacket.why.type, "pauseOnDOMEvents",
"A hidden breakpoint was hit.");
switch (handlers.length) {
case 1:
is(aPacket.frame.where.line, 26, "Found the clicker handler.");
handlers.push("handleEventClick");
break;
case 2:
is(aPacket.frame.where.line, 36, "Found the handleEventClick handler.");
handlers.push("boundHandleEventClick");
break;
case 3:
is(aPacket.frame.where.line, 46, "Found the boundHandleEventClick handler.");
gClient.removeListener("paused", tester);
deferred.resolve();
}
gThreadClient.resume(() => triggerButtonClick(handlers.slice(-1)));
});
triggerButtonClick(handlers.slice(-1));
});
return deferred.promise;
}
function triggerButtonClick(aNodeId) {
let button = content.document.getElementById(aNodeId);
EventUtils.sendMouseEvent({ type: "click" }, button);
}
registerCleanupFunction(function () {
gClient = null;
gThreadClient = null;
});

View file

@ -0,0 +1,97 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that the break-on-dom-events request works for load event listeners.
*/
const TAB_URL = EXAMPLE_URL + "doc_event-listeners-04.html";
var gClient, gThreadClient;
function test() {
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect().then(([aType, aTraits]) => {
is(aType, "browser",
"Root actor should identify itself as a browser.");
addTab(TAB_URL)
.then(() => attachThreadActorForUrl(gClient, TAB_URL))
.then(aThreadClient => gThreadClient = aThreadClient)
.then(pauseDebuggee)
.then(testBreakOnLoad)
.then(() => gClient.close())
.then(finish)
.then(null, aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
});
}
function pauseDebuggee() {
let deferred = promise.defer();
gClient.addOneTimeListener("paused", (aEvent, aPacket) => {
is(aPacket.type, "paused",
"We should now be paused.");
is(aPacket.why.type, "debuggerStatement",
"The debugger statement was hit.");
gThreadClient.resume(deferred.resolve);
});
// Spin the event loop before causing the debuggee to pause, to allow
// this function to return first.
executeSoon(() => triggerButtonClick());
return deferred.promise;
}
// Test pause on a load event.
function testBreakOnLoad() {
let deferred = promise.defer();
// Test calling pauseOnDOMEvents from a running state.
gThreadClient.pauseOnDOMEvents(["load"], (aPacket) => {
is(aPacket.error, undefined,
"The pause-on-load request completed successfully.");
let handlers = ["loadHandler"];
gClient.addListener("paused", function tester(aEvent, aPacket) {
is(aPacket.why.type, "pauseOnDOMEvents",
"A hidden breakpoint was hit.");
is(aPacket.frame.where.line, 15, "Found the load event listener.");
gClient.removeListener("paused", tester);
deferred.resolve();
gThreadClient.resume(() => triggerButtonClick(handlers.slice(-1)));
});
getTabActorForUrl(gClient, TAB_URL).then(aGrip => {
gClient.attachTab(aGrip.actor, (aResponse, aTabClient) => {
aTabClient.reload();
});
});
});
return deferred.promise;
}
function triggerButtonClick() {
let button = content.document.querySelector("button");
EventUtils.sendMouseEvent({ type: "click" }, button);
}
registerCleanupFunction(function () {
gClient = null;
gThreadClient = null;
});

View file

@ -0,0 +1,61 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test if 'break on next' functionality works from executions
* in content triggered by the console in the toolbox.
*/
const TAB_URL = EXAMPLE_URL + "doc_script-eval.html";
function test() {
let gTab, gPanel, gDebugger;
let gSources, gBreakpoints, gTarget, gResumeButton, gResumeKey, gThreadClient;
let options = {
source: EXAMPLE_URL + "code_script-eval.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;
gTarget = gDebugger.gTarget;
gThreadClient = gDebugger.gThreadClient;
gResumeButton = gDebugger.document.getElementById("resume");
gResumeKey = gDebugger.document.getElementById("resumeKey");
testConsole()
.then(() => closeDebuggerAndFinish(gPanel));
});
let testConsole = Task.async(function* () {
info("Starting testConsole");
let oncePaused = gTarget.once("thread-paused");
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
let jsterm = yield getSplitConsole(gDevTools.getToolbox(gPanel.target));
let executed = jsterm.execute("1+1");
yield oncePaused;
let updatedFrame = yield waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES);
let variables = gDebugger.DebuggerView.Variables;
is(variables._store.length, 3, "Correct number of scopes available");
is(variables.getScopeAtIndex(0).name, "With scope [Object]",
"Paused with correct scope (0)");
is(variables.getScopeAtIndex(1).name, "Block scope",
"Paused with correct scope (1)");
is(variables.getScopeAtIndex(2).name, "Global scope [Window]",
"Paused with correct scope (2)");
let onceResumed = gTarget.once("thread-resumed");
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
yield onceResumed;
yield executed;
});
}

View file

@ -0,0 +1,103 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test if 'break on next' functionality works from executions
* in content that are triggered by the page.
*/
const TAB_URL = EXAMPLE_URL + "doc_script-eval.html";
function test() {
let gTab, gPanel, gDebugger;
let gSources, gBreakpoints, gTarget, gResumeButton, gResumeKey, gThreadClient;
const options = {
source: EXAMPLE_URL + "code_script-eval.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;
gTarget = gDebugger.gTarget;
gThreadClient = gDebugger.gThreadClient;
gResumeButton = gDebugger.document.getElementById("resume");
gResumeKey = gDebugger.document.getElementById("resumeKey");
testInterval()
.then(testEvent)
.then(() => closeDebuggerAndFinish(gPanel));
});
// Testing an interval instead of a timeout / rAF because
// it's less likely to fail due to timing issues. If the
// first callback happens to fire before the break request
// happens then we'll just get it next time.
let testInterval = Task.async(function* () {
info("Starting testInterval");
yield evalInTab(gTab, `
var interval = setInterval(function() {
return 1+1;
}, 100);
`);
let oncePaused = gTarget.once("thread-paused");
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
yield oncePaused;
yield waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN);
let variables = gDebugger.DebuggerView.Variables;
is(variables._store.length, 3, "Correct number of scopes available");
is(variables.getScopeAtIndex(0).name, "Function scope [interval<]",
"Paused with correct scope (0)");
is(variables.getScopeAtIndex(1).name, "Block scope",
"Paused with correct scope (1)");
is(variables.getScopeAtIndex(2).name, "Global scope [Window]",
"Paused with correct scope (2)");
yield evalInTab(gTab, "clearInterval(interval)");
let onceResumed = gTarget.once("thread-resumed");
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
yield onceResumed;
});
let testEvent = Task.async(function* () {
info("Starting testEvent");
let oncePaused = gTarget.once("thread-paused");
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
once(gDebugger.gClient, "willInterrupt").then(() => {
generateMouseClickInTab(gTab, "content.document.querySelector('button')");
});
yield oncePaused;
yield waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN);
let variables = gDebugger.DebuggerView.Variables;
is(variables._store.length, 6, "Correct number of scopes available");
is(variables.getScopeAtIndex(0).name, "Function scope [onclick]",
"Paused with correct scope (0)");
// Non-syntactic lexical scope introduced by non-syntactic scope chain.
is(variables.getScopeAtIndex(1).name, "Block scope",
"Paused with correct scope (1)");
is(variables.getScopeAtIndex(2).name, "With scope [HTMLButtonElement]",
"Paused with correct scope (2)");
is(variables.getScopeAtIndex(3).name, "With scope [HTMLDocument]",
"Paused with correct scope (3)");
// Global lexical scope.
is(variables.getScopeAtIndex(4).name, "Block scope",
"Paused with correct scope (4)");
is(variables.getScopeAtIndex(5).name, "Global scope [Window]",
"Paused with correct scope (5)");
let onceResumed = gTarget.once("thread-resumed");
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
yield onceResumed;
});
}

View file

@ -0,0 +1,48 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test breaking in code and jumping to the debugger before
* the debugger UI has been initialized.
*/
const TAB_URL = EXAMPLE_URL + "doc_inline-debugger-statement.html";
function test() {
Task.spawn(function* () {
const tab = yield getTab(TAB_URL);
const target = TargetFactory.forTab(tab);
const toolbox = yield gDevTools.showToolbox(target, "webconsole");
is(toolbox.currentToolId, "webconsole", "Console is the current panel");
toolbox.target.on("thread-paused", Task.async(function* () {
// Wait for the toolbox to handle the event and switch tools
yield waitForTick();
is(toolbox.currentToolId, "jsdebugger", "Debugger is the current panel");
// Wait until it's actually fully loaded
yield toolbox.loadTool("jsdebugger");
const panel = toolbox.getCurrentPanel();
const queries = panel.panelWin.require("./content/queries");
const getState = panel.panelWin.DebuggerController.getState;
is(panel.panelWin.gThreadClient.state, "paused",
"Thread is still paused");
yield waitForSourceAndCaret(panel, "debugger-statement.html", 16);
is(queries.getSelectedSource(getState()).url, TAB_URL,
"Selected source is the current tab url");
is(queries.getSelectedSourceOpts(getState()).line, 16,
"Line 16 is highlighted in the editor");
resumeDebuggerThenCloseAndFinish(panel);
}));
callInTab(tab, "runDebuggerStatement");
});
}

View file

@ -0,0 +1,55 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Bug 737803: Setting a breakpoint in a line without code should move
* the icon to the actual location.
*/
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
let options = {
source: EXAMPLE_URL + "code_script-switching-01.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gEditor = gDebugger.DebuggerView.editor;
const gSources = gDebugger.DebuggerView.Sources;
const gController = gDebugger.DebuggerController;
const constants = gDebugger.require("./content/constants");
const queries = gDebugger.require("./content/queries");
const actions = bindActionCreators(gPanel);
Task.spawn(function* () {
yield waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1);
is(queries.getBreakpoints(gController.getState()).length, 0,
"There are no breakpoints in the editor");
const response = yield actions.addBreakpoint({
actor: gSources.selectedValue, line: 4
});
ok(response.actualLocation, "has an actualLocation");
is(response.actualLocation.line, 6, "moved to line 6");
is(queries.getBreakpoints(gController.getState()).length, 1,
"There is only one breakpoint in the editor");
ok(!queries.getBreakpoint(gController.getState(), { actor: gSources.selectedValue, line: 4 }),
"There isn't any breakpoint added on an invalid line.");
ok(queries.getBreakpoint(gController.getState(), { actor: gSources.selectedValue, line: 6 }),
"There isn't any breakpoint added on an invalid line.");
resumeDebuggerThenCloseAndFinish(gPanel);
});
callInTab(gTab, "firstCall");
});
}

View file

@ -0,0 +1,88 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Bug 1008372: Setting a breakpoint in a line without code should move
* the icon to the actual location, and if a breakpoint already exists
* on the new location don't duplicate
*/
const TAB_URL = EXAMPLE_URL + "doc_breakpoint-move.html";
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gEditor = gDebugger.DebuggerView.editor;
const gSources = gDebugger.DebuggerView.Sources;
const gController = gDebugger.DebuggerController;
const actions = bindActionCreators(gPanel);
const constants = gDebugger.require("./content/constants");
const queries = gDebugger.require("./content/queries");
function resumeAndTestBreakpoint(line) {
return Task.spawn(function* () {
let event = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES);
doResume(gPanel);
yield event;
testBreakpoint(line);
});
}
function testBreakpoint(line) {
let bp = gSources._selectedBreakpoint;
ok(bp, "There should be a selected breakpoint on line " + line);
is(bp.location.line, line,
"The breakpoint on line " + line + " was not hit");
}
Task.spawn(function* () {
let onCaretUpdated = waitForCaretAndScopes(gPanel, 16);
callInTab(gTab, "ermahgerd");
yield onCaretUpdated;
is(queries.getBreakpoints(gController.getState()).length, 0,
"There are no breakpoints in the editor");
yield actions.addBreakpoint({
actor: gSources.selectedValue,
line: 19
});
yield actions.addBreakpoint({
actor: gSources.selectedValue,
line: 20
});
const response = yield actions.addBreakpoint({
actor: gSources.selectedValue,
line: 17
});
is(response.actualLocation.line, 19,
"Breakpoint client line is new.");
yield resumeAndTestBreakpoint(19);
yield actions.removeBreakpoint({
actor: gSources.selectedValue,
line: 19
});
yield resumeAndTestBreakpoint(20);
yield doResume(gPanel);
callInTab(gTab, "ermahgerd");
yield waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES);
yield resumeAndTestBreakpoint(20);
resumeDebuggerThenCloseAndFinish(gPanel);
});
});
}

View file

@ -0,0 +1,116 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Bug 978019: Setting a breakpoint on the last line of a Debugger.Script and
* reloading should still hit the breakpoint.
*/
const TAB_URL = EXAMPLE_URL + "doc_breakpoints-break-on-last-line-of-script-on-reload.html";
const CODE_URL = EXAMPLE_URL + "code_breakpoints-break-on-last-line-of-script-on-reload.js";
function test() {
// Debug test slaves are a bit slow at this test.
requestLongerTimeout(2);
let gPanel, gDebugger, gThreadClient, gEvents, gSources;
const options = {
source: CODE_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gThreadClient = gDebugger.gThreadClient;
gEvents = gDebugger.EVENTS;
gSources = gDebugger.DebuggerView.Sources;
const actions = bindActionCreators(gPanel);
Task.spawn(function* () {
try {
// Refresh and hit the debugger statement before the location we want to
// set our breakpoints. We have to pause before the breakpoint locations
// so that GC doesn't get a chance to kick in and collect the IIFE's
// script, which would causes us to receive a 'noScript' error from the
// server when we try to set the breakpoints.
const [paused, ] = yield promise.all([
waitForThreadEvents(gPanel, "paused"),
reloadActiveTab(gPanel, gEvents.SOURCE_SHOWN),
]);
is(paused.why.type, "debuggerStatement");
// Set our breakpoints.
const sourceActor = getSourceActor(gSources, CODE_URL);
yield promise.all([
actions.addBreakpoint({
actor: sourceActor,
line: 3
}),
actions.addBreakpoint({
actor: sourceActor,
line: 4
}),
actions.addBreakpoint({
actor: sourceActor,
line: 5
})
]);
// Refresh and hit the debugger statement again.
yield promise.all([
reloadActiveTab(gPanel, gEvents.SOURCE_SHOWN),
waitForCaretAndScopes(gPanel, 1)
]);
// And we should hit the breakpoints as we resume.
yield promise.all([
doResume(gPanel),
waitForCaretAndScopes(gPanel, 3)
]);
yield promise.all([
doResume(gPanel),
waitForCaretAndScopes(gPanel, 4)
]);
yield promise.all([
doResume(gPanel),
waitForCaretAndScopes(gPanel, 5)
]);
// Clean up the breakpoints.
yield promise.all([
actions.removeBreakpoint({ actor: sourceActor, line: 3 }),
actions.removeBreakpoint({ actor: sourceActor, line: 4 }),
actions.removeBreakpoint({ actor: sourceActor, line: 5 })
]);
yield resumeDebuggerThenCloseAndFinish(gPanel);
} catch (e) {
DevToolsUtils.reportException(
"browser_dbg_breakpoints-break-on-last-line-of-script-on-reload.js",
e
);
ok(false);
}
});
});
function setBreakpoint(location) {
let item = gSources.getItemByValue(getSourceActor(gSources, location.url));
let source = gThreadClient.source(item.attachment.source);
let deferred = promise.defer();
source.setBreakpoint(location, ({ error, message }, bpClient) => {
if (error) {
deferred.reject(error + ": " + message);
}
deferred.resolve(bpClient);
});
return deferred.promise;
}
}

View file

@ -0,0 +1,55 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test if the breakpoints toggle button works as advertised.
*/
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
let options = {
source: EXAMPLE_URL + "code_script-switching-01.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gSources = gDebugger.DebuggerView.Sources;
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
function checkBreakpointsDisabled(isDisabled, total = 3) {
let breakpoints = gDebugger.queries.getBreakpoints(getState());
is(breakpoints.length, total,
"Breakpoints should still be set.");
is(breakpoints.filter(bp => bp.disabled === isDisabled).length, total,
"Breakpoints should be " + (isDisabled ? "disabled" : "enabled") + ".");
}
Task.spawn(function* () {
yield actions.addBreakpoint({ actor: gSources.values[0], line: 5 });
yield actions.addBreakpoint({ actor: gSources.values[1], line: 6 });
yield actions.addBreakpoint({ actor: gSources.values[1], line: 7 });
yield ensureThreadClientState(gPanel, "resumed");
gSources.toggleBreakpoints();
yield waitForDispatch(gPanel, gDebugger.constants.REMOVE_BREAKPOINT, 3);
checkBreakpointsDisabled(true);
const finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.BREAKPOINT_ADDED, 3);
gSources.toggleBreakpoints();
yield waitForDispatch(gPanel, gDebugger.constants.ADD_BREAKPOINT, 3);
checkBreakpointsDisabled(false);
if (gDebugger.gThreadClient.state !== "attached") {
yield waitForThreadEvents(gPanel, "resumed");
}
closeDebuggerAndFinish(gPanel);
});
});
}

View file

@ -0,0 +1,64 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test if the breakpoints toggle button works as advertised when there are
* some breakpoints already disabled.
*/
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
let options = {
source: EXAMPLE_URL + "code_script-switching-01.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gSources = gDebugger.DebuggerView.Sources;
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
function checkBreakpointsDisabled(isDisabled, total = 3) {
let breakpoints = gDebugger.queries.getBreakpoints(getState());
is(breakpoints.length, total,
"Breakpoints should still be set.");
is(breakpoints.filter(bp => bp.disabled === isDisabled).length, total,
"Breakpoints should be " + (isDisabled ? "disabled" : "enabled") + ".");
}
Task.spawn(function* () {
yield promise.all([
actions.addBreakpoint({ actor: gSources.values[0], line: 5 }),
actions.addBreakpoint({ actor: gSources.values[1], line: 6 }),
actions.addBreakpoint({ actor: gSources.values[1], line: 7 })
]);
if (gDebugger.gThreadClient.state !== "attached") {
yield waitForThreadEvents(gPanel, "resumed");
}
yield promise.all([
actions.disableBreakpoint({ actor: gSources.values[0], line: 5 }),
actions.disableBreakpoint({ actor: gSources.values[1], line: 6 })
]);
gSources.toggleBreakpoints();
yield waitForDispatch(gPanel, gDebugger.constants.REMOVE_BREAKPOINT, 1);
checkBreakpointsDisabled(true);
gSources.toggleBreakpoints();
yield waitForDispatch(gPanel, gDebugger.constants.ADD_BREAKPOINT, 3);
checkBreakpointsDisabled(false);
if (gDebugger.gThreadClient.state !== "attached") {
yield waitForThreadEvents(gPanel, "resumed");
}
closeDebuggerAndFinish(gPanel);
});
});
}

View file

@ -0,0 +1,107 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that the message which breakpoint condition throws
* could be displayed on UI correctly
*/
const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gEditor = gDebugger.DebuggerView.editor;
const gSources = gDebugger.DebuggerView.Sources;
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
function initialCheck(aCaretLine) {
let bp = gDebugger.queries.getBreakpoint(getState(),
{ actor: gSources.values[0], line: aCaretLine });
ok(bp, "There should be a breakpoint on line " + aCaretLine);
let attachment = gSources._getBreakpoint(bp).attachment;
ok(attachment,
"There should be a breakpoint on line " + aCaretLine + " in the sources pane.");
let thrownNode = attachment.view.container.querySelector(".dbg-breakpoint-condition-thrown-message");
ok(thrownNode,
"The breakpoint item should contain a thrown message node.");
ok(!attachment.view.container.classList.contains("dbg-breakpoint-condition-thrown"),
"The thrown message on line " + aCaretLine + " should be hidden when condition has not been evaluated.");
}
function resumeAndTestThrownMessage(line) {
doResume(gPanel);
return waitForCaretUpdated(gPanel, line).then(() => {
// Test that the thrown message is correctly shown.
let bp = gDebugger.queries.getBreakpoint(
getState(),
{ actor: gSources.values[0], line: line }
);
let attachment = gSources._getBreakpoint(bp).attachment;
ok(attachment.view.container.classList.contains("dbg-breakpoint-condition-thrown"),
"Message on line " + line + " should be shown when condition throws.");
});
}
function resumeAndTestNoThrownMessage(line) {
doResume(gPanel);
return waitForCaretUpdated(gPanel, line).then(() => {
// test that the thrown message is correctly shown
let bp = gDebugger.queries.getBreakpoint(
getState(),
{ actor: gSources.values[0], line: line }
);
let attachment = gSources._getBreakpoint(bp).attachment;
ok(!attachment.view.container.classList.contains("dbg-breakpoint-condition-thrown"),
"Message on line " + line + " should be hidden if condition doesn't throw.");
});
}
Task.spawn(function* () {
let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
callInTab(gTab, "ermahgerd");
yield onCaretUpdated;
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 18 }, " 1afff");
// Close the popup because a SET_BREAKPOINT_CONDITION action is
// fired when it's closed, and it sets it on the currently
// selected breakpoint and we want to make sure it uses the
// current breakpoint. This isn't a problem outside of tests
// because any UI interaction will close the popup before the
// new breakpoint is added.
gSources._hideConditionalPopup();
initialCheck(18);
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 19 }, "true");
gSources._hideConditionalPopup();
initialCheck(19);
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 20 }, "false");
gSources._hideConditionalPopup();
initialCheck(20);
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 22 }, "randomVar");
gSources._hideConditionalPopup();
initialCheck(22);
yield resumeAndTestThrownMessage(18);
yield resumeAndTestNoThrownMessage(19);
yield resumeAndTestThrownMessage(22);
resumeDebuggerThenCloseAndFinish(gPanel);
});
});
}

View file

@ -0,0 +1,84 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test adding breakpoints from the source editor context menu
*/
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
let options = {
source: EXAMPLE_URL + "code_script-switching-01.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gEditor = gDebugger.DebuggerView.editor;
const gSources = gDebugger.DebuggerView.Sources;
const gContextMenu = gDebugger.document.getElementById("sourceEditorContextMenu");
const queries = gDebugger.require("./content/queries");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
Task.spawn(function* () {
yield waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1);
is(gDebugger.gThreadClient.state, "paused",
"Should only be getting stack frames while paused.");
is(queries.getSourceCount(getState()), 2,
"Found the expected number of sources.");
isnot(gEditor.getText().indexOf("debugger"), -1,
"The correct source was loaded initially.");
is(gSources.selectedValue, gSources.values[1],
"The correct source is selected.");
ok(gContextMenu,
"The source editor's context menupopup is available.");
gEditor.focus();
gEditor.setSelection({ line: 1, ch: 0 }, { line: 1, ch: 10 });
gContextMenu.openPopup(gEditor.container, "overlap", 0, 0, true, false);
gEditor.emit("gutterClick", 6, 2);
yield once(gContextMenu, "popupshown");
is(queries.getBreakpoints(getState()).length, 0, "no breakpoints added");
let cmd = gContextMenu.querySelector("menuitem[command=addBreakpointCommand]");
EventUtils.synthesizeMouseAtCenter(cmd, {}, gDebugger);
yield waitForDispatch(gPanel, gDebugger.constants.ADD_BREAKPOINT);
is(queries.getBreakpoints(getState()).length, 1,
"1 breakpoint correctly added");
ok(queries.getBreakpoint(getState(),
{ actor: gSources.values[1], line: 7 }),
"Breakpoint on line 7 exists");
gContextMenu.openPopup(gEditor.container, "overlap", 0, 0, true, false);
gEditor.emit("gutterClick", 7, 2);
yield once(gContextMenu, "popupshown");
is(queries.getBreakpoints(getState()).length, 1,
"1 breakpoint correctly added");
cmd = gContextMenu.querySelector("menuitem[command=addConditionalBreakpointCommand]");
EventUtils.synthesizeMouseAtCenter(cmd, {}, gDebugger);
yield waitForDispatch(gPanel, gDebugger.constants.ADD_BREAKPOINT);
is(queries.getBreakpoints(getState()).length, 2,
"2 breakpoints correctly added");
ok(queries.getBreakpoint(getState(),
{ actor: gSources.values[1], line: 8 }),
"Breakpoint on line 8 exists");
resumeDebuggerThenCloseAndFinish(gPanel);
});
callInTab(gTab, "firstCall");
});
}

View file

@ -0,0 +1,252 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test if the context menu associated with each breakpoint does what it should.
*/
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
// Debug test slaves are a bit slow at this test.
requestLongerTimeout(2);
Task.spawn(function* () {
const options = {
source: EXAMPLE_URL + "code_script-switching-01.js",
line: 1
};
const [gTab,, gPanel ] = yield initDebugger(TAB_URL, options);
const gDebugger = gPanel.panelWin;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require("./content/queries");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
const addBreakpoints = Task.async(function* () {
yield actions.addBreakpoint({ actor: gSources.values[0], line: 5 });
yield actions.addBreakpoint({ actor: gSources.values[1], line: 6 });
yield actions.addBreakpoint({ actor: gSources.values[1], line: 7 });
yield actions.addBreakpoint({ actor: gSources.values[1], line: 8 });
yield actions.addBreakpoint({ actor: gSources.values[1], line: 9 });
yield ensureThreadClientState(gPanel, "resumed");
gSources.highlightBreakpoint({ actor: gSources.values[1], line: 9 });
});
const pauseAndCheck = Task.async(function* () {
let source = queries.getSelectedSource(getState());
is(source.url, EXAMPLE_URL + "code_script-switching-02.js",
"The currently selected source is incorrect (1).");
is(gSources.selectedIndex, 1,
"The currently selected source is incorrect (2).");
ok(isCaretPos(gPanel, 9),
"The editor location is correct before pausing.");
generateMouseClickInTab(gTab, "content.document.querySelector('button')");
return waitForSourceAndCaretAndScopes(gPanel, "-01.js", 5).then(() => {
let source = queries.getSelectedSource(getState());
is(source.url, EXAMPLE_URL + "code_script-switching-01.js",
"The currently selected source is incorrect (3).");
is(gSources.selectedIndex, 0,
"The currently selected source is incorrect (4).");
ok(isCaretPos(gPanel, 5),
"The editor location is correct after pausing.");
});
});
let initialChecks = Task.async(function* () {
for (let bp of queries.getBreakpoints(getState())) {
ok(bp.actor, "All breakpoint items should have an actor");
ok(!bp.disabled, "All breakpoints should initially be enabled.");
let prefix = "bp-cMenu-"; // "breakpoints context menu"
let identifier = queries.makeLocationId(bp.location);
let enableSelfId = prefix + "enableSelf-" + identifier + "-menuitem";
let disableSelfId = prefix + "disableSelf-" + identifier + "-menuitem";
// Check to make sure that only the bp context menu is shown when right clicking
// this node (Bug 1159276).
let breakpointItem = gSources._getBreakpoint(bp);
let menu = gDebugger.document.getElementById("bp-mPop-" + identifier);
let contextMenuShown = once(gDebugger.document, "popupshown");
EventUtils.synthesizeMouseAtCenter(breakpointItem.prebuiltNode, {type: "contextmenu", button: 2}, gDebugger);
let event = yield contextMenuShown;
is(event.originalTarget.id, menu.id, "The correct context menu was shown");
let contextMenuHidden = once(gDebugger.document, "popuphidden");
menu.hidePopup();
yield contextMenuHidden;
is(gDebugger.document.getElementById(enableSelfId).getAttribute("hidden"), "true",
"The 'Enable breakpoint' context menu item should initially be hidden'.");
ok(!gDebugger.document.getElementById(disableSelfId).hasAttribute("hidden"),
"The 'Disable breakpoint' context menu item should initially not be hidden'.");
is(breakpointItem.attachment.view.checkbox.getAttribute("checked"), "true",
"All breakpoints should initially have a checked checkbox.");
}
});
const checkBreakpointToggleSelf = Task.async(function* (index) {
EventUtils.sendMouseEvent({ type: "click" },
gDebugger.document.querySelectorAll(".dbg-breakpoint")[index],
gDebugger);
let selectedBreakpoint = gSources._selectedBreakpoint;
let selectedBreakpointItem = gSources._getBreakpoint(selectedBreakpoint);
ok(selectedBreakpoint.actor,
"Selected breakpoint should have an actor.");
ok(!selectedBreakpoint.disabled,
"The breakpoint should not be disabled yet (" + index + ").");
let prefix = "bp-cMenu-"; // "breakpoints context menu"
let identifier = queries.makeLocationId(selectedBreakpoint.location);
let enableSelfId = prefix + "enableSelf-" + identifier + "-menuitem";
let disableSelfId = prefix + "disableSelf-" + identifier + "-menuitem";
is(gDebugger.document.getElementById(enableSelfId).getAttribute("hidden"), "true",
"The 'Enable breakpoint' context menu item should be hidden'.");
ok(!gDebugger.document.getElementById(disableSelfId).hasAttribute("hidden"),
"The 'Disable breakpoint' context menu item should not be hidden'.");
ok(isCaretPos(gPanel, selectedBreakpoint.location.line),
"The source editor caret position was incorrect (" + index + ").");
// Test disabling this breakpoint.
gSources._onDisableSelf(selectedBreakpoint.location);
yield waitForDispatch(gPanel, gDebugger.constants.REMOVE_BREAKPOINT);
ok(!!queries.getBreakpoint(getState(), selectedBreakpoint.location).disabled,
"The breakpoint should be disabled.");
ok(!gDebugger.document.getElementById(enableSelfId).hasAttribute("hidden"),
"The 'Enable breakpoint' context menu item should not be hidden'.");
is(gDebugger.document.getElementById(disableSelfId).getAttribute("hidden"), "true",
"The 'Disable breakpoint' context menu item should be hidden'.");
ok(!selectedBreakpointItem.attachment.view.checkbox.hasAttribute("checked"),
"The breakpoint should now be unchecked.");
gSources._onEnableSelf(selectedBreakpoint.location);
yield waitForDispatch(gPanel, gDebugger.constants.ADD_BREAKPOINT);
ok(!queries.getBreakpoint(getState(), selectedBreakpoint.location).disabled,
"The breakpoint should be enabled.");
is(gDebugger.document.getElementById(enableSelfId).getAttribute("hidden"), "true",
"The 'Enable breakpoint' context menu item should be hidden'.");
ok(!gDebugger.document.getElementById(disableSelfId).hasAttribute("hidden"),
"The 'Disable breakpoint' context menu item should not be hidden'.");
ok(selectedBreakpointItem.attachment.view.checkbox.hasAttribute("checked"),
"The breakpoint should now be checked.");
});
const checkBreakpointToggleOthers = Task.async(function* (index) {
EventUtils.sendMouseEvent(
{ type: "click" },
gDebugger.document.querySelectorAll(".dbg-breakpoint")[index],
gDebugger
);
// Test disabling other breakpoints.
disableOthers();
yield waitForDispatch(gPanel, gDebugger.constants.REMOVE_BREAKPOINT, 4);
let selectedBreakpoint = queries.getBreakpoint(getState(), gSources._selectedBreakpoint.location);
ok(selectedBreakpoint.actor,
"There should be a breakpoint actor.");
ok(!selectedBreakpoint.disabled,
"The targetted breakpoint should not have been disabled (" + index + ").");
for (let bp of queries.getBreakpoints(getState())) {
if (bp !== selectedBreakpoint) {
ok(bp.disabled,
"Non-targetted breakpoints should have been disabled.");
}
}
// Test re-enabling other breakpoints.
enableOthers();
yield waitForDispatch(gPanel, gDebugger.constants.ADD_BREAKPOINT, 4);
for (let bp of queries.getBreakpoints(getState())) {
ok(!bp.disabled, "All breakpoints should be enabled.");
}
// Test disabling all breakpoints.
disableAll();
yield waitForDispatch(gPanel, gDebugger.constants.REMOVE_BREAKPOINT, 5);
for (let bp of queries.getBreakpoints(getState())) {
ok(!!bp.disabled, "All breakpoints should be disabled.");
}
// Test re-enabling all breakpoints.
enableAll();
yield waitForDispatch(gPanel, gDebugger.constants.ADD_BREAKPOINT, 5);
for (let bp of queries.getBreakpoints(getState())) {
ok(!bp.disabled, "All breakpoints should be enabled.");
}
});
const testDeleteAll = Task.async(function* () {
// Test deleting all breakpoints.
deleteAll();
yield waitForDispatch(gPanel, gDebugger.constants.REMOVE_BREAKPOINT, 5);
ok(!gSources._selectedBreakpoint,
"There should be no breakpoint available after removing all breakpoints.");
for (let bp of queries.getBreakpoints(getState())) {
ok(false, "It's a trap!");
}
});
function disableOthers() {
gSources._onDisableOthers(gSources._selectedBreakpoint.location);
}
function enableOthers() {
gSources._onEnableOthers(gSources._selectedBreakpoint.location);
}
function disableAll() {
gSources._onDisableAll();
}
function enableAll() {
gSources._onEnableAll();
}
function deleteAll() {
gSources._onDeleteAll();
}
yield addBreakpoints();
yield initialChecks();
yield checkBreakpointToggleSelf(0);
yield checkBreakpointToggleOthers(0);
yield checkBreakpointToggleSelf(1);
yield checkBreakpointToggleOthers(1);
yield checkBreakpointToggleSelf(2);
yield checkBreakpointToggleOthers(2);
yield checkBreakpointToggleSelf(3);
yield checkBreakpointToggleOthers(3);
yield checkBreakpointToggleSelf(4);
yield checkBreakpointToggleOthers(4);
yield testDeleteAll();
yield addBreakpoints();
yield initialChecks();
yield pauseAndCheck();
yield checkBreakpointToggleSelf(0);
yield checkBreakpointToggleOthers(0);
yield checkBreakpointToggleSelf(1);
yield checkBreakpointToggleOthers(1);
yield checkBreakpointToggleSelf(2);
yield checkBreakpointToggleOthers(2);
yield checkBreakpointToggleSelf(3);
yield checkBreakpointToggleOthers(3);
yield checkBreakpointToggleSelf(4);
yield checkBreakpointToggleOthers(4);
yield testDeleteAll();
resumeDebuggerThenCloseAndFinish(gPanel);
});
}

View file

@ -0,0 +1,124 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that disabled breakpoints survive target navigation.
*/
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
let options = {
source: EXAMPLE_URL + "code_script-switching-01.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
const gPanel = aPanel;
const gTab = aTab;
const gDebugger = gPanel.panelWin;
const gEvents = gDebugger.EVENTS;
const gEditor = gDebugger.DebuggerView.editor;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require("./content/queries");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
let gBreakpointLocation;
Task.spawn(function* () {
gBreakpointLocation = { actor: getSourceActor(gSources, EXAMPLE_URL + "code_script-switching-01.js"),
line: 5 };
yield actions.addBreakpoint(gBreakpointLocation);
yield ensureThreadClientState(gPanel, "resumed");
yield testWhenBreakpointEnabledAndFirstSourceShown();
gSources._preferredSourceURL = EXAMPLE_URL + "code_script-switching-02.js";
yield reloadActiveTab(gPanel, gEvents.SOURCE_SHOWN);
yield testWhenBreakpointEnabledAndSecondSourceShown();
yield actions.disableBreakpoint(gBreakpointLocation);
yield reloadActiveTab(gPanel, gEvents.SOURCE_SHOWN);
yield testWhenBreakpointDisabledAndSecondSourceShown();
yield actions.enableBreakpoint(gBreakpointLocation);
yield reloadActiveTab(gPanel, gEvents.SOURCE_SHOWN);
yield testWhenBreakpointEnabledAndSecondSourceShown();
yield resumeDebuggerThenCloseAndFinish(gPanel);
});
function verifyView({ disabled }) {
return Task.spawn(function* () {
// It takes a tick for the checkbox in the SideMenuWidget and the
// gutter in the editor to get updated.
yield waitForTick();
let breakpoint = queries.getBreakpoint(getState(), gBreakpointLocation);
let breakpointItem = gSources._getBreakpoint(breakpoint);
is(!!breakpoint.disabled, disabled,
"The selected breakpoint state was correct.");
is(breakpointItem.attachment.view.checkbox.hasAttribute("checked"), !disabled,
"The selected breakpoint's checkbox state was correct.");
});
}
// All the following executeSoon()'s are required to spin the event loop
// before causing the debuggee to pause, to allow functions to yield first.
function testWhenBreakpointEnabledAndFirstSourceShown() {
return Task.spawn(function* () {
yield ensureSourceIs(gPanel, "-01.js");
yield verifyView({ disabled: false });
callInTab(gTab, "firstCall");
yield waitForDebuggerEvents(gPanel, gEvents.FETCHED_SCOPES);
yield ensureSourceIs(gPanel, "-01.js");
yield ensureCaretAt(gPanel, 5);
yield verifyView({ disabled: false });
executeSoon(() => gDebugger.gThreadClient.resume());
yield waitForSourceAndCaretAndScopes(gPanel, "-02.js", 6);
yield verifyView({ disabled: false });
});
}
function testWhenBreakpointEnabledAndSecondSourceShown() {
return Task.spawn(function* () {
yield ensureSourceIs(gPanel, "-02.js", true);
yield verifyView({ disabled: false });
callInTab(gTab, "firstCall");
yield waitForSourceAndCaretAndScopes(gPanel, "-01.js", 1);
yield verifyView({ disabled: false });
executeSoon(() => gDebugger.gThreadClient.resume());
yield waitForSourceAndCaretAndScopes(gPanel, "-02.js", 6);
yield verifyView({ disabled: false });
});
}
function testWhenBreakpointDisabledAndSecondSourceShown() {
return Task.spawn(function* () {
yield ensureSourceIs(gPanel, "-02.js", true);
yield verifyView({ disabled: true });
callInTab(gTab, "firstCall");
yield waitForDebuggerEvents(gPanel, gEvents.FETCHED_SCOPES);
yield ensureSourceIs(gPanel, "-02.js");
yield ensureCaretAt(gPanel, 6);
yield verifyView({ disabled: true });
executeSoon(() => gDebugger.gThreadClient.resume());
yield waitForDebuggerEvents(gPanel, gEvents.AFTER_FRAMES_CLEARED);
yield ensureSourceIs(gPanel, "-02.js");
yield ensureCaretAt(gPanel, 6);
yield verifyView({ disabled: true });
});
}
});
}

View file

@ -0,0 +1,241 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Bug 723069: Test the debugger breakpoint API and connection to the
* source editor.
*/
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
let options = {
source: EXAMPLE_URL + "code_script-switching-01.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gEditor = gDebugger.DebuggerView.editor;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require("./content/queries");
const constants = gDebugger.require("./content/constants");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
Task.spawn(function* () {
yield waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1);
is(gDebugger.gThreadClient.state, "paused",
"Should only be getting stack frames while paused.");
is(queries.getSourceCount(getState()), 2,
"Found the expected number of sources.");
is(gEditor.getText().indexOf("debugger"), 166,
"The correct source was loaded initially.");
is(queries.getSelectedSource(getState()).actor, gSources.values[1],
"The correct source is selected.");
is(queries.getBreakpoints(getState()).length, 0,
"No breakpoints currently added.");
info("Add the first breakpoint.");
gEditor.once("breakpointAdded", onEditorBreakpointAddFirst);
let location = { actor: gSources.selectedValue, line: 6 };
yield actions.addBreakpoint(location);
checkFirstBreakpoint(location);
info("Remove the first breakpoint.");
gEditor.once("breakpointRemoved", onEditorBreakpointRemoveFirst);
yield actions.removeBreakpoint(location);
checkFirstBreakpointRemoved(location);
checkBackgroundBreakpoint(yield testBreakpointAddBackground());
info("Switch to the first source, which is not yet selected");
gEditor.once("breakpointAdded", onEditorBreakpointAddSwitch);
gEditor.once("change", onEditorTextChanged);
actions.selectSource(gSources.items[0].attachment.source);
yield waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN);
onReadyForClick();
});
callInTab(gTab, "firstCall");
let breakpointsAdded = 0;
let breakpointsRemoved = 0;
let editorBreakpointChanges = 0;
function onEditorBreakpointAddFirst(aEvent, aLine) {
editorBreakpointChanges++;
ok(aEvent,
"breakpoint1 added to the editor.");
is(aLine, 5,
"Editor breakpoint line is correct.");
is(gEditor.getBreakpoints().length, 1,
"editor.getBreakpoints().length is correct.");
}
function onEditorBreakpointRemoveFirst(aEvent, aLine) {
editorBreakpointChanges++;
ok(aEvent,
"breakpoint1 removed from the editor.");
is(aLine, 5,
"Editor breakpoint line is correct.");
is(gEditor.getBreakpoints().length, 0,
"editor.getBreakpoints().length is correct.");
}
function checkFirstBreakpoint(location) {
breakpointsAdded++;
const bp = queries.getBreakpoint(getState(), location);
ok(bp,
"breakpoint1 exists");
is(bp.location.actor, queries.getSelectedSource(getState()).actor,
"breakpoint1 actor is correct.");
is(bp.location.line, 6,
"breakpoint1 line is correct.");
is(queries.getBreakpoints(getState()).length, 1,
"The list of added breakpoints holds only one breakpoint.");
is(queries.getSelectedSource(getState()).actor, gSources.values[1],
"The second source should be currently selected.");
}
function checkFirstBreakpointRemoved(location) {
breakpointsRemoved++;
const bp = queries.getBreakpoint(getState(), location);
ok(!bp, "breakpoint1 removed");
}
function testBreakpointAddBackground() {
is(queries.getBreakpoints(getState()).length, 0,
"No breakpoints currently added.");
is(gSources.values[1], gSources.selectedValue,
"The second source should be currently selected.");
info("Add a breakpoint to the first source, which is not selected.");
let location = { actor: gSources.values[0], line: 5 };
gEditor.on("breakpointAdded", onEditorBreakpointAddBackgroundTrap);
return actions.addBreakpoint(location).then(() => location);
}
function onEditorBreakpointAddBackgroundTrap() {
// Trap listener: no breakpoint must be added to the editor when a
// breakpoint is added to a source that is not currently selected.
editorBreakpointChanges++;
ok(false, "breakpoint2 must not be added to the editor.");
}
function checkBackgroundBreakpoint(location) {
breakpointsAdded++;
const bp = queries.getBreakpoint(getState(), location);
ok(bp,
"breakpoint2 added, client received");
is(bp.location.actor, gSources.values[0],
"breakpoint2 client url is correct.");
is(bp.location.line, 5,
"breakpoint2 client line is correct.");
ok(queries.getBreakpoint(getState(), bp.location),
"breakpoint2 found in the list of added breakpoints.");
is(queries.getBreakpoints(getState()).length, 1,
"The list of added breakpoints holds only one breakpoint.");
is(queries.getSelectedSource(getState()).actor, gSources.values[1],
"The second source should be currently selected.");
// Remove the trap listener.
gEditor.off("breakpointAdded", onEditorBreakpointAddBackgroundTrap);
}
function onEditorBreakpointAddSwitch(aEvent, aLine) {
editorBreakpointChanges++;
ok(aEvent,
"breakpoint2 added to the editor.");
is(aLine, 4,
"Editor breakpoint line is correct.");
is(gEditor.getBreakpoints().length, 1,
"editor.getBreakpoints().length is correct");
}
function onEditorTextChanged() {
// Wait for the actual text to be shown.
if (gEditor.getText() == gDebugger.L10N.getStr("loadingText"))
return void gEditor.once("change", onEditorTextChanged);
is(gEditor.getText().indexOf("debugger"), -1,
"The second source is no longer displayed.");
is(gEditor.getText().indexOf("firstCall"), 118,
"The first source is displayed.");
is(gSources.values[0], gSources.selectedValue,
"The first source should be currently selected.");
}
function onReadyForClick() {
info("Remove the second breakpoint using the mouse.");
gEditor.once("breakpointRemoved", onEditorBreakpointRemoveSecond);
let iframe = gEditor.container;
let testWin = iframe.ownerDocument.defaultView;
// Flush the layout for the iframe.
info("rect " + iframe.contentDocument.documentElement.getBoundingClientRect());
let utils = testWin
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let coords = gEditor.getCoordsFromPosition({ line: 4, ch: 0 });
let rect = iframe.getBoundingClientRect();
let left = rect.left + 10;
let top = rect.top + coords.top + 4;
utils.sendMouseEventToWindow("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEventToWindow("mouseup", left, top, 0, 1, 0, false, 0, 0);
}
function onEditorBreakpointRemoveSecond(aEvent, aLine) {
editorBreakpointChanges++;
ok(aEvent,
"breakpoint2 removed from the editor.");
is(aLine, 4,
"Editor breakpoint line is correct.");
is(gEditor.getBreakpoints().length, 0,
"editor.getBreakpoints().length is correct.");
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.AFTER_FRAMES_CLEARED).then(() => {
finalCheck();
closeDebuggerAndFinish(gPanel);
});
gDebugger.gThreadClient.resume();
}
function finalCheck() {
is(queries.getBreakpoints(getState()).length, 0,
"No breakpoints currently added.");
is(breakpointsAdded, 2,
"Correct number of breakpoints have been added.");
is(breakpointsRemoved, 1,
"Correct number of breakpoints have been removed.");
is(editorBreakpointChanges, 4,
"Correct number of editor breakpoint changes.");
}
});
}

View file

@ -0,0 +1,47 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test setting breakpoints on an eval script
*/
const TAB_URL = EXAMPLE_URL + "doc_script-eval.html";
function test() {
let options = {
source: EXAMPLE_URL + "code_script-eval.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gSources = gDebugger.DebuggerView.Sources;
const actions = bindActionCreators(gPanel);
Task.spawn(function* () {
let newSource = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.NEW_SOURCE);
callInTab(gTab, "evalSourceWithSourceURL");
yield newSource;
// Wait for it to be added to the UI
yield waitForTick();
const newSourceActor = getSourceActor(gSources, EXAMPLE_URL + "bar.js");
yield actions.addBreakpoint({
actor: newSourceActor,
line: 2
});
yield ensureThreadClientState(gPanel, "resumed");
const paused = waitForThreadEvents(gPanel, "paused");
callInTab(gTab, "bar");
let frame = (yield paused).frame;
is(frame.where.source.actor, newSourceActor, "Should have broken on the eval'ed source");
is(frame.where.line, 2, "Should break on line 2");
yield resumeDebuggerThenCloseAndFinish(gPanel);
});
});
}

View file

@ -0,0 +1,90 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test if breakpoints are highlighted when they should.
*/
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
let options = {
source: EXAMPLE_URL + "code_script-switching-01.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gEditor = gDebugger.DebuggerView.editor;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require("./content/queries");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
const addBreakpoints = Task.async(function* () {
yield actions.addBreakpoint({ actor: gSources.values[0], line: 5 });
yield actions.addBreakpoint({ actor: gSources.values[1], line: 6 });
yield actions.addBreakpoint({ actor: gSources.values[1], line: 7 });
yield actions.addBreakpoint({ actor: gSources.values[1], line: 8 });
yield actions.addBreakpoint({ actor: gSources.values[1], line: 9 });
});
function clickBreakpointAndCheck(aBreakpointIndex, aSourceIndex, aCaretLine) {
let finished = waitForCaretUpdated(gPanel, aCaretLine).then(() => {
checkHighlight(gSources.values[aSourceIndex], aCaretLine);
checkEditorContents(aSourceIndex);
is(queries.getSelectedSource(getState()).actor,
gSources.items[aSourceIndex].value,
"The currently selected source value is incorrect (1).");
ok(isCaretPos(gPanel, aCaretLine),
"The editor caret line and column were incorrect (1).");
});
EventUtils.sendMouseEvent(
{ type: "click" },
gDebugger.document.querySelectorAll(".dbg-breakpoint")[aBreakpointIndex],
gDebugger
);
return finished;
}
function checkHighlight(actor, line) {
let breakpoint = gSources._selectedBreakpoint;
let breakpointItem = gSources._getBreakpoint(breakpoint);
is(breakpoint.location.actor, actor,
"The currently selected breakpoint actor is incorrect.");
is(breakpoint.location.line, line,
"The currently selected breakpoint line is incorrect.");
is(breakpointItem.attachment.actor, actor,
"The selected breakpoint item's source location attachment is incorrect.");
ok(breakpointItem.target.classList.contains("selected"),
"The selected breakpoint item's target should have a selected class.");
}
function checkEditorContents(aSourceIndex) {
if (aSourceIndex == 0) {
is(gEditor.getText().indexOf("firstCall"), 118,
"The first source is correctly displayed.");
} else {
is(gEditor.getText().indexOf("debugger"), 166,
"The second source is correctly displayed.");
}
}
Task.spawn(function* () {
yield addBreakpoints();
yield clickBreakpointAndCheck(0, 0, 5);
yield clickBreakpointAndCheck(1, 1, 6);
yield clickBreakpointAndCheck(2, 1, 7);
yield clickBreakpointAndCheck(3, 1, 8);
yield clickBreakpointAndCheck(4, 1, 9);
closeDebuggerAndFinish(gPanel);
});
});
}

View file

@ -0,0 +1,92 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Bug 771452: Make sure that setting a breakpoint in an inline source doesn't
* add it twice.
*/
const TAB_URL = EXAMPLE_URL + "doc_inline-script.html";
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require('./content/queries');
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
function testResume() {
const deferred = promise.defer();
is(gDebugger.gThreadClient.state, "paused",
"The breakpoint wasn't hit yet.");
gDebugger.gThreadClient.resume(() => {
gDebugger.gThreadClient.addOneTimeListener("paused", (aEvent, aPacket) => {
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES).then(() => {
is(aPacket.why.type, "breakpoint",
"Execution has advanced to the next breakpoint.");
isnot(aPacket.why.type, "debuggerStatement",
"The breakpoint was hit before the debugger statement.");
ok(isCaretPos(gPanel, 20),
"The source editor caret position is incorrect (2).");
deferred.resolve();
});
});
generateMouseClickInTab(gTab, "content.document.querySelector('button')");
});
return deferred.promise;
}
function testBreakpointHit() {
const deferred = promise.defer();
is(gDebugger.gThreadClient.state, "paused",
"The breakpoint was hit.");
gDebugger.gThreadClient.addOneTimeListener("paused", (aEvent, aPacket) => {
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES).then(() => {
is(aPacket.why.type, "debuggerStatement",
"Execution has advanced to the next line.");
isnot(aPacket.why.type, "breakpoint",
"No ghost breakpoint was hit.");
ok(isCaretPos(gPanel, 20),
"The source editor caret position is incorrect (3).");
deferred.resolve();
});
});
EventUtils.sendMouseEvent({ type: "mousedown" },
gDebugger.document.getElementById("resume"),
gDebugger);
return deferred.promise;
}
Task.spawn(function(){
let onCaretUpdated = waitForCaretAndScopes(gPanel, 16);
callInTab(gTab, "runDebuggerStatement");
yield onCaretUpdated;
is(gDebugger.gThreadClient.state, "paused",
"The debugger statement was reached.");
ok(isCaretPos(gPanel, 16),
"The source editor caret position is incorrect (1).");
yield actions.addBreakpoint({ actor: getSourceActor(gSources, TAB_URL), line: 20 });
yield testResume();
yield testBreakpointHit();
resumeDebuggerThenCloseAndFinish(gPanel);
});
});
}

View file

@ -0,0 +1,41 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that setting a breakpoint in one tab, doesn't cause another tab at
* the same source to pause at that location.
*/
const TAB_URL = EXAMPLE_URL + "doc_breakpoints-other-tabs.html";
var test = Task.async(function* () {
const options = {
source: EXAMPLE_URL + "code_breakpoints-other-tabs.js",
line: 1
};
const [tab1,, panel1] = yield initDebugger(TAB_URL, options);
const [tab2,, panel2] = yield initDebugger(TAB_URL, options);
const queries = panel1.panelWin.require("./content/queries");
const actions = bindActionCreators(panel1);
const getState = panel1.panelWin.DebuggerController.getState;
const sources = panel1.panelWin.DebuggerView.Sources;
yield actions.addBreakpoint({
actor: queries.getSelectedSource(getState()).actor,
line: 2
});
const paused = waitForThreadEvents(panel2, "paused");
callInTab(tab2, "testCase");
const packet = yield paused;
is(packet.why.type, "debuggerStatement",
"Should have stopped at the debugger statement, not the other tab's breakpoint");
is(packet.frame.where.line, 3,
"Should have stopped at line 3 (debugger statement), not line 2 (other tab's breakpoint)");
yield resumeDebuggerThenCloseAndFinish(panel2);
});

View file

@ -0,0 +1,238 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Bug 723071: Test adding a pane to display the list of breakpoints across
* all sources in the debuggee.
*/
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
let options = {
source: EXAMPLE_URL + "code_script-switching-01.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gEditor = gDebugger.DebuggerView.editor;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require("./content/queries");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
const { getBreakpoint } = queries;
let breakpointsAdded = 0;
let breakpointsDisabled = 0;
let breakpointsRemoved = 0;
let breakpointsList;
const addBreakpoints = Task.async(function* (aIncrementFlag) {
const loc1 = { actor: gSources.selectedValue, line: 6 };
yield actions.addBreakpoint(loc1);
onBreakpointAdd(getBreakpoint(getState(), loc1), {
increment: aIncrementFlag,
line: 6,
text: "debugger;"
});
const loc2 = { actor: gSources.selectedValue, line: 7 };
yield actions.addBreakpoint(loc2);
onBreakpointAdd(getBreakpoint(getState(), loc2), {
increment: aIncrementFlag,
line: 7,
text: "function foo() {}"
});
const loc3 = {actor: gSources.selectedValue, line: 9 };
yield actions.addBreakpoint(loc3);
onBreakpointAdd(getBreakpoint(getState(), loc3), {
increment: aIncrementFlag,
line: 9,
text: "foo();"
});
});
function disableBreakpoints() {
let deferred = promise.defer();
let nodes = breakpointsList.querySelectorAll(".dbg-breakpoint");
info("Nodes to disable: " + breakpointsAdded.length);
is(nodes.length, breakpointsAdded,
"The number of nodes to disable is incorrect.");
for (let node of nodes) {
info("Disabling breakpoint: " + node.id);
let sourceItem = gSources.getItemForElement(node);
let breakpointItem = gSources.getItemForElement.call(sourceItem, node);
info("Found data: " + breakpointItem.attachment.toSource());
actions.disableBreakpoint(breakpointItem.attachment).then(() => {
if (++breakpointsDisabled == breakpointsAdded) {
deferred.resolve();
}
});
}
return deferred.promise;
}
function removeBreakpoints() {
let deferred = promise.defer();
let nodes = breakpointsList.querySelectorAll(".dbg-breakpoint");
info("Nodes to remove: " + breakpointsAdded.length);
is(nodes.length, breakpointsAdded,
"The number of nodes to remove is incorrect.");
for (let node of nodes) {
info("Removing breakpoint: " + node.id);
let sourceItem = gSources.getItemForElement(node);
let breakpointItem = gSources.getItemForElement.call(sourceItem, node);
info("Found data: " + breakpointItem.attachment.toSource());
actions.removeBreakpoint(breakpointItem.attachment).then(() => {
if (++breakpointsRemoved == breakpointsAdded) {
deferred.resolve();
}
});
}
return deferred.promise;
}
function onBreakpointAdd(bp, testData) {
if (testData.increment) {
breakpointsAdded++;
}
is(breakpointsList.querySelectorAll(".dbg-breakpoint").length, breakpointsAdded,
testData.increment
? "Should have added a breakpoint in the pane."
: "Should have the same number of breakpoints in the pane.");
let identifier = queries.makeLocationId(bp.location);
let node = gDebugger.document.getElementById("breakpoint-" + identifier);
let line = node.getElementsByClassName("dbg-breakpoint-line")[0];
let text = node.getElementsByClassName("dbg-breakpoint-text")[0];
let check = node.querySelector("checkbox");
ok(node,
"Breakpoint element found successfully.");
is(line.getAttribute("value"), testData.line,
"The expected information wasn't found in the breakpoint element.");
is(text.getAttribute("value"), testData.text,
"The expected line text wasn't found in the breakpoint element.");
is(check.getAttribute("checked"), "true",
"The breakpoint enable checkbox is checked as expected.");
}
Task.spawn(function* () {
yield waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1);
is(gDebugger.gThreadClient.state, "paused",
"Should only be getting stack frames while paused.");
is(queries.getSourceCount(getState()), 2,
"Found the expected number of sources.");
is(gEditor.getText().indexOf("debugger"), 166,
"The correct source was loaded initially.");
is(gSources.selectedValue, gSources.values[1],
"The correct source is selected.");
is(queries.getBreakpoints(getState()).length, 0,
"No breakpoints currently added.");
let breakpointsParent = gSources.widget._parent;
breakpointsList = gSources.widget._list;
is(breakpointsParent.childNodes.length, 1, // one sources list
"Found junk in the breakpoints container.");
is(breakpointsList.childNodes.length, 1, // one sources group
"Found junk in the breakpoints container.");
is(breakpointsList.querySelectorAll(".dbg-breakpoint").length, 0,
"No breakpoints should be visible at this point.");
yield addBreakpoints(true);
is(breakpointsAdded, 3,
"Should have added 3 breakpoints so far.");
is(breakpointsDisabled, 0,
"Shouldn't have disabled anything so far.");
is(breakpointsRemoved, 0,
"Shouldn't have removed anything so far.");
is(breakpointsParent.childNodes.length, 1, // one sources list
"Found junk in the breakpoints container.");
is(breakpointsList.childNodes.length, 1, // one sources group
"Found junk in the breakpoints container.");
is(breakpointsList.querySelectorAll(".dbg-breakpoint").length, 3,
"3 breakpoints should be visible at this point.");
yield disableBreakpoints();
is(breakpointsAdded, 3,
"Should still have 3 breakpoints added so far.");
is(breakpointsDisabled, 3,
"Should have 3 disabled breakpoints.");
is(breakpointsRemoved, 0,
"Shouldn't have removed anything so far.");
is(breakpointsParent.childNodes.length, 1, // one sources list
"Found junk in the breakpoints container.");
is(breakpointsList.childNodes.length, 1, // one sources group
"Found junk in the breakpoints container.");
is(breakpointsList.querySelectorAll(".dbg-breakpoint").length, breakpointsAdded,
"Should have the same number of breakpoints in the pane.");
is(breakpointsList.querySelectorAll(".dbg-breakpoint").length, breakpointsDisabled,
"Should have the same number of disabled breakpoints.");
yield addBreakpoints();
is(breakpointsAdded, 3,
"Should still have only 3 breakpoints added so far.");
is(breakpointsDisabled, 3,
"Should still have 3 disabled breakpoints.");
is(breakpointsRemoved, 0,
"Shouldn't have removed anything so far.");
is(breakpointsParent.childNodes.length, 1, // one sources list
"Found junk in the breakpoints container.");
is(breakpointsList.childNodes.length, 1, // one sources group
"Found junk in the breakpoints container.");
is(breakpointsList.querySelectorAll(".dbg-breakpoint").length, breakpointsAdded,
"Since half of the breakpoints already existed, but disabled, " +
"only half of the added breakpoints are actually in the pane.");
yield removeBreakpoints();
is(breakpointsRemoved, 3,
"Should have 3 removed breakpoints.");
is(breakpointsParent.childNodes.length, 1, // one sources list
"Found junk in the breakpoints container.");
is(breakpointsList.childNodes.length, 1, // one sources group
"Found junk in the breakpoints container.");
is(breakpointsList.querySelectorAll(".dbg-breakpoint").length, 0,
"No breakpoints should be visible at this point.");
const cleared = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.AFTER_FRAMES_CLEARED);
gDebugger.gThreadClient.resume();
yield cleared;
is(queries.getBreakpoints(getState()).length, 0,
"No breakpoints currently added.");
closeDebuggerAndFinish(gPanel);
});
callInTab(gTab, "firstCall");
});
}

View file

@ -0,0 +1,39 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that setting a breakpoint on code that gets run on load, will get
* hit when we reload.
*/
const TAB_URL = EXAMPLE_URL + "doc_breakpoints-reload.html";
var test = Task.async(function* () {
requestLongerTimeout(4);
const options = {
source: TAB_URL,
line: 1
};
const [tab,, panel] = yield initDebugger(TAB_URL, options);
const actions = bindActionCreators(panel);
const sources = panel.panelWin.DebuggerView.Sources;
yield actions.addBreakpoint({
actor: sources.selectedValue,
line: 10 // "break on me" string
});
const paused = waitForThreadEvents(panel, "paused");
yield reloadActiveTab(panel, panel.panelWin.EVENTS.SOURCE_SHOWN);
const packet = yield paused;
is(packet.why.type, "breakpoint",
"Should have hit the breakpoint after the reload");
is(packet.frame.where.line, 10,
"Should have stopped at line 10, where we set the breakpoint");
yield resumeDebuggerThenCloseAndFinish(panel);
});

View file

@ -0,0 +1,48 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Bug 896139 - Breakpoints not triggering when reloading script.
*/
const TAB_URL = EXAMPLE_URL + "doc_bug-896139.html";
const SCRIPT_URL = EXAMPLE_URL + "code_bug-896139.js";
function test() {
Task.spawn(function* () {
function testBreakpoint() {
let promise = waitForDebuggerEvents(panel, win.EVENTS.FETCHED_SCOPES);
callInTab(tab, "f");
return promise.then(() => doResume(panel));
}
let options = {
source: SCRIPT_URL,
line: 1
};
let [tab,, panel] = yield initDebugger(TAB_URL, options);
let win = panel.panelWin;
let Sources = win.DebuggerView.Sources;
yield panel.addBreakpoint({
actor: getSourceActor(win.DebuggerView.Sources, SCRIPT_URL),
line: 6
});
// Race condition: the setBreakpoint request sometimes leaves the
// debugger in paused state for a bit because we are called before
// that request finishes (see bug 1156531 for plans to fix)
if (panel.panelWin.gThreadClient.state !== "attached") {
yield waitForThreadEvents(panel, "resumed");
}
yield testBreakpoint();
yield reloadActiveTab(panel, win.EVENTS.SOURCE_SHOWN);
yield testBreakpoint();
yield closeDebuggerAndFinish(panel);
});
}

View file

@ -0,0 +1,64 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that a chrome debugger can be created in a new process.
*/
var gProcess;
function test() {
// Windows XP and 8.1 test slaves are terribly slow at this test.
requestLongerTimeout(5);
Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true);
initChromeDebugger(aOnClose).then(aProcess => {
gProcess = aProcess;
info("Starting test...");
performTest();
});
}
function performTest() {
ok(gProcess._dbgProcess,
"The remote debugger process wasn't created properly!");
ok(gProcess._dbgProcess.isRunning,
"The remote debugger process isn't running!");
is(typeof gProcess._dbgProcess.pid, "number",
"The remote debugger process doesn't have a pid (?!)");
info("process location: " + gProcess._dbgProcess.location);
info("process pid: " + gProcess._dbgProcess.pid);
info("process name: " + gProcess._dbgProcess.processName);
info("process sig: " + gProcess._dbgProcess.processSignature);
ok(gProcess._dbgProfilePath,
"The remote debugger profile wasn't created properly!");
is(gProcess._dbgProfilePath, OS.Path.join(OS.Constants.Path.profileDir, "chrome_debugger_profile"),
"The remote debugger profile isn't where we expect it!");
info("profile path: " + gProcess._dbgProfilePath);
gProcess.close();
}
function aOnClose() {
ok(!gProcess._dbgProcess.isRunning,
"The remote debugger process isn't closed as it should be!");
is(gProcess._dbgProcess.exitValue, (Services.appinfo.OS == "WINNT" ? 0 : 256),
"The remote debugger process didn't die cleanly.");
info("process exit value: " + gProcess._dbgProcess.exitValue);
info("profile path: " + gProcess._dbgProfilePath);
finish();
}
registerCleanupFunction(function () {
Services.prefs.clearUserPref("devtools.debugger.remote-enabled");
gProcess = null;
});

View file

@ -0,0 +1,102 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that chrome debugging works.
*/
const TAB_URL = EXAMPLE_URL + "doc_inline-debugger-statement.html";
var gClient, gThreadClient;
var gAttached = promise.defer();
var gNewGlobal = promise.defer();
var gNewChromeSource = promise.defer();
var { DevToolsLoader } = Cu.import("resource://devtools/shared/Loader.jsm", {});
var customLoader = new DevToolsLoader();
customLoader.invisibleToDebugger = true;
var { DebuggerServer } = customLoader.require("devtools/server/main");
function test() {
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
DebuggerServer.allowChromeProcess = true;
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect().then(([aType, aTraits]) => {
is(aType, "browser",
"Root actor should identify itself as a browser.");
promise.all([gAttached.promise, gNewGlobal.promise, gNewChromeSource.promise])
.then(resumeAndCloseConnection)
.then(finish)
.then(null, aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
testChromeActor();
});
}
function testChromeActor() {
gClient.getProcess().then(aResponse => {
gClient.addListener("newGlobal", onNewGlobal);
let actor = aResponse.form.actor;
gClient.attachTab(actor, (response, tabClient) => {
tabClient.attachThread(null, (aResponse, aThreadClient) => {
gThreadClient = aThreadClient;
gThreadClient.addListener("newSource", onNewSource);
if (aResponse.error) {
ok(false, "Couldn't attach to the chrome debugger.");
gAttached.reject();
} else {
ok(true, "Attached to the chrome debugger.");
gAttached.resolve();
// Ensure that a new chrome global will be created.
gBrowser.selectedTab = gBrowser.addTab("about:mozilla");
}
});
});
});
}
function onNewGlobal() {
ok(true, "Received a new chrome global.");
gClient.removeListener("newGlobal", onNewGlobal);
gNewGlobal.resolve();
}
function onNewSource(aEvent, aPacket) {
if (aPacket.source.url.startsWith("chrome:")) {
ok(true, "Received a new chrome source: " + aPacket.source.url);
gThreadClient.removeListener("newSource", onNewSource);
gNewChromeSource.resolve();
}
}
function resumeAndCloseConnection() {
let deferred = promise.defer();
gThreadClient.resume(() => deferred.resolve(gClient.close()));
return deferred.promise;
}
registerCleanupFunction(function () {
gClient = null;
gThreadClient = null;
gAttached = null;
gNewGlobal = null;
gNewChromeSource = null;
customLoader = null;
DebuggerServer = null;
});

View file

@ -0,0 +1,86 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that closing a window with the debugger in a paused state exits cleanly.
*/
var gDebuggee, gPanel, gDebugger, gWindow;
const TAB_URL = EXAMPLE_URL + "doc_inline-debugger-statement.html";
function test() {
addWindow(TAB_URL)
.then(win => initDebugger(TAB_URL, { window: win }))
.then(([aTab, aDebuggee, aPanel, aWindow]) => {
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gWindow = aWindow;
return testCleanExit();
})
.then(null, aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
}
function testCleanExit() {
let deferred = promise.defer();
ok(!!gWindow, "Second window created.");
gWindow.focus();
is(Services.wm.getMostRecentWindow("navigator:browser"), gWindow,
"The second window is on top.");
let isActive = promise.defer();
let isLoaded = promise.defer();
promise.all([isActive.promise, isLoaded.promise]).then(() => {
waitForSourceAndCaretAndScopes(gPanel, ".html", 16).then(() => {
is(gDebugger.gThreadClient.paused, true,
"Should be paused after the debugger statement.");
gWindow.close();
deferred.resolve();
finish();
});
gDebuggee.runDebuggerStatement();
});
if (Services.focus.activeWindow != gWindow) {
gWindow.addEventListener("activate", function onActivate(aEvent) {
if (aEvent.target != gWindow) {
return;
}
gWindow.removeEventListener("activate", onActivate, true);
isActive.resolve();
}, true);
} else {
isActive.resolve();
}
if (gWindow.content.location.href != TAB_URL) {
gWindow.document.addEventListener("load", function onLoad(aEvent) {
if (aEvent.target.documentURI != TAB_URL) {
return;
}
gWindow.document.removeEventListener("load", onLoad, true);
isLoaded.resolve();
}, true);
} else {
isLoaded.resolve();
}
return deferred.promise;
}
registerCleanupFunction(function () {
gWindow = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
});

View file

@ -0,0 +1,44 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that closing a tab with the debugger in a paused state exits cleanly.
*/
var gTab, gPanel, gDebugger;
const TAB_URL = EXAMPLE_URL + "doc_inline-debugger-statement.html";
function test() {
const options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
testCleanExit();
});
}
function testCleanExit() {
promise.all([
waitForSourceAndCaretAndScopes(gPanel, ".html", 16),
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.AFTER_FRAMES_REFILLED)
]).then(() => {
is(gDebugger.gThreadClient.paused, true,
"Should be paused after the debugger statement.");
}).then(() => closeDebuggerAndFinish(gPanel, { whilePaused: true }));
callInTab(gTab, "runDebuggerStatement");
}
registerCleanupFunction(function () {
gTab = null;
gPanel = null;
gDebugger = null;
});

View file

@ -0,0 +1,153 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
const TAB_URL = EXAMPLE_URL + "doc_closures.html";
// Test that inspecting a closure works as expected.
function test() {
let gPanel, gTab, gDebugger;
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
testClosure()
.then(() => resumeDebuggerThenCloseAndFinish(gPanel))
.then(null, aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
});
function testClosure() {
generateMouseClickInTab(gTab, "content.document.querySelector('button')");
return waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES).then(() => {
let gVars = gDebugger.DebuggerView.Variables;
let localScope = gVars.getScopeAtIndex(0);
let localNodes = localScope.target.querySelector(".variables-view-element-details").childNodes;
is(localNodes[4].querySelector(".name").getAttribute("value"), "person",
"Should have the right property name for |person|.");
is(localNodes[4].querySelector(".value").getAttribute("value"), "Object",
"Should have the right property value for |person|.");
// Expand the 'person' tree node. This causes its properties to be
// retrieved and displayed.
let personNode = gVars.getItemForNode(localNodes[4]);
let personFetched = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_PROPERTIES);
personNode.expand();
return personFetched.then(() => {
is(personNode.expanded, true,
"|person| should be expanded at this point.");
is(personNode.get("getName").target.querySelector(".name")
.getAttribute("value"), "getName",
"Should have the right property name for 'getName' in person.");
is(personNode.get("getName").target.querySelector(".value")
.getAttribute("value"), "_pfactory/<.getName()",
"'getName' in person should have the right value.");
is(personNode.get("getFoo").target.querySelector(".name")
.getAttribute("value"), "getFoo",
"Should have the right property name for 'getFoo' in person.");
is(personNode.get("getFoo").target.querySelector(".value")
.getAttribute("value"), "_pfactory/<.getFoo()",
"'getFoo' in person should have the right value.");
// Expand the function nodes. This causes their properties to be
// retrieved and displayed.
let getFooNode = personNode.get("getFoo");
let getNameNode = personNode.get("getName");
let funcsFetched = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_PROPERTIES, 2);
let funcClosuresFetched = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES, 2);
getFooNode.expand();
getNameNode.expand();
return funcsFetched.then(() => {
is(getFooNode.expanded, true,
"|person.getFoo| should be expanded at this point.");
is(getNameNode.expanded, true,
"|person.getName| should be expanded at this point.");
is(getFooNode.get("<Closure>").target.querySelector(".name")
.getAttribute("value"), "<Closure>",
"Found the closure node for getFoo.");
is(getFooNode.get("<Closure>").target.querySelector(".value")
.getAttribute("value"), "",
"The closure node has no value for getFoo.");
is(getNameNode.get("<Closure>").target.querySelector(".name")
.getAttribute("value"), "<Closure>",
"Found the closure node for getName.");
is(getNameNode.get("<Closure>").target.querySelector(".value")
.getAttribute("value"), "",
"The closure node has no value for getName.");
// Expand the closure nodes. This causes their environments to be
// retrieved and displayed.
let getFooClosure = getFooNode.get("<Closure>");
let getNameClosure = getNameNode.get("<Closure>");
getFooClosure.expand();
getNameClosure.expand();
return funcClosuresFetched.then(() => {
is(getFooClosure.expanded, true,
"|person.getFoo| closure should be expanded at this point.");
is(getNameClosure.expanded, true,
"|person.getName| closure should be expanded at this point.");
is(getFooClosure.get("Function scope [_pfactory]").target.querySelector(".name")
.getAttribute("value"), "Function scope [_pfactory]",
"Found the function scope node for the getFoo closure.");
is(getFooClosure.get("Function scope [_pfactory]").target.querySelector(".value")
.getAttribute("value"), "",
"The function scope node has no value for the getFoo closure.");
is(getNameClosure.get("Function scope [_pfactory]").target.querySelector(".name")
.getAttribute("value"), "Function scope [_pfactory]",
"Found the function scope node for the getName closure.");
is(getNameClosure.get("Function scope [_pfactory]").target.querySelector(".value")
.getAttribute("value"), "",
"The function scope node has no value for the getName closure.");
// Expand the scope nodes.
let getFooInnerScope = getFooClosure.get("Function scope [_pfactory]");
let getNameInnerScope = getNameClosure.get("Function scope [_pfactory]");
let innerFuncsFetched = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_PROPERTIES, 2);
getFooInnerScope.expand();
getNameInnerScope.expand();
return funcsFetched.then(() => {
is(getFooInnerScope.expanded, true,
"|person.getFoo| inner scope should be expanded at this point.");
is(getNameInnerScope.expanded, true,
"|person.getName| inner scope should be expanded at this point.");
// Only test that each function closes over the necessary variable.
// We wouldn't want future SpiderMonkey closure space
// optimizations to break this test.
is(getFooInnerScope.get("foo").target.querySelector(".name")
.getAttribute("value"), "foo",
"Found the foo node for the getFoo inner scope.");
is(getFooInnerScope.get("foo").target.querySelector(".value")
.getAttribute("value"), "10",
"The foo node has the expected value.");
is(getNameInnerScope.get("name").target.querySelector(".name")
.getAttribute("value"), "name",
"Found the name node for the getName inner scope.");
is(getNameInnerScope.get("name").target.querySelector(".value")
.getAttribute("value"), '"Bob"',
"The name node has the expected value.");
});
});
});
});
});
}
}

View file

@ -0,0 +1,117 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that the 'dbg blackbox' and 'dbg unblackbox' commands work as
* they should.
*/
const TEST_URL = EXAMPLE_URL + "doc_blackboxing.html";
const BLACKBOXME_URL = EXAMPLE_URL + "code_blackboxing_blackboxme.js";
const BLACKBOXONE_URL = EXAMPLE_URL + "code_blackboxing_one.js";
const BLACKBOXTWO_URL = EXAMPLE_URL + "code_blackboxing_two.js";
const BLACKBOXTHREE_URL = EXAMPLE_URL + "code_blackboxing_three.js";
function test() {
return Task.spawn(spawnTest).then(finish, helpers.handleError);
}
function* spawnTest() {
let options = yield helpers.openTab(TEST_URL);
yield helpers.openToolbar(options);
let toolbox = yield gDevTools.showToolbox(options.target, "jsdebugger");
let panel = toolbox.getCurrentPanel();
let constants = panel.panelWin.require("./content/constants");
yield waitForDebuggerEvents(panel, panel.panelWin.EVENTS.SOURCE_SHOWN);
function cmd(aTyped, aEventRepeat = 1, aOutput = "") {
return promise.all([
waitForDispatch(panel, constants.BLACKBOX, aEventRepeat),
helpers.audit(options, [{ setup: aTyped, output: aOutput, exec: {} }])
]);
}
// test Black-Box Source
yield cmd("dbg blackbox " + BLACKBOXME_URL);
let bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXME_URL);
ok(bbButton.checked,
"Should be able to black box a specific source.");
// test Un-Black-Box Source
yield cmd("dbg unblackbox " + BLACKBOXME_URL);
bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXME_URL);
ok(!bbButton.checked,
"Should be able to stop black boxing a specific source.");
// test Black-Box Glob
yield cmd("dbg blackbox --glob *blackboxing_t*.js", 2,
[/blackboxing_three\.js/g, /blackboxing_two\.js/g]);
bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXME_URL);
ok(!bbButton.checked,
"blackboxme should not be black boxed because it doesn't match the glob.");
bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXONE_URL);
ok(!bbButton.checked,
"blackbox_one should not be black boxed because it doesn't match the glob.");
bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXTWO_URL);
ok(bbButton.checked,
"blackbox_two should be black boxed because it matches the glob.");
bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXTHREE_URL);
ok(bbButton.checked,
"blackbox_three should be black boxed because it matches the glob.");
// test Un-Black-Box Glob
yield cmd("dbg unblackbox --glob *blackboxing_t*.js", 2);
bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXTWO_URL);
ok(!bbButton.checked,
"blackbox_two should be un-black boxed because it matches the glob.");
bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXTHREE_URL);
ok(!bbButton.checked,
"blackbox_three should be un-black boxed because it matches the glob.");
// test Black-Box Invert
yield cmd("dbg blackbox --invert --glob *blackboxing_t*.js", 3,
[/blackboxing_three\.js/g, /blackboxing_two\.js/g]);
bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXME_URL);
ok(bbButton.checked,
"blackboxme should be black boxed because it doesn't match the glob.");
bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXONE_URL);
ok(bbButton.checked,
"blackbox_one should be black boxed because it doesn't match the glob.");
bbButton = yield selectSourceAndGetBlackBoxButton(panel, TEST_URL);
ok(bbButton.checked,
"TEST_URL should be black boxed because it doesn't match the glob.");
bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXTWO_URL);
ok(!bbButton.checked,
"blackbox_two should not be black boxed because it matches the glob.");
bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXTHREE_URL);
ok(!bbButton.checked,
"blackbox_three should not be black boxed because it matches the glob.");
// test Un-Black-Box Invert
yield cmd("dbg unblackbox --invert --glob *blackboxing_t*.js", 3);
bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXME_URL);
ok(!bbButton.checked,
"blackboxme should be un-black boxed because it does not match the glob.");
bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXONE_URL);
ok(!bbButton.checked,
"blackbox_one should be un-black boxed because it does not match the glob.");
bbButton = yield selectSourceAndGetBlackBoxButton(panel, TEST_URL);
ok(!bbButton.checked,
"TEST_URL should be un-black boxed because it doesn't match the glob.");
yield teardown(panel, { noTabRemoval: true });
yield helpers.closeToolbar(options);
yield helpers.closeTab(options);
}

View file

@ -0,0 +1,225 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that the break commands works as they should.
*/
const TAB_URL = EXAMPLE_URL + "doc_cmd-break.html";
var TAB_URL_ACTOR;
function test() {
let gPanel, gDebugger, gThreadClient, gSources;
let gLineNumber;
let expectedActorObj = {
value: null,
message: ""
};
helpers.addTabWithToolbar(TAB_URL, aOptions => {
return Task.spawn(function* () {
yield helpers.audit(aOptions, [{
setup: "break",
check: {
input: "break",
hints: " add line",
markup: "IIIII",
status: "ERROR",
}
}]);
yield helpers.audit(aOptions, [{
setup: "break add",
check: {
input: "break add",
hints: " line",
markup: "IIIIIVIII",
status: "ERROR"
}
}]);
yield helpers.audit(aOptions, [{
setup: "break add line",
check: {
input: "break add line",
hints: " <file> <line>",
markup: "VVVVVVVVVVVVVV",
status: "ERROR"
}
}]);
yield helpers.audit(aOptions, [{
name: "open toolbox",
setup: Task.async(function* () {
let [aTab, aDebuggee, aPanel] = yield initDebugger(gBrowser.selectedTab);
// Spin the event loop before causing the debuggee to pause, to allow this
// function to return first.
executeSoon(() => aDebuggee.firstCall());
yield waitForSourceAndCaretAndScopes(aPanel, ".html", 1);
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gThreadClient = gPanel.panelWin.gThreadClient;
gLineNumber = yield ContentTask.spawn(aOptions.browser, {}, function* () {
return "" + content.wrappedJSObject.gLineNumber;
});
gSources = gDebugger.DebuggerView.Sources;
expectedActorObj.value = getSourceActor(gSources, TAB_URL);
}),
post: function () {
ok(gThreadClient, "Debugger client exists.");
is(gLineNumber, 14, "gLineNumber is correct.");
},
}]);
yield helpers.audit(aOptions, [{
name: "break add line .../doc_cmd-break.html 14",
setup: function () {
// We have to setup in a function to allow gLineNumber to be initialized.
let line = "break add line " + TAB_URL + " " + gLineNumber;
return helpers.setInput(aOptions, line);
},
check: {
hints: "",
status: "VALID",
message: "",
args: {
file: expectedActorObj,
line: { value: 14 }
}
},
exec: {
output: "Added breakpoint"
}
}]);
yield helpers.audit(aOptions, [{
setup: "break add line " + TAB_URL + " 17",
check: {
hints: "",
status: "VALID",
message: "",
args: {
file: expectedActorObj,
line: { value: 17 }
}
},
exec: {
output: "Added breakpoint"
}
}]);
yield helpers.audit(aOptions, [{
setup: "break list",
check: {
input: "break list",
hints: "",
markup: "VVVVVVVVVV",
status: "VALID"
},
exec: {
output: [
/Source/, /Remove/,
/doc_cmd-break\.html:14/,
/doc_cmd-break\.html:17/
]
}
}]);
yield helpers.audit(aOptions, [{
name: "cleanup",
setup: function () {
let deferred = promise.defer();
gThreadClient.resume(deferred.resolve);
return deferred.promise;
}
}]);
yield helpers.audit(aOptions, [{
setup: "break del 14",
check: {
input: "break del 14",
hints: " -> doc_cmd-break.html:14",
markup: "VVVVVVVVVVII",
status: "ERROR",
args: {
breakpoint: {
status: "INCOMPLETE",
message: "Value required for \u2018breakpoint\u2019."
}
}
}
}]);
yield helpers.audit(aOptions, [{
setup: "break del doc_cmd-break.html:14",
check: {
input: "break del doc_cmd-break.html:14",
hints: "",
markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV",
status: "VALID",
args: {
breakpoint: { arg: " doc_cmd-break.html:14" },
}
},
exec: {
output: "Breakpoint removed"
}
}]);
yield helpers.audit(aOptions, [{
setup: "break list",
check: {
input: "break list",
hints: "",
markup: "VVVVVVVVVV",
status: "VALID"
},
exec: {
output: [
/Source/, /Remove/,
/doc_cmd-break\.html:17/
]
}
}]);
yield helpers.audit(aOptions, [{
setup: "break del doc_cmd-break.html:17",
check: {
input: "break del doc_cmd-break.html:17",
hints: "",
markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV",
status: "VALID",
args: {
breakpoint: { arg: " doc_cmd-break.html:17" },
}
},
exec: {
output: "Breakpoint removed"
}
}]);
yield helpers.audit(aOptions, [{
setup: "break list",
check: {
input: "break list",
hints: "",
markup: "VVVVVVVVVV",
status: "VALID"
},
exec: {
output: "No breakpoints set"
},
post: function () {
return teardown(gPanel, { noTabRemoval: true });
}
}]);
});
}).then(finish);
}

View file

@ -0,0 +1,102 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that the debugger commands work as they should.
*/
const TEST_URI = EXAMPLE_URL + "doc_cmd-dbg.html";
function test() {
return Task.spawn(function* () {
let options = yield helpers.openTab(TEST_URI);
yield helpers.openToolbar(options);
yield helpers.audit(options, [{
setup: "dbg open",
exec: { output: "" }
}]);
let [gTab, gDebuggee, gPanel] = yield initDebugger(gBrowser.selectedTab);
let gDebugger = gPanel.panelWin;
let gThreadClient = gDebugger.gThreadClient;
yield helpers.audit(options, [{
setup: "dbg list",
exec: { output: /doc_cmd-dbg.html/ }
}]);
let button = gDebuggee.document.querySelector("input[type=button]");
let output = gDebuggee.document.querySelector("input[type=text]");
let cmd = function (aTyped, aState) {
return promise.all([
waitForThreadEvents(gPanel, aState),
helpers.audit(options, [{ setup: aTyped, exec: { output: "" } }])
]);
};
let click = function (aElement, aState) {
return promise.all([
waitForThreadEvents(gPanel, aState),
executeSoon(() => EventUtils.sendMouseEvent({ type: "click" }, aElement, gDebuggee))
]);
};
yield cmd("dbg interrupt", "paused");
is(gThreadClient.state, "paused", "Debugger is paused.");
yield cmd("dbg continue", "resumed");
isnot(gThreadClient.state, "paused", "Debugger has continued.");
yield click(button, "paused");
is(gThreadClient.state, "paused", "Debugger is paused again.");
yield cmd("dbg step in", "paused");
yield cmd("dbg step in", "paused");
yield cmd("dbg step in", "paused");
is(output.value, "step in", "Debugger stepped in.");
yield cmd("dbg step over", "paused");
is(output.value, "step over", "Debugger stepped over.");
yield cmd("dbg step out", "paused");
is(output.value, "step out", "Debugger stepped out.");
yield cmd("dbg continue", "paused");
is(output.value, "dbg continue", "Debugger continued.");
let closeDebugger = function () {
let deferred = promise.defer();
helpers.audit(options, [{
setup: "dbg close",
exec: { output: "" }
}])
.then(() => {
let toolbox = gDevTools.getToolbox(options.target);
if (!toolbox) {
ok(true, "Debugger is closed.");
deferred.resolve();
} else {
toolbox.on("destroyed", () => {
ok(true, "Debugger just closed.");
deferred.resolve();
});
}
});
return deferred.promise;
};
// We close the debugger twice to ensure 'dbg close' doesn't error when
// toolbox is already closed. See bug 884638 for more info.
yield closeDebugger();
yield closeDebugger();
yield helpers.closeToolbar(options);
yield helpers.closeTab(options);
}).then(finish, helpers.handleError);
}

View file

@ -0,0 +1,218 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Bug 740825: Test the debugger conditional breakpoints.
*/
const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
function test() {
// Linux debug test slaves are a bit slow at this test sometimes.
requestLongerTimeout(2);
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gEditor = gDebugger.DebuggerView.editor;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require("./content/queries");
const constants = gDebugger.require("./content/constants");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
// This test forces conditional breakpoints to be evaluated on the
// client-side
var client = gPanel.target.client;
client.mainRoot.traits.conditionalBreakpoints = false;
const addBreakpoints = Task.async(function* () {
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 18 },
"undefined");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 19 },
"null");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 20 },
"42");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 21 },
"true");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 22 },
"'nasu'");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 23 },
"/regexp/");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 24 },
"({})");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 25 },
"(function() {})");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 26 },
"(function() { return false; })()");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 27 },
"a");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 28 },
"a !== undefined");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 29 },
"b");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 30 },
"a !== null");
});
function resumeAndTestBreakpoint(line) {
let finished = waitForCaretUpdated(gPanel, line).then(() => testBreakpoint(line));
EventUtils.sendMouseEvent({ type: "mousedown" },
gDebugger.document.getElementById("resume"),
gDebugger);
return finished;
}
function resumeAndTestNoBreakpoint() {
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.AFTER_FRAMES_CLEARED).then(() => {
is(gSources.itemCount, 1,
"Found the expected number of sources.");
is(gEditor.getText().indexOf("ermahgerd"), 253,
"The correct source was loaded initially.");
is(gSources.selectedValue, gSources.values[0],
"The correct source is selected.");
ok(gSources.selectedItem,
"There should be a selected source in the sources pane.");
ok(!gSources._selectedBreakpoint,
"There should be no selected breakpoint in the sources pane.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not be shown.");
is(gDebugger.document.querySelectorAll(".dbg-stackframe").length, 0,
"There should be no visible stackframes.");
is(gDebugger.document.querySelectorAll(".dbg-breakpoint").length, 13,
"There should be thirteen visible breakpoints.");
});
gDebugger.gThreadClient.resume();
return finished;
}
function testBreakpoint(line, highlightBreakpoint) {
// Highlight the breakpoint only if required.
if (highlightBreakpoint) {
let finished = waitForCaretUpdated(gPanel, line).then(() => testBreakpoint(line));
gSources.highlightBreakpoint({ actor: gSources.selectedValue, line: line });
return finished;
}
let selectedActor = gSources.selectedValue;
let selectedBreakpoint = gSources._selectedBreakpoint;
let selectedBreakpointItem = gSources._getBreakpoint(selectedBreakpoint);
ok(selectedActor,
"There should be a selected item in the sources pane.");
ok(selectedBreakpoint,
"There should be a selected breakpoint in the sources pane.");
let source = gSources.selectedItem.attachment.source;
let bp = queries.getBreakpoint(getState(), selectedBreakpoint.location);
ok(bp, "The selected breakpoint exists");
is(bp.location.actor, source.actor,
"The breakpoint on line " + line + " wasn't added on the correct source.");
is(bp.location.line, line,
"The breakpoint on line " + line + " wasn't found.");
is(!!bp.disabled, false,
"The breakpoint on line " + line + " should be enabled.");
is(!!selectedBreakpointItem.attachment.openPopup, false,
"The breakpoint on line " + line + " should not have opened a popup.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not have been shown.");
isnot(bp.condition, undefined,
"The breakpoint on line " + line + " should have a conditional expression.");
ok(isCaretPos(gPanel, line),
"The editor caret position is not properly set.");
}
const testAfterReload = Task.async(function* () {
let selectedActor = gSources.selectedValue;
let selectedBreakpoint = gSources._selectedBreakpoint;
ok(selectedActor,
"There should be a selected item in the sources pane after reload.");
ok(!selectedBreakpoint,
"There should be no selected breakpoint in the sources pane after reload.");
yield testBreakpoint(18, true);
yield testBreakpoint(19, true);
yield testBreakpoint(20, true);
yield testBreakpoint(21, true);
yield testBreakpoint(22, true);
yield testBreakpoint(23, true);
yield testBreakpoint(24, true);
yield testBreakpoint(25, true);
yield testBreakpoint(26, true);
yield testBreakpoint(27, true);
yield testBreakpoint(28, true);
yield testBreakpoint(29, true);
yield testBreakpoint(30, true);
is(gSources.itemCount, 1,
"Found the expected number of sources.");
is(gEditor.getText().indexOf("ermahgerd"), 253,
"The correct source was loaded again.");
is(gSources.selectedValue, gSources.values[0],
"The correct source is selected.");
ok(gSources.selectedItem,
"There should be a selected source in the sources pane.");
ok(gSources._selectedBreakpoint,
"There should be a selected breakpoint in the sources pane.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not be shown.");
});
Task.spawn(function* () {
let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
callInTab(gTab, "ermahgerd");
yield onCaretUpdated;
yield addBreakpoints();
is(gDebugger.gThreadClient.state, "paused",
"Should only be getting stack frames while paused.");
is(queries.getSourceCount(getState()), 1,
"Found the expected number of sources.");
is(gEditor.getText().indexOf("ermahgerd"), 253,
"The correct source was loaded initially.");
is(gSources.selectedValue, gSources.values[0],
"The correct source is selected.");
is(queries.getBreakpoints(getState()).length, 13,
"13 breakpoints currently added.");
yield resumeAndTestBreakpoint(20);
yield resumeAndTestBreakpoint(21);
yield resumeAndTestBreakpoint(22);
yield resumeAndTestBreakpoint(23);
yield resumeAndTestBreakpoint(24);
yield resumeAndTestBreakpoint(25);
yield resumeAndTestBreakpoint(27);
yield resumeAndTestBreakpoint(28);
yield resumeAndTestBreakpoint(29);
yield resumeAndTestBreakpoint(30);
yield resumeAndTestNoBreakpoint();
let sourceShown = waitForSourceShown(gPanel, ".html");
reload(gPanel),
yield sourceShown;
testAfterReload();
// Reset traits back to default value
client.mainRoot.traits.conditionalBreakpoints = true;
closeDebuggerAndFinish(gPanel);
});
});
}

View file

@ -0,0 +1,219 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Bug 740825: Test the debugger conditional breakpoints.
*/
const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gEditor = gDebugger.DebuggerView.editor;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require("./content/queries");
const constants = gDebugger.require("./content/constants");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
const CONDITIONAL_POPUP_SHOWN = gDebugger.EVENTS.CONDITIONAL_BREAKPOINT_POPUP_SHOWN;
// This test forces conditional breakpoints to be evaluated on the
// client-side
var client = gPanel.target.client;
client.mainRoot.traits.conditionalBreakpoints = false;
function addBreakpoint1() {
return actions.addBreakpoint({ actor: gSources.selectedValue, line: 18 });
}
function addBreakpoint2() {
let finished = waitForDispatch(gPanel, constants.ADD_BREAKPOINT);
setCaretPosition(19);
gSources._onCmdAddBreakpoint();
return finished;
}
function modBreakpoint2() {
setCaretPosition(19);
let popupShown = waitForDebuggerEvents(gPanel, CONDITIONAL_POPUP_SHOWN);
gSources._onCmdAddConditionalBreakpoint();
return popupShown;
}
function* addBreakpoint3() {
let finished = waitForDispatch(gPanel, constants.ADD_BREAKPOINT);
let popupShown = waitForDebuggerEvents(gPanel, CONDITIONAL_POPUP_SHOWN);
setCaretPosition(20);
gSources._onCmdAddConditionalBreakpoint();
yield finished;
yield popupShown;
}
function* modBreakpoint3() {
setCaretPosition(20);
let popupShown = waitForDebuggerEvents(gPanel, CONDITIONAL_POPUP_SHOWN);
gSources._onCmdAddConditionalBreakpoint();
yield popupShown;
typeText(gSources._cbTextbox, "bamboocha");
let finished = waitForDispatch(gPanel, constants.SET_BREAKPOINT_CONDITION);
EventUtils.sendKey("RETURN", gDebugger);
yield finished;
}
function addBreakpoint4() {
let finished = waitForDispatch(gPanel, constants.ADD_BREAKPOINT);
setCaretPosition(21);
gSources._onCmdAddBreakpoint();
return finished;
}
function delBreakpoint4() {
let finished = waitForDispatch(gPanel, constants.REMOVE_BREAKPOINT);
setCaretPosition(21);
gSources._onCmdAddBreakpoint();
return finished;
}
function testBreakpoint(aLine, aPopupVisible, aConditionalExpression) {
const source = queries.getSelectedSource(getState());
ok(source,
"There should be a selected item in the sources pane.");
const bp = queries.getBreakpoint(getState(), {
actor: source.actor,
line: aLine
});
const bpItem = gSources._getBreakpoint(bp);
ok(bp, "There should be a breakpoint.");
ok(bpItem, "There should be a breakpoint in the sources pane.");
is(bp.location.actor, source.actor,
"The breakpoint on line " + aLine + " wasn't added on the correct source.");
is(bp.location.line, aLine,
"The breakpoint on line " + aLine + " wasn't found.");
is(!!bp.disabled, false,
"The breakpoint on line " + aLine + " should be enabled.");
is(gSources._conditionalPopupVisible, aPopupVisible,
"The breakpoint on line " + aLine + " should have a correct popup state (2).");
is(bp.condition, aConditionalExpression,
"The breakpoint on line " + aLine + " should have a correct conditional expression.");
}
function testNoBreakpoint(aLine) {
let selectedActor = gSources.selectedValue;
let selectedBreakpoint = gSources._selectedBreakpoint;
ok(selectedActor,
"There should be a selected item in the sources pane for line " + aLine + ".");
ok(!selectedBreakpoint,
"There should be no selected brekapoint in the sources pane for line " + aLine + ".");
ok(isCaretPos(gPanel, aLine),
"The editor caret position is not properly set.");
}
function setCaretPosition(aLine) {
gEditor.setCursor({ line: aLine - 1, ch: 0 });
}
function clickOnBreakpoint(aIndex) {
EventUtils.sendMouseEvent({ type: "click" },
gDebugger.document.querySelectorAll(".dbg-breakpoint")[aIndex],
gDebugger);
}
function waitForConditionUpdate() {
// This will close the popup and send another request to update
// the condition
gSources._hideConditionalPopup();
return waitForDispatch(gPanel, constants.SET_BREAKPOINT_CONDITION);
}
Task.spawn(function* () {
let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
callInTab(gTab, "ermahgerd");
yield onCaretUpdated;
is(gDebugger.gThreadClient.state, "paused",
"Should only be getting stack frames while paused.");
is(queries.getSourceCount(getState()), 1,
"Found the expected number of sources.");
is(gEditor.getText().indexOf("ermahgerd"), 253,
"The correct source was loaded initially.");
is(gSources.selectedValue, gSources.values[0],
"The correct source is selected.");
is(queries.getBreakpoints(getState()).length, 0,
"No breakpoints currently added.");
yield addBreakpoint1();
testBreakpoint(18, false, undefined);
yield addBreakpoint2();
testBreakpoint(19, false, undefined);
yield modBreakpoint2();
testBreakpoint(19, true, undefined);
yield waitForConditionUpdate();
yield addBreakpoint3();
testBreakpoint(20, true, "");
yield waitForConditionUpdate();
yield modBreakpoint3();
testBreakpoint(20, false, "bamboocha");
yield addBreakpoint4();
testBreakpoint(21, false, undefined);
yield delBreakpoint4();
setCaretPosition(18);
is(gSources._selectedBreakpoint.location.line, 18,
"The selected breakpoint is line 18");
yield testBreakpoint(18, false, undefined);
setCaretPosition(19);
is(gSources._selectedBreakpoint.location.line, 19,
"The selected breakpoint is line 19");
yield testBreakpoint(19, false, "");
setCaretPosition(20);
is(gSources._selectedBreakpoint.location.line, 20,
"The selected breakpoint is line 20");
yield testBreakpoint(20, false, "bamboocha");
setCaretPosition(17);
yield testNoBreakpoint(17);
setCaretPosition(21);
yield testNoBreakpoint(21);
clickOnBreakpoint(0);
is(gSources._selectedBreakpoint.location.line, 18,
"The selected breakpoint is line 18");
yield testBreakpoint(18, false, undefined);
clickOnBreakpoint(1);
is(gSources._selectedBreakpoint.location.line, 19,
"The selected breakpoint is line 19");
yield testBreakpoint(19, false, "");
clickOnBreakpoint(2);
is(gSources._selectedBreakpoint.location.line, 20,
"The selected breakpoint is line 20");
testBreakpoint(20, true, "bamboocha");
// Reset traits back to default value
client.mainRoot.traits.conditionalBreakpoints = true;
resumeDebuggerThenCloseAndFinish(gPanel);
});
});
}

View file

@ -0,0 +1,78 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that conditional breakpoint expressions survive disabled breakpoints.
*/
const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
function test() {
initDebugger().then(([aTab,, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require("./content/queries");
const constants = gDebugger.require("./content/constants");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
// This test forces conditional breakpoints to be evaluated on the
// client-side
var client = gPanel.target.client;
client.mainRoot.traits.conditionalBreakpoints = false;
function waitForConditionUpdate() {
// This will close the popup and send another request to update
// the condition
gSources._hideConditionalPopup();
return waitForDispatch(gPanel, constants.SET_BREAKPOINT_CONDITION);
}
Task.spawn(function* () {
let onCaretUpdated = waitForCaretUpdated(gPanel, 17);
yield navigateActiveTabTo(gPanel,
TAB_URL,
gDebugger.EVENTS.SOURCE_SHOWN);
callInTab(gTab, "ermahgerd");
yield onCaretUpdated;
const location = { actor: gSources.selectedValue, line: 18 };
yield actions.addBreakpoint(location, "hello");
yield actions.disableBreakpoint(location);
yield actions.addBreakpoint(location);
const bp = queries.getBreakpoint(getState(), location);
is(bp.condition, "hello", "The conditional expression is correct.");
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.CONDITIONAL_BREAKPOINT_POPUP_SHOWN);
EventUtils.sendMouseEvent({ type: "click" },
gDebugger.document.querySelector(".dbg-breakpoint"),
gDebugger);
yield finished;
const textbox = gDebugger.document.getElementById("conditional-breakpoint-panel-textbox");
is(textbox.value, "hello", "The expression is correct (2).");
yield waitForConditionUpdate();
yield actions.disableBreakpoint(location);
yield actions.setBreakpointCondition(location, "foo");
yield actions.addBreakpoint(location);
finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.CONDITIONAL_BREAKPOINT_POPUP_SHOWN);
EventUtils.sendMouseEvent({ type: "click" },
gDebugger.document.querySelector(".dbg-breakpoint"),
gDebugger);
yield finished;
is(textbox.value, "foo", "The expression is correct (3).");
// Reset traits back to default value
client.mainRoot.traits.conditionalBreakpoints = true;
resumeDebuggerThenCloseAndFinish(gPanel);
});
});
}

View file

@ -0,0 +1,52 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that conditional breakpoints with blank expressions
* maintain their conditions after enabling them.
*/
const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require("./content/queries");
const constants = gDebugger.require("./content/constants");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
// This test forces conditional breakpoints to be evaluated on the
// client-side
var client = gPanel.target.client;
client.mainRoot.traits.conditionalBreakpoints = false;
Task.spawn(function* () {
let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
callInTab(gTab, "ermahgerd");
yield onCaretUpdated;
const location = { actor: gSources.selectedValue, line: 18 };
yield actions.addBreakpoint(location, "");
yield actions.disableBreakpoint(location);
yield actions.addBreakpoint(location);
const bp = queries.getBreakpoint(getState(), location);
is(bp.condition, "", "The conditional expression is correct.");
// Reset traits back to default value
client.mainRoot.traits.conditionalBreakpoints = true;
resumeDebuggerThenCloseAndFinish(gPanel);
});
});
}

View file

@ -0,0 +1,141 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that conditional breakpoints with an exception-throwing expression
* could pause on hit
*/
const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gEditor = gDebugger.DebuggerView.editor;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require("./content/queries");
const constants = gDebugger.require("./content/constants");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
// This test forces conditional breakpoints to be evaluated on the
// client-side
var client = gPanel.target.client;
client.mainRoot.traits.conditionalBreakpoints = false;
function resumeAndTestBreakpoint(line) {
let finished = waitForCaretUpdated(gPanel, line).then(() => testBreakpoint(line));
EventUtils.sendMouseEvent({ type: "mousedown" },
gDebugger.document.getElementById("resume"),
gDebugger);
return finished;
}
function resumeAndTestNoBreakpoint() {
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.AFTER_FRAMES_CLEARED).then(() => {
is(gSources.itemCount, 1,
"Found the expected number of sources.");
is(gEditor.getText().indexOf("ermahgerd"), 253,
"The correct source was loaded initially.");
is(gSources.selectedValue, gSources.values[0],
"The correct source is selected.");
ok(gSources.selectedItem,
"There should be a selected source in the sources pane.");
ok(!gSources._selectedBreakpoint,
"There should be no selected breakpoint in the sources pane.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not be shown.");
is(gDebugger.document.querySelectorAll(".dbg-stackframe").length, 0,
"There should be no visible stackframes.");
is(gDebugger.document.querySelectorAll(".dbg-breakpoint").length, 6,
"There should be thirteen visible breakpoints.");
});
gDebugger.gThreadClient.resume();
return finished;
}
function testBreakpoint(line, highlightBreakpoint) {
// Highlight the breakpoint only if required.
if (highlightBreakpoint) {
let finished = waitForCaretUpdated(gPanel, line).then(() => testBreakpoint(line));
gSources.highlightBreakpoint({ actor: gSources.selectedValue, line: line });
return finished;
}
let selectedActor = gSources.selectedValue;
let selectedBreakpoint = gSources._selectedBreakpoint;
let selectedBreakpointItem = gSources._getBreakpoint(selectedBreakpoint);
let source = queries.getSource(getState(), selectedActor);
ok(selectedActor,
"There should be a selected item in the sources pane.");
ok(selectedBreakpoint,
"There should be a selected breakpoint.");
ok(selectedBreakpointItem,
"There should be a selected breakpoint item in the sources pane.");
is(selectedBreakpoint.location.actor, source.actor,
"The breakpoint on line " + line + " wasn't added on the correct source.");
is(selectedBreakpoint.location.line, line,
"The breakpoint on line " + line + " wasn't found.");
is(!!selectedBreakpoint.location.disabled, false,
"The breakpoint on line " + line + " should be enabled.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not have been shown.");
isnot(selectedBreakpoint.condition, undefined,
"The breakpoint on line " + line + " should have a conditional expression.");
ok(isCaretPos(gPanel, line),
"The editor caret position is not properly set.");
}
Task.spawn(function* () {
let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
callInTab(gTab, "ermahgerd");
yield onCaretUpdated;
yield actions.addBreakpoint(
{ actor: gSources.selectedValue, line: 18 }, " 1a"
);
yield actions.addBreakpoint(
{ actor: gSources.selectedValue, line: 19 }, "new Error()"
);
yield actions.addBreakpoint(
{ actor: gSources.selectedValue, line: 20 }, "true"
);
yield actions.addBreakpoint(
{ actor: gSources.selectedValue, line: 21 }, "false"
);
yield actions.addBreakpoint(
{ actor: gSources.selectedValue, line: 22 }, "0"
);
yield actions.addBreakpoint(
{ actor: gSources.selectedValue, line: 23 }, "randomVar"
);
yield resumeAndTestBreakpoint(18);
yield resumeAndTestBreakpoint(19);
yield resumeAndTestBreakpoint(20);
yield resumeAndTestBreakpoint(23);
yield resumeAndTestNoBreakpoint();
// Reset traits back to default value
client.mainRoot.traits.conditionalBreakpoints = true;
closeDebuggerAndFinish(gPanel);
});
});
}

View file

@ -0,0 +1,41 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Breaking in the middle of a script evaluated by the console should
* work
*/
function test() {
Task.spawn(function* () {
let TAB_URL = EXAMPLE_URL + "doc_empty-tab-01.html";
let [,, panel] = yield initDebugger(TAB_URL, { source: null });
let dbgWin = panel.panelWin;
let sources = dbgWin.DebuggerView.Sources;
let frames = dbgWin.DebuggerView.StackFrames;
let editor = dbgWin.DebuggerView.editor;
let toolbox = gDevTools.getToolbox(panel.target);
let paused = promise.all([
waitForEditorEvents(panel, "cursorActivity"),
waitForDebuggerEvents(panel, dbgWin.EVENTS.SOURCE_SHOWN)
]);
toolbox.once("webconsole-ready", () => {
ok(toolbox.splitConsole, "Split console is shown.");
let jsterm = toolbox.getPanel("webconsole").hud.jsterm;
jsterm.execute("debugger");
});
EventUtils.synthesizeKey("VK_ESCAPE", {}, dbgWin);
yield paused;
is(sources.selectedItem.attachment.label, "SCRIPT0",
"Anonymous source is selected in sources");
ok(editor.getText() === "debugger", "Editor has correct text");
yield toolbox.closeSplitConsole();
yield resumeDebuggerThenCloseAndFinish(panel);
});
}

View file

@ -0,0 +1,42 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Breaking in the middle of a named eval script created by the
* console should work
*/
function test() {
Task.spawn(runTests);
}
function* runTests() {
let TAB_URL = EXAMPLE_URL + "doc_empty-tab-01.html";
let [,, panel] = yield initDebugger(TAB_URL, { source: null });
let dbgWin = panel.panelWin;
let sources = dbgWin.DebuggerView.Sources;
let frames = dbgWin.DebuggerView.StackFrames;
let editor = dbgWin.DebuggerView.editor;
let toolbox = gDevTools.getToolbox(panel.target);
let paused = waitForSourceAndCaretAndScopes(panel, "foo.js", 1);
toolbox.once("webconsole-ready", () => {
ok(toolbox.splitConsole, "Split console is shown.");
let jsterm = toolbox.getPanel("webconsole").hud.jsterm;
jsterm.execute("eval('debugger; //# sourceURL=foo.js')");
});
EventUtils.synthesizeKey("VK_ESCAPE", {}, dbgWin);
yield paused;
is(sources.selectedItem.attachment.label, "foo.js",
"New source is selected in sources");
is(sources.selectedItem.attachment.group, "http://example.com",
"New source is in the right group");
ok(editor.getText() === "debugger; //# sourceURL=foo.js", "Editor has correct text");
yield toolbox.closeSplitConsole();
yield resumeDebuggerThenCloseAndFinish(panel);
}

View file

@ -0,0 +1,106 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests the public evaluation API from the debugger controller.
*/
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
Task.spawn(function* () {
const options = {
source: EXAMPLE_URL + "code_script-switching-01.js",
line: 1
};
const [tab,, panel] = yield initDebugger(TAB_URL, options);
const win = panel.panelWin;
const frames = win.DebuggerController.StackFrames;
const framesView = win.DebuggerView.StackFrames;
const sourcesView = win.DebuggerView.Sources;
const editorView = win.DebuggerView.editor;
const events = win.EVENTS;
const queries = win.require("./content/queries");
const constants = win.require("./content/constants");
const actions = bindActionCreators(panel);
const getState = win.DebuggerController.getState;
function checkView(frameDepth, selectedSource, caretLine, editorText) {
is(win.gThreadClient.state, "paused",
"Should only be getting stack frames while paused.");
is(framesView.itemCount, 2,
"Should have four frames.");
is(framesView.selectedDepth, frameDepth,
"The correct frame is selected in the widget.");
is(sourcesView.selectedIndex, selectedSource,
"The correct source is selected in the widget.");
ok(isCaretPos(panel, caretLine),
"Editor caret location is correct.");
is(editorView.getText().search(editorText[0]), editorText[1],
"The correct source is not displayed.");
}
// Cache the sources text to avoid having to wait for their
// retrieval.
const sources = queries.getSources(getState());
yield promise.all(Object.keys(sources).map(k => {
return actions.loadSourceText(sources[k]);
}));
is(Object.keys(getState().sources.sourcesText).length, 2,
"There should be two cached sources in the cache.");
// Eval while not paused.
try {
yield frames.evaluate("foo");
} catch (error) {
is(error.message, "No stack frame available.",
"Evaluating shouldn't work while the debuggee isn't paused.");
}
callInTab(tab, "firstCall");
yield waitForSourceAndCaretAndScopes(panel, "-02.js", 6);
checkView(0, 1, 6, [/secondCall/, 118]);
// Eval in the topmost frame, while paused.
let updatedView = waitForDebuggerEvents(panel, events.FETCHED_SCOPES);
let result = yield frames.evaluate("foo");
ok(!result.throw, "The evaluation hasn't thrown.");
is(result.return.type, "object", "The evaluation return type is correct.");
is(result.return.class, "Function", "The evaluation return class is correct.");
yield updatedView;
checkView(0, 1, 6, [/secondCall/, 118]);
ok(true, "Evaluating in the topmost frame works properly.");
// Eval in a different frame, while paused.
updatedView = waitForDebuggerEvents(panel, events.FETCHED_SCOPES);
try {
yield frames.evaluate("foo", { depth: 1 }); // oldest frame
} catch (result) {
is(result.return.type, "object", "The evaluation thrown type is correct.");
is(result.return.class, "Error", "The evaluation thrown class is correct.");
ok(!result.return, "The evaluation hasn't returned.");
}
yield updatedView;
checkView(0, 1, 6, [/secondCall/, 118]);
ok(true, "Evaluating in a custom frame works properly.");
// Eval in a non-existent frame, while paused.
waitForDebuggerEvents(panel, events.FETCHED_SCOPES).then(() => {
ok(false, "Shouldn't have updated the view when trying to evaluate " +
"an expression in a non-existent stack frame.");
});
try {
yield frames.evaluate("foo", { depth: 4 }); // non-existent frame
} catch (error) {
is(error.message, "No stack frame available.",
"Evaluating shouldn't work if the specified frame doesn't exist.");
}
yield resumeDebuggerThenCloseAndFinish(panel);
});
}

Some files were not shown because too many files have changed in this diff Show more