summaryrefslogtreecommitdiffstats
path: root/devtools/client/inspector/markup/test/browser_markup_shadowdom_open_debugger.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/inspector/markup/test/browser_markup_shadowdom_open_debugger.js')
-rw-r--r--devtools/client/inspector/markup/test/browser_markup_shadowdom_open_debugger.js152
1 files changed, 152 insertions, 0 deletions
diff --git a/devtools/client/inspector/markup/test/browser_markup_shadowdom_open_debugger.js b/devtools/client/inspector/markup/test/browser_markup_shadowdom_open_debugger.js
new file mode 100644
index 0000000000..f508f777cd
--- /dev/null
+++ b/devtools/client/inspector/markup/test/browser_markup_shadowdom_open_debugger.js
@@ -0,0 +1,152 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that markup view displays a "custom" badge for custom elements.
+// Test that the context menu also has a menu item to show the custom element definition.
+// Test that clicking on any of those opens the debugger.
+// Test that the markup view is correctly updated to show those items if the custom
+// element definition happens after opening the inspector.
+
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/devtools/client/debugger/test/mochitest/shared-head.js",
+ this
+);
+
+const TEST_URL =
+ `data:text/html;charset=utf-8,` +
+ encodeURIComponent(`
+<test-component></test-component>
+<other-component>some-content</other-component>
+
+<script>
+ "use strict";
+ window.attachTestComponent = function() {
+ customElements.define("test-component", class extends HTMLElement {
+ constructor() {
+ super();
+ let shadowRoot = this.attachShadow({mode: "open"});
+ shadowRoot.innerHTML = "<slot>some default content</slot>";
+ }
+ connectedCallback() {}
+ disconnectedCallback() {}
+ });
+ }
+
+ window.defineOtherComponent = function() {
+ customElements.define('other-component', class extends HTMLParagraphElement {
+ constructor() {
+ super();
+ }
+ }, { extends: 'p' });
+ }
+</script>`);
+
+add_task(async function () {
+ const { inspector, toolbox } = await openInspectorForURL(TEST_URL);
+
+ // Test with an element to which we attach a shadow.
+ await runTest(inspector, toolbox, "test-component", "attachTestComponent");
+
+ // Test with an element to which we only add a custom element definition.
+ await runTest(inspector, toolbox, "other-component", "defineOtherComponent");
+});
+
+async function runTest(inspector, toolbox, selector, contentMethod) {
+ // Test element is a regular element (no shadow root or custom element definition).
+ info(`Select <${selector}>.`);
+ await selectNode(selector, inspector);
+ const testFront = await getNodeFront(selector, inspector);
+ const testContainer = inspector.markup.getContainer(testFront);
+ let customBadge = testContainer.elt.querySelector(
+ ".inspector-badge.interactive[data-custom]"
+ );
+
+ // Verify that the "custom" badge and menu item are hidden.
+ ok(!customBadge, "[custom] badge is hidden");
+ let menuItem = getMenuItem("node-menu-jumptodefinition", inspector);
+ ok(
+ !menuItem,
+ selector + ": The menu item was not found in the contextual menu"
+ );
+
+ info(
+ "Call the content method that should attach a custom element definition"
+ );
+ const mutated = waitForMutation(inspector, "customElementDefined");
+ SpecialPowers.spawn(
+ gBrowser.selectedBrowser,
+ [{ contentMethod }],
+ function (args) {
+ content.wrappedJSObject[args.contentMethod]();
+ }
+ );
+ await mutated;
+
+ // Test element should now have a custom element definition.
+
+ // Check that the badge opens the debugger.
+ customBadge = testContainer.elt.querySelector(
+ ".inspector-badge.interactive[data-custom]"
+ );
+ ok(customBadge, "[custom] badge is visible");
+ ok(
+ !customBadge.hasAttribute("aria-pressed"),
+ "[custom] badge is not a toggle button"
+ );
+
+ info("Click on the `custom` badge and verify that the debugger opens.");
+ let onDebuggerReady = toolbox.getPanelWhenReady("jsdebugger");
+ customBadge.click();
+ await onDebuggerReady;
+
+ const debuggerContext = createDebuggerContext(toolbox);
+ await waitUntilDebuggerReady(debuggerContext);
+ ok(true, "The debugger was opened when clicking on the custom badge");
+
+ info("Switch to the inspector");
+ await toolbox.selectTool("inspector");
+
+ // Check that the debugger can be opened with the keyboard.
+ info("Press the Enter key and verify that the debugger opens.");
+ customBadge.focus();
+ onDebuggerReady = toolbox.getPanelWhenReady("jsdebugger");
+ EventUtils.synthesizeKey("VK_RETURN", {}, customBadge.ownerGlobal);
+
+ await onDebuggerReady;
+ await waitUntilDebuggerReady(debuggerContext);
+ ok(true, "The debugger was opened via the keyboard");
+
+ info("Switch to the inspector");
+ await toolbox.selectTool("inspector");
+
+ // Check that the menu item also opens the debugger.
+ menuItem = getMenuItem("node-menu-jumptodefinition", inspector);
+ ok(menuItem, selector + ": The menu item was found in the contextual menu");
+ ok(!menuItem.disabled, selector + ": The menu item is not disabled");
+
+ info("Click on `Jump to Definition` and verify that the debugger opens.");
+ onDebuggerReady = toolbox.getPanelWhenReady("jsdebugger");
+ menuItem.click();
+ await onDebuggerReady;
+
+ await waitUntilDebuggerReady(debuggerContext);
+ ok(true, "The debugger was opened via the context menu");
+
+ info("Switch to the inspector");
+ await toolbox.selectTool("inspector");
+}
+
+function getMenuItem(id, inspector) {
+ const allMenuItems = openContextMenuAndGetAllItems(inspector);
+ return allMenuItems.find(i => i.id === "node-menu-jumptodefinition");
+}
+
+async function waitUntilDebuggerReady(debuggerContext) {
+ info("Wait until source is loaded in the debugger");
+
+ // We have to wait until the debugger has fully loaded the source otherwise
+ // we will get unhandled promise rejections.
+ await waitForLoadedSource(debuggerContext, TEST_URL);
+}