/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; const JS_CODE = ` window.onclick = function foo() { setTimeout(function bar() { dump("click and timed out\n"); subFunction(); document.documentElement.setAttribute("foo", "bar"); }); function subFunction() { nestedSubFunction(); }; function nestedSubFunction() {}; }; `; const TEST_URL = "data:text/html,"; add_task(async function testTracingDocument() { const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL); await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { const { JSTracer } = ChromeUtils.importESModule( "resource://devtools/server/tracer/tracer.sys.mjs", { global: "shared" } ); // We have to fake opening DevTools otherwise DebuggerNotificationObserver wouldn't work // and the tracer wouldn't be able to trace the DOM events. ChromeUtils.notifyDevToolsOpened(); const frames = []; const mutations = []; const listener = { onTracingFrame(frameInfo) { frames.push(frameInfo); }, onTracingDOMMutation(mutation) { mutations.push(mutation); }, }; info("Register a tracing listener"); JSTracer.addTracingListener(listener); info("Start tracing the iframe"); JSTracer.startTracing({ global: content, traceDOMEvents: true, traceDOMMutations: ["attributes"], }); info("Dispatch a click event on the iframe"); EventUtils.synthesizeMouseAtCenter( content.document.documentElement, {}, content ); info("Wait for the traces generated by this click"); await ContentTaskUtils.waitForCondition(() => frames.length == 4); info("Wait for the mutation to be notified"); await ContentTaskUtils.waitForCondition(() => mutations.length == 1); const firstFrame = frames[0]; is(firstFrame.formatedDisplayName, "λ foo"); is(firstFrame.currentDOMEvent, "global.click"); is(firstFrame.depth, 0); const secondFrame = frames[1]; is(secondFrame.formatedDisplayName, "λ bar"); is(secondFrame.currentDOMEvent, "setTimeoutCallback"); is(secondFrame.depth, 0); const thirdFrame = frames[2]; is(thirdFrame.formatedDisplayName, "λ subFunction"); is(thirdFrame.currentDOMEvent, "setTimeoutCallback"); is(thirdFrame.depth, 1); const lastFrame = frames[3]; is(lastFrame.formatedDisplayName, "λ nestedSubFunction"); is(lastFrame.currentDOMEvent, "setTimeoutCallback"); is(lastFrame.depth, 2); const mutation = mutations[0]; is(mutation.type, "attributes"); is(mutation.element, content.document.documentElement); is(mutation.caller.filename, content.document.location.href); // ensure that the depth is correct and the DOM Mutation is nested to `bar` and not `subFunction` or `nestedSubFunction` is(mutation.depth, 1); JSTracer.stopTracing(); JSTracer.removeTracingListener(listener); ChromeUtils.notifyDevToolsClosed(); }); BrowserTestUtils.removeTab(tab); });