/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; // Test that selector warnings are displayed in the rule-view. const TEST_URI = `
`; const UNCONSTRAINED_HAS_WARNING_MESSAGE = "This selector uses unconstrained :has(), which can be slow"; const SIBLING_COMTINATOR_AFTER_SCOPE_WARNING_MESSAGE = "Sibling selectors after :scope will never match anything"; add_task(async function () { await addTab( "https://example.com/document-builder.sjs?html=" + encodeURIComponent(TEST_URI) ); const { inspector, view } = await openRuleView(); await selectNode("main", inspector); const { ancestorDataEl, selectorText } = getRuleViewRuleEditorAt(view, 1); info( "Check that unconstrained :has() warnings are displayed for the rules selectors" ); let ruleSelectors = Array.from( selectorText.querySelectorAll(".ruleview-selector") ); await assertSelectorWarnings({ view, selectorEl: ruleSelectors[0], selectorText: "& :has(input)", expectedWarnings: [UNCONSTRAINED_HAS_WARNING_MESSAGE], }); await assertSelectorWarnings({ view, selectorEl: ruleSelectors[1], selectorText: "& :has(select)", expectedWarnings: [UNCONSTRAINED_HAS_WARNING_MESSAGE], }); // Warning is not displayed when the selector does not have warnings await assertSelectorWarnings({ view, selectorEl: ruleSelectors[2], selectorText: "&:has(button)", expectedWarnings: [], }); info( "Check that unconstrained :has() warnings are displayed for the parent rules selectors" ); const parentRuleSelectors = Array.from( ancestorDataEl.querySelectorAll(".ruleview-selector") ); await assertSelectorWarnings({ view, selectorEl: parentRuleSelectors[0], selectorText: "main", expectedWarnings: [], }); await assertSelectorWarnings({ view, selectorEl: parentRuleSelectors[1], selectorText: ":has(form)", expectedWarnings: [UNCONSTRAINED_HAS_WARNING_MESSAGE], }); const scopeSiblingRuleEditor = getRuleViewRuleEditorAt(view, 3); ruleSelectors = Array.from( scopeSiblingRuleEditor.selectorText.querySelectorAll(".ruleview-selector") ); // Warning is not displayed when the selector does not have warnings await assertSelectorWarnings({ view, selectorEl: ruleSelectors[0], selectorText: "main", expectedWarnings: [], }); await assertSelectorWarnings({ view, selectorEl: ruleSelectors[1], selectorText: ":scope ~ *", expectedWarnings: [SIBLING_COMTINATOR_AFTER_SCOPE_WARNING_MESSAGE], }); }); async function assertSelectorWarnings({ view, selectorEl, selectorText, expectedWarnings, }) { is( selectorEl.textContent, selectorText, "Passed selector element is the expected one" ); const selectorWarningsContainerEl = selectorEl.querySelector( ".ruleview-selector-warnings" ); if (expectedWarnings.length === 0) { Assert.strictEqual( selectorWarningsContainerEl, null, `"${selectorText}" does not have warnings` ); return; } Assert.notStrictEqual( selectorWarningsContainerEl, null, `"${selectorText}" does have warnings` ); is( selectorWarningsContainerEl .getAttribute("data-selector-warning-kind") ?.split(",")?.length || 0, expectedWarnings.length, `"${selectorText}" has expected number of warnings` ); // Ensure that the element can be targetted from EventUtils. selectorWarningsContainerEl.scrollIntoView(); const tooltip = view.tooltips.getTooltip("interactiveTooltip"); const onTooltipReady = tooltip.once("shown"); EventUtils.synthesizeMouseAtCenter( selectorWarningsContainerEl, { type: "mousemove" }, selectorWarningsContainerEl.ownerDocument.defaultView ); await onTooltipReady; const lis = Array.from(tooltip.panel.querySelectorAll("li")).map( li => li.textContent ); Assert.deepEqual(lis, expectedWarnings, "Tooltip has expected items"); info("Hide the tooltip"); const onHidden = tooltip.once("hidden"); // Move the mouse elsewhere to hide the tooltip EventUtils.synthesizeMouse( selectorWarningsContainerEl.ownerDocument.body, 1, 1, { type: "mousemove" }, selectorWarningsContainerEl.ownerDocument.defaultView ); await onHidden; }