diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-dom-mutation-breakpoints.js b/devtools/client/debugger/test/mochitest/browser_dbg-dom-mutation-breakpoints.js index b8902082d629..d62e48433f9a 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg-dom-mutation-breakpoints.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-dom-mutation-breakpoints.js @@ -28,21 +28,45 @@ add_task(async function() { const { inspector, toolbox } = await openInspectorForURL(DMB_TEST_URL); - info("Selecting the body node"); - await selectNode("body", inspector); + { + info("Selecting the body node"); + await selectNode("body", inspector); - info("Adding DOM mutation breakpoints to body"); - const allMenuItems = openContextMenuAndGetAllItems(inspector); + info("Adding DOM mutation breakpoints to body"); + const allMenuItems = openContextMenuAndGetAllItems(inspector); - const attributeMenuItem = allMenuItems.find( - item => item.id === "node-menu-mutation-breakpoint-attribute" - ); - attributeMenuItem.click(); + const attributeMenuItem = allMenuItems.find( + item => item.id === "node-menu-mutation-breakpoint-attribute" + ); + attributeMenuItem.click(); - const subtreeMenuItem = allMenuItems.find( - item => item.id === "node-menu-mutation-breakpoint-subtree" - ); - subtreeMenuItem.click(); + const subtreeMenuItem = allMenuItems.find( + item => item.id === "node-menu-mutation-breakpoint-subtree" + ); + subtreeMenuItem.click(); + } + + { + info("Find and expand the shadow host."); + const hostFront = await getNodeFront("#host", inspector); + const hostContainer = inspector.markup.getContainer(hostFront); + await expandContainer(inspector, hostContainer); + + info("Expand the shadow root"); + const shadowRootContainer = hostContainer.getChildContainers()[0]; + await expandContainer(inspector, shadowRootContainer); + + info("Select the div under the shadow root"); + const divContainer = shadowRootContainer.getChildContainers()[0]; + await selectNode(divContainer.node, inspector); + + const allMenuItems = openContextMenuAndGetAllItems(inspector); + info("Adding attribute breakpoint."); + const attributeMenuItem = allMenuItems.find( + item => item.id === "node-menu-mutation-breakpoint-attribute" + ); + attributeMenuItem.click(); + } info("Switches over to the debugger pane"); await toolbox.selectTool("jsdebugger"); @@ -84,6 +108,13 @@ add_task(async function() { await waitForPaused(dbg); await resume(dbg); + info("Changing attribute in shadow dom to trigger debugger pause"); + SpecialPowers.spawn(gBrowser.selectedBrowser, [], function() { + content.document.querySelector("#shadow-attribute").click(); + }); + await waitForPaused(dbg); + await resume(dbg); + info("Adding element in subtree to trigger debugger pause"); SpecialPowers.spawn(gBrowser.selectedBrowser, [], function() { content.document.querySelector("#add-in-subtree").click(); @@ -94,7 +125,7 @@ add_task(async function() { ); is( whyPaused, - `Paused on DOM mutation\nDOM Mutation: 'subtreeModified'\nbodyAdded:div` + `Paused on DOM mutation\nDOM Mutation: 'subtreeModified'\nbodyAdded:div#dynamic` ); await resume(dbg); @@ -109,7 +140,7 @@ add_task(async function() { ); is( whyPaused, - `Paused on DOM mutation\nDOM Mutation: 'subtreeModified'\nbodyRemoved:div` + `Paused on DOM mutation\nDOM Mutation: 'subtreeModified'\nbodyRemoved:div#dynamic` ); await resume(dbg); @@ -136,5 +167,5 @@ add_task(async function() { info("Removing breakpoints works"); dbg.win.document.querySelector(".dom-mutation-list .close-btn").click(); - await waitForAllElements(dbg, "domMutationItem", 1, true); + await waitForAllElements(dbg, "domMutationItem", 2, true); }); diff --git a/devtools/client/debugger/test/mochitest/examples/doc-dom-mutation.html b/devtools/client/debugger/test/mochitest/examples/doc-dom-mutation.html index 9bc32aafee22..e7ff809457f2 100644 --- a/devtools/client/debugger/test/mochitest/examples/doc-dom-mutation.html +++ b/devtools/client/debugger/test/mochitest/examples/doc-dom-mutation.html @@ -11,9 +11,11 @@ + +
diff --git a/devtools/client/debugger/test/mochitest/examples/dom-mutation.js b/devtools/client/debugger/test/mochitest/examples/dom-mutation.js index e98e0a1e54af..7de3ca72eb49 100644 --- a/devtools/client/debugger/test/mochitest/examples/dom-mutation.js +++ b/devtools/client/debugger/test/mochitest/examples/dom-mutation.js @@ -8,11 +8,19 @@ function changeStyleAttribute() { } function addDivToBody() { - document.body.appendChild(document.createElement("div")); + let div = document.createElement("div"); + div.id = "dynamic"; + document.body.appendChild(div); } function removeDivInBody() { - document.body.querySelector("div").remove(); + document.body.querySelector("#dynamic").remove(); } +function changeAttributeInShadow() { + document.getElementById("host").shadowRoot.querySelector("div").classList.toggle("red"); +} + +document.getElementById("host").attachShadow({ mode: "open" }).innerHTML = `
`; + //# sourceMappingURL=dom-mutation.js.map diff --git a/devtools/client/inspector/test/head.js b/devtools/client/inspector/test/head.js index 042ffaaf08c3..0de3453edc78 100644 --- a/devtools/client/inspector/test/head.js +++ b/devtools/client/inspector/test/head.js @@ -793,39 +793,6 @@ function getHighlighterTestHelpers(inspector) { }; } -// The expand all operation of the markup-view calls itself recursively and -// there's not one event we can wait for to know when it's done so use this -// helper function to wait until all recursive children updates are done. -async function waitForMultipleChildrenUpdates(inspector) { - // As long as child updates are queued up while we wait for an update already - // wait again - if ( - inspector.markup._queuedChildUpdates && - inspector.markup._queuedChildUpdates.size - ) { - await waitForChildrenUpdated(inspector); - return waitForMultipleChildrenUpdates(inspector); - } - return null; -} - -/** - * Using the markupview's _waitForChildren function, wait for all queued - * children updates to be handled. - * @param {InspectorPanel} inspector The instance of InspectorPanel currently - * loaded in the toolbox - * @return a promise that resolves when all queued children updates have been - * handled - */ -function waitForChildrenUpdated({ markup }) { - info("Waiting for queued children updates to be handled"); - return new Promise(resolve => { - markup._waitForChildren().then(() => { - executeSoon(resolve); - }); - }); -} - /** * Wait for the toolbox to emit the styleeditor-selected event and when done * wait for the stylesheet identified by href to be loaded in the stylesheet @@ -1119,15 +1086,6 @@ async function toggleShapesHighlighter( } } -/** - * Expand the provided markup container programatically and wait for all children to - * update. - */ -async function expandContainer(inspector, container) { - await inspector.markup.expandNode(container.node); - await waitForMultipleChildrenUpdates(inspector); -} - /** * Toggle the provided markup container by clicking on the expand arrow and waiting for * children to update. Similar to expandContainer helper, but this method diff --git a/devtools/client/inspector/test/shared-head.js b/devtools/client/inspector/test/shared-head.js index 2237fcb57db9..1b2600022421 100644 --- a/devtools/client/inspector/test/shared-head.js +++ b/devtools/client/inspector/test/shared-head.js @@ -260,6 +260,48 @@ var selectNode = async function( await onSelectionCssSelectorsUpdated; }; +/** + * Using the markupview's _waitForChildren function, wait for all queued + * children updates to be handled. + * @param {InspectorPanel} inspector The instance of InspectorPanel currently + * loaded in the toolbox + * @return a promise that resolves when all queued children updates have been + * handled + */ +function waitForChildrenUpdated({ markup }) { + info("Waiting for queued children updates to be handled"); + return new Promise(resolve => { + markup._waitForChildren().then(() => { + executeSoon(resolve); + }); + }); +} + +// The expand all operation of the markup-view calls itself recursively and +// there's not one event we can wait for to know when it's done, so use this +// helper function to wait until all recursive children updates are done. +async function waitForMultipleChildrenUpdates(inspector) { + // As long as child updates are queued up while we wait for an update already + // wait again + if ( + inspector.markup._queuedChildUpdates && + inspector.markup._queuedChildUpdates.size + ) { + await waitForChildrenUpdated(inspector); + return waitForMultipleChildrenUpdates(inspector); + } + return null; +} + +/** + * Expand the provided markup container programmatically and wait for all + * children to update. + */ +async function expandContainer(inspector, container) { + await inspector.markup.expandNode(container.node); + await waitForMultipleChildrenUpdates(inspector); +} + /** * Get the NodeFront for a node that matches a given css selector inside a * given iframe. diff --git a/devtools/server/actors/inspector/walker.js b/devtools/server/actors/inspector/walker.js index f72217fce51f..be824a0298d1 100644 --- a/devtools/server/actors/inspector/walker.js +++ b/devtools/server/actors/inspector/walker.js @@ -1779,7 +1779,10 @@ class WalkerActor extends Actor { } const rawNode = node.rawNode; - if (rawNode.ownerDocument && !rawNode.ownerDocument.contains(rawNode)) { + if ( + rawNode.ownerDocument && + rawNode.getRootNode({ composed: true }) != rawNode.ownerDocument + ) { // We only allow watching for mutations on nodes that are attached to // documents. That allows us to clean up our mutation listeners when all // of the watched nodes have been removed from the document.