browser_document_tracer.js (3347B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 const JS_CODE = ` 7 window.onclick = function foo() { 8 setTimeout(function bar() { 9 dump("click and timed out\n"); 10 subFunction(); 11 document.documentElement.setAttribute("foo", "bar"); 12 }); 13 function subFunction() { nestedSubFunction(); }; 14 function nestedSubFunction() {}; 15 }; 16 window.scriptReady = true; 17 `; 18 const TEST_URL = 19 "data:text/html,<!DOCTYPE html><html><script>" + JS_CODE + " </script>"; 20 21 add_task(async function testTracingDocument() { 22 const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL); 23 24 await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { 25 info("Wait for scriptReady on the window object"); 26 await ContentTaskUtils.waitForCondition( 27 () => content.wrappedJSObject.scriptReady 28 ); 29 30 const { JSTracer } = ChromeUtils.importESModule( 31 "resource://devtools/server/tracer/tracer.sys.mjs", 32 { global: "shared" } 33 ); 34 35 // We have to fake opening DevTools otherwise DebuggerNotificationObserver wouldn't work 36 // and the tracer wouldn't be able to trace the DOM events. 37 ChromeUtils.notifyDevToolsOpened(); 38 39 const frames = []; 40 const mutations = []; 41 const listener = { 42 onTracingFrame(frameInfo) { 43 frames.push(frameInfo); 44 }, 45 onTracingDOMMutation(mutation) { 46 mutations.push(mutation); 47 }, 48 }; 49 info("Register a tracing listener"); 50 JSTracer.addTracingListener(listener); 51 52 info("Start tracing the iframe"); 53 JSTracer.startTracing({ 54 global: content, 55 traceDOMEvents: true, 56 traceDOMMutations: ["attributes"], 57 }); 58 59 info("Dispatch a click event on the iframe"); 60 EventUtils.synthesizeMouseAtCenter( 61 content.document.documentElement, 62 {}, 63 content 64 ); 65 66 info("Wait for the traces generated by this click"); 67 await ContentTaskUtils.waitForCondition(() => frames.length == 4); 68 info("Wait for the mutation to be notified"); 69 await ContentTaskUtils.waitForCondition(() => mutations.length == 1); 70 71 const firstFrame = frames[0]; 72 is(firstFrame.formatedDisplayName, "λ foo"); 73 is(firstFrame.currentDOMEvent, "global.click"); 74 is(firstFrame.depth, 0); 75 76 const secondFrame = frames[1]; 77 is(secondFrame.formatedDisplayName, "λ bar"); 78 is(secondFrame.currentDOMEvent, "setTimeoutCallback"); 79 is(secondFrame.depth, 0); 80 81 const thirdFrame = frames[2]; 82 is(thirdFrame.formatedDisplayName, "λ subFunction"); 83 is(thirdFrame.currentDOMEvent, "setTimeoutCallback"); 84 is(thirdFrame.depth, 1); 85 86 const lastFrame = frames[3]; 87 is(lastFrame.formatedDisplayName, "λ nestedSubFunction"); 88 is(lastFrame.currentDOMEvent, "setTimeoutCallback"); 89 is(lastFrame.depth, 2); 90 91 const mutation = mutations[0]; 92 is(mutation.type, "attributes"); 93 is(mutation.element, content.document.documentElement); 94 is(mutation.caller.filename, content.document.location.href); 95 // ensure that the depth is correct and the DOM Mutation is nested to `bar` and not `subFunction` or `nestedSubFunction` 96 is(mutation.depth, 1); 97 98 JSTracer.stopTracing(); 99 JSTracer.removeTracingListener(listener); 100 101 ChromeUtils.notifyDevToolsClosed(); 102 }); 103 104 BrowserTestUtils.removeTab(tab); 105 });