1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/devtools/debugger/test/browser_dbg_break-on-dom-event.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,230 @@ 1.4 +/* Any copyright is dedicated to the Public Domain. 1.5 + http://creativecommons.org/publicdomain/zero/1.0/ */ 1.6 + 1.7 +/** 1.8 + * Tests that the break-on-dom-events request works. 1.9 + */ 1.10 + 1.11 +const TAB_URL = EXAMPLE_URL + "doc_event-listeners.html"; 1.12 + 1.13 +let gClient, gThreadClient, gInput, gButton; 1.14 + 1.15 +function test() { 1.16 + if (!DebuggerServer.initialized) { 1.17 + DebuggerServer.init(() => true); 1.18 + DebuggerServer.addBrowserActors(); 1.19 + } 1.20 + 1.21 + let transport = DebuggerServer.connectPipe(); 1.22 + gClient = new DebuggerClient(transport); 1.23 + gClient.connect((aType, aTraits) => { 1.24 + is(aType, "browser", 1.25 + "Root actor should identify itself as a browser."); 1.26 + 1.27 + addTab(TAB_URL) 1.28 + .then(() => attachThreadActorForUrl(gClient, TAB_URL)) 1.29 + .then(setupGlobals) 1.30 + .then(pauseDebuggee) 1.31 + .then(testBreakOnAll) 1.32 + .then(testBreakOnDisabled) 1.33 + .then(testBreakOnNone) 1.34 + .then(testBreakOnClick) 1.35 + .then(closeConnection) 1.36 + .then(finish) 1.37 + .then(null, aError => { 1.38 + ok(false, "Got an error: " + aError.message + "\n" + aError.stack); 1.39 + }); 1.40 + }); 1.41 +} 1.42 + 1.43 +function setupGlobals(aThreadClient) { 1.44 + gThreadClient = aThreadClient; 1.45 + gInput = content.document.querySelector("input"); 1.46 + gButton = content.document.querySelector("button"); 1.47 +} 1.48 + 1.49 +function pauseDebuggee() { 1.50 + let deferred = promise.defer(); 1.51 + 1.52 + gClient.addOneTimeListener("paused", (aEvent, aPacket) => { 1.53 + is(aPacket.type, "paused", 1.54 + "We should now be paused."); 1.55 + is(aPacket.why.type, "debuggerStatement", 1.56 + "The debugger statement was hit."); 1.57 + 1.58 + deferred.resolve(); 1.59 + }); 1.60 + 1.61 + // Spin the event loop before causing the debuggee to pause, to allow 1.62 + // this function to return first. 1.63 + executeSoon(triggerButtonClick); 1.64 + 1.65 + return deferred.promise; 1.66 +} 1.67 + 1.68 +// Test pause on all events. 1.69 +function testBreakOnAll() { 1.70 + let deferred = promise.defer(); 1.71 + 1.72 + // Test calling pauseOnDOMEvents from a paused state. 1.73 + gThreadClient.pauseOnDOMEvents("*", (aPacket) => { 1.74 + is(aPacket.error, undefined, 1.75 + "The pause-on-any-event request completed successfully."); 1.76 + 1.77 + gClient.addOneTimeListener("paused", (aEvent, aPacket) => { 1.78 + is(aPacket.why.type, "pauseOnDOMEvents", 1.79 + "A hidden breakpoint was hit."); 1.80 + is(aPacket.frame.callee.name, "keyupHandler", 1.81 + "The keyupHandler is entered."); 1.82 + 1.83 + gClient.addOneTimeListener("paused", (aEvent, aPacket) => { 1.84 + is(aPacket.why.type, "pauseOnDOMEvents", 1.85 + "A hidden breakpoint was hit."); 1.86 + is(aPacket.frame.callee.name, "clickHandler", 1.87 + "The clickHandler is entered."); 1.88 + 1.89 + gClient.addOneTimeListener("paused", (aEvent, aPacket) => { 1.90 + is(aPacket.why.type, "pauseOnDOMEvents", 1.91 + "A hidden breakpoint was hit."); 1.92 + is(aPacket.frame.callee.name, "onchange", 1.93 + "The onchange handler is entered."); 1.94 + 1.95 + gThreadClient.resume(deferred.resolve); 1.96 + }); 1.97 + 1.98 + gThreadClient.resume(triggerInputChange); 1.99 + }); 1.100 + 1.101 + gThreadClient.resume(triggerButtonClick); 1.102 + }); 1.103 + 1.104 + gThreadClient.resume(triggerInputKeyup); 1.105 + }); 1.106 + 1.107 + return deferred.promise; 1.108 +} 1.109 + 1.110 +// Test that removing events from the array disables them. 1.111 +function testBreakOnDisabled() { 1.112 + let deferred = promise.defer(); 1.113 + 1.114 + // Test calling pauseOnDOMEvents from a running state. 1.115 + gThreadClient.pauseOnDOMEvents(["click"], (aPacket) => { 1.116 + is(aPacket.error, undefined, 1.117 + "The pause-on-click-only request completed successfully."); 1.118 + 1.119 + gClient.addListener("paused", unexpectedListener); 1.120 + 1.121 + // This non-capturing event listener is guaranteed to run after the page's 1.122 + // capturing one had a chance to execute and modify window.foobar. 1.123 + once(gInput, "keyup").then(() => { 1.124 + is(content.wrappedJSObject.foobar, "keyupHandler", 1.125 + "No hidden breakpoint was hit."); 1.126 + 1.127 + gClient.removeListener("paused", unexpectedListener); 1.128 + deferred.resolve(); 1.129 + }); 1.130 + 1.131 + triggerInputKeyup(); 1.132 + }); 1.133 + 1.134 + return deferred.promise; 1.135 +} 1.136 + 1.137 +// Test that specifying an empty event array clears all hidden breakpoints. 1.138 +function testBreakOnNone() { 1.139 + let deferred = promise.defer(); 1.140 + 1.141 + // Test calling pauseOnDOMEvents from a running state. 1.142 + gThreadClient.pauseOnDOMEvents([], (aPacket) => { 1.143 + is(aPacket.error, undefined, 1.144 + "The pause-on-none request completed successfully."); 1.145 + 1.146 + gClient.addListener("paused", unexpectedListener); 1.147 + 1.148 + // This non-capturing event listener is guaranteed to run after the page's 1.149 + // capturing one had a chance to execute and modify window.foobar. 1.150 + once(gInput, "keyup").then(() => { 1.151 + is(content.wrappedJSObject.foobar, "keyupHandler", 1.152 + "No hidden breakpoint was hit."); 1.153 + 1.154 + gClient.removeListener("paused", unexpectedListener); 1.155 + deferred.resolve(); 1.156 + }); 1.157 + 1.158 + triggerInputKeyup(); 1.159 + }); 1.160 + 1.161 + return deferred.promise; 1.162 +} 1.163 + 1.164 +// Test pause on a single event. 1.165 +function testBreakOnClick() { 1.166 + let deferred = promise.defer(); 1.167 + 1.168 + // Test calling pauseOnDOMEvents from a running state. 1.169 + gThreadClient.pauseOnDOMEvents(["click"], (aPacket) => { 1.170 + is(aPacket.error, undefined, 1.171 + "The pause-on-click request completed successfully."); 1.172 + 1.173 + gClient.addOneTimeListener("paused", (aEvent, aPacket) => { 1.174 + is(aPacket.why.type, "pauseOnDOMEvents", 1.175 + "A hidden breakpoint was hit."); 1.176 + is(aPacket.frame.callee.name, "clickHandler", 1.177 + "The clickHandler is entered."); 1.178 + 1.179 + gThreadClient.resume(deferred.resolve); 1.180 + }); 1.181 + 1.182 + triggerButtonClick(); 1.183 + }); 1.184 + 1.185 + return deferred.promise; 1.186 +} 1.187 + 1.188 +function closeConnection() { 1.189 + let deferred = promise.defer(); 1.190 + gClient.close(deferred.resolve); 1.191 + return deferred.promise; 1.192 +} 1.193 + 1.194 +function unexpectedListener() { 1.195 + gClient.removeListener("paused", unexpectedListener); 1.196 + ok(false, "An unexpected hidden breakpoint was hit."); 1.197 + gThreadClient.resume(testBreakOnClick); 1.198 +} 1.199 + 1.200 +function triggerInputKeyup() { 1.201 + // Make sure that the focus is not on the input box so that a focus event 1.202 + // will be triggered. 1.203 + window.focus(); 1.204 + gBrowser.selectedBrowser.focus(); 1.205 + gButton.focus(); 1.206 + 1.207 + // Focus the element and wait for focus event. 1.208 + once(gInput, "focus").then(() => { 1.209 + executeSoon(() => { 1.210 + EventUtils.synthesizeKey("e", { shiftKey: 1 }, content); 1.211 + }); 1.212 + }); 1.213 + 1.214 + gInput.focus(); 1.215 +} 1.216 + 1.217 +function triggerButtonClick() { 1.218 + EventUtils.sendMouseEvent({ type: "click" }, gButton); 1.219 +} 1.220 + 1.221 +function triggerInputChange() { 1.222 + gInput.focus(); 1.223 + gInput.value = "foo"; 1.224 + gInput.blur(); 1.225 +} 1.226 + 1.227 +registerCleanupFunction(function() { 1.228 + removeTab(gBrowser.selectedTab); 1.229 + gClient = null; 1.230 + gThreadClient = null; 1.231 + gInput = null; 1.232 + gButton = null; 1.233 +});