author | Panos Astithas <past@mozilla.com> |
Fri, 29 Aug 2014 20:51:24 +0300 | |
changeset 235168 | 337e3aa22117505a66e42628d7eb0f43a8e1e7fa |
parent 235054 | a9f983fdb8a45352fe1e9f9dbee6395a8cca3f5d |
child 235169 | 358d0174fee4da8eeeb3d5e75c6ba3e75545e3e2 |
push id | 57353 |
push user | kwierso@gmail.com |
push date | Mon, 23 Mar 2015 23:51:33 +0000 |
treeherder | mozilla-inbound@7f5abc27fd53 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | ochameau |
bugs | 1054159 |
milestone | 39.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/devtools/debugger/test/browser.ini +++ b/browser/devtools/debugger/test/browser.ini @@ -54,16 +54,17 @@ support-files = 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-search.html doc_global-method-override.html doc_iframes.html doc_included-script.html doc_inline-debugger-statement.html doc_inline-script.html @@ -129,16 +130,18 @@ skip-if = e10s || true # bug 1113935 [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_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-contextmenu-add.js] [browser_dbg_breakpoints-contextmenu.js]
new file mode 100644 --- /dev/null +++ b/browser/devtools/debugger/test/browser_dbg_break-on-dom-event-03.js @@ -0,0 +1,101 @@ +/* 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"; + +let gClient, gThreadClient; + +function test() { + if (!DebuggerServer.initialized) { + DebuggerServer.init(); + DebuggerServer.addBrowserActors(); + } + + let transport = DebuggerServer.connectPipe(); + gClient = new DebuggerClient(transport); + gClient.connect((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(closeConnection) + .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); +} + +function closeConnection() { + let deferred = promise.defer(); + gClient.close(deferred.resolve); + return deferred.promise; +} + +registerCleanupFunction(function() { + gClient = null; + gThreadClient = null; +});
new file mode 100644 --- /dev/null +++ b/browser/devtools/debugger/test/doc_event-listeners-04.html @@ -0,0 +1,23 @@ +<!-- Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ --> +<!doctype html> +<html> + <head> + <meta charset="utf-8"/> + <title>Debugger test page</title> + </head> + + <body> + <button>Click me!</button> + + <script type="text/javascript"> + window.addEventListener("load", function onload() { + var button = document.querySelector("button"); + button.onclick = function () { + debugger; + }; + }); + </script> + </body> + +</html>
--- a/toolkit/devtools/server/actors/script.js +++ b/toolkit/devtools/server/actors/script.js @@ -24,16 +24,17 @@ const { defer, resolve, reject, all } = loader.lazyGetter(this, "Debugger", () => { let Debugger = require("Debugger"); hackDebugger(Debugger); return Debugger; }); loader.lazyRequireGetter(this, "SourceMapConsumer", "source-map", true); loader.lazyRequireGetter(this, "SourceMapGenerator", "source-map", true); loader.lazyRequireGetter(this, "CssLogic", "devtools/styleinspector/css-logic", true); +loader.lazyRequireGetter(this, "events", "sdk/event/core"); let TYPED_ARRAY_CLASSES = ["Uint8Array", "Uint8ClampedArray", "Uint16Array", "Uint32Array", "Int8Array", "Int16Array", "Int32Array", "Float32Array", "Float64Array"]; // Number of items to preview in objects, arrays, maps, sets, lists, // collections, etc. let OBJECT_PREVIEW_MAX_ITEMS = 10; @@ -439,16 +440,17 @@ function ThreadActor(aParent, aGlobal) this._frameActors = []; this._parent = aParent; this._dbg = null; this._gripDepth = 0; this._threadLifetimePool = null; this._tabClosed = false; this._scripts = null; this._sources = null; + this._pauseOnDOMEvents = null; this._options = { useSourceMaps: false, autoBlackBox: false }; this.breakpointActorMap = new BreakpointActorMap; this.sourceActorStore = new SourceActorStore; @@ -462,16 +464,18 @@ function ThreadActor(aParent, aGlobal) this.global = aGlobal; this._allEventsListener = this._allEventsListener.bind(this); this.onNewGlobal = this.onNewGlobal.bind(this); this.onNewSource = this.onNewSource.bind(this); this.uncaughtExceptionHook = this.uncaughtExceptionHook.bind(this); this.onDebuggerStatement = this.onDebuggerStatement.bind(this); this.onNewScript = this.onNewScript.bind(this); + this._onWindowReady = this._onWindowReady.bind(this); + events.on(this._parent, "window-ready", this._onWindowReady); // Set a wrappedJSObject property so |this| can be sent via the observer svc // for the xpcshell harness. this.wrappedJSObject = this; } ThreadActor.prototype = { // Used by the ObjectActor to keep track of the depth of grip() calls. _gripDepth: null, @@ -615,16 +619,17 @@ ThreadActor.prototype = { this.onResume(); } // Blow away our source actor ID store because those IDs are only // valid for this connection. This is ok because we never keep // things like breakpoints across connections. this._sourceActorStore = null; + events.off(this._parent, "window-ready", this._onWindowReady); this.clearDebuggees(); this.conn.removeActorPool(this._threadLifetimePool); this._threadLifetimePool = null; if (this._prettyPrintWorker) { this._prettyPrintWorker.removeEventListener( "error", this._onPrettyPrintError, false); this._prettyPrintWorker.removeEventListener( @@ -1005,16 +1010,26 @@ ThreadActor.prototype = { this._pauseOnDOMEvents = events; let els = Cc["@mozilla.org/eventlistenerservice;1"] .getService(Ci.nsIEventListenerService); els.addListenerForAllEvents(this.global, this._allEventsListener, true); } }, /** + * If we are tasked with breaking on the load event, we have to add the + * listener early enough. + */ + _onWindowReady: function () { + this._maybeListenToEvents({ + pauseOnDOMEvents: this._pauseOnDOMEvents + }); + }, + + /** * Handle a protocol request to resume execution of the debuggee. */ onResume: function (aRequest) { if (this._state !== "paused") { return { error: "wrongState", message: "Can't resume when debuggee isn't paused. Current state is '" + this._state + "'"