/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; // Test that pseudo elements rules are displayed correctly in Rules view. const TEST_URI = URL_ROOT + "doc_pseudoelement.html"; add_task(async function () { await addTab(TEST_URI); const { inspector, view } = await openRuleView(); const node = await getNodeFront("#topleft", inspector); const children = await inspector.markup.walker.children(node); is(children.nodes.length, 3, "Element has correct number of children"); info("Check rules on #topleft::before node"); const beforeElement = children.nodes[0]; is(beforeElement.displayName, "::before", "display name is correct"); await selectNode(beforeElement, inspector); checkRuleViewContent(view, [ { selector: `.topleft::before`, ancestorRulesData: null, declarations: [ { name: "top", value: "0" }, { name: "left", value: "0" }, ], }, { selector: `.box::before`, ancestorRulesData: null, declarations: [ { name: "background", value: "green" }, { name: "content", value: `" "` }, { name: "position", value: `absolute` }, { name: "height", value: `32px` }, { name: "width", value: `32px` }, ], }, { header: "Inherited from div#topleft", }, { selector: `*`, ancestorRulesData: null, inherited: true, declarations: [{ name: "cursor", value: "default" }], }, { header: "Inherited from body", }, { selector: `body`, ancestorRulesData: null, inherited: true, declarations: [{ name: "color", value: "#333" }], }, ]); info("Check rules on #topleft::after node"); const afterElement = children.nodes.at(-1); is(afterElement.displayName, "::after", "display name is correct"); await selectNode(afterElement, inspector); checkRuleViewContent(view, [ { selector: `.box::after`, ancestorRulesData: null, declarations: [ { name: "background", value: `red` }, { name: "content", value: `" "` }, { name: "position", value: `absolute` }, { name: "border-radius", value: `50%` }, { name: "height", value: `32px` }, { name: "width", value: `32px` }, { name: "top", value: `50%` }, { name: "left", value: `50%` }, { name: "margin-top", value: `-16px` }, { name: "margin-left", value: `-16px` }, ], }, { header: "Inherited from div#topleft", }, { selector: `*`, ancestorRulesData: null, inherited: true, declarations: [{ name: "cursor", value: "default" }], }, { header: "Inherited from body", }, { selector: `body`, ancestorRulesData: null, inherited: true, declarations: [{ name: "color", value: "#333" }], }, ]); info("Check #list children"); const listNode = await getNodeFront("#list", inspector); const listChildren = await inspector.markup.walker.children(listNode); const listAfterNode = listChildren.nodes.at(-1); is( listAfterNode.displayName, "::after", "display name is correct for #list::after" ); const listAfterChildren = await inspector.markup.walker.children(listAfterNode); is( listAfterChildren.nodes.length, 1, "ol::after has the expected number of children" ); const listAfterMarkerNode = listAfterChildren.nodes[0]; is( listAfterMarkerNode.displayName, "::marker", "display name is correct for #list::after::marker" ); info("Check rules on #list-item::marker node"); await selectNode(listAfterMarkerNode, inspector); checkRuleViewContent(view, [ { selector: `#list::after::marker`, ancestorRulesData: null, declarations: [ { name: "content", value: `"+"` }, { name: "color", value: `tomato` }, ], }, { header: "Inherited from ol#list", }, { selector: `*`, ancestorRulesData: null, inherited: true, declarations: [{ name: "cursor", value: "default" }], }, { header: "Inherited from body", }, { selector: `body`, ancestorRulesData: null, inherited: true, declarations: [{ name: "color", value: "#333", overridden: true }], }, ]); info("Check #list-item children"); const listItemNode = await getNodeFront("#list-item", inspector); const listItemChildren = await inspector.markup.walker.children(listItemNode); is(listItemChildren.nodes.length, 4, "
  • has correct number of children"); info("Check rules on #list-item::marker node"); const markerElement = listItemChildren.nodes[0]; is(markerElement.displayName, "::marker", "display name is correct"); await selectNode(markerElement, inspector); checkRuleViewContent(view, [ { selector: `#list-item::marker`, ancestorRulesData: null, declarations: [{ name: "color", value: `purple` }], }, { header: "Inherited from li#list-item", }, { selector: `*`, ancestorRulesData: null, inherited: true, declarations: [{ name: "cursor", value: "default" }], }, { header: "Inherited from body", }, { selector: `body`, ancestorRulesData: null, inherited: true, declarations: [{ name: "color", value: "#333", overridden: true }], }, ]); info("Check rules on #list-item::before node"); const listBeforeElement = listItemChildren.nodes[1]; is(listBeforeElement.displayName, "::before", "display name is correct"); await selectNode(listBeforeElement, inspector); checkRuleViewContent(view, [ { selector: `.box::before`, ancestorRulesData: null, declarations: [ { name: "background", value: "green" }, { name: "content", value: `" "` }, { name: "position", value: `absolute` }, { name: "height", value: `32px` }, { name: "width", value: `32px` }, ], }, { header: "Inherited from li#list-item", }, { selector: `*`, ancestorRulesData: null, inherited: true, declarations: [{ name: "cursor", value: "default" }], }, { header: "Inherited from body", }, { selector: `body`, ancestorRulesData: null, inherited: true, declarations: [{ name: "color", value: "#333" }], }, ]); info("Check unmatched selector parts in Pseudo element section"); await selectNode("#with-unmatched-selector", inspector); checkRuleViewContent(view, [ { header: `Pseudo-elements`, }, { selector: `#with-unmatched-selector::before, ~~unknown::before~~, #with-unmatched-selector::after, ~~anotherunknown~~`, declarations: [{ name: "content", value: `"unmatched pseudo"` }], }, { header: `This Element`, }, { selector: `element`, declarations: [], selectorEditable: false, }, { selector: `*`, declarations: [{ name: "cursor", value: "default" }], }, { header: "Inherited from body", }, { selector: `body`, inherited: true, declarations: [{ name: "color", value: "#333" }], }, ]); info("Check rules on ::view-transition"); const htmlNodeFront = await getNodeFront("html", inspector); const onMarkupMutation = inspector.once("markupmutation"); await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async () => { const document = content.document; const transition = document.startViewTransition(() => { document.querySelector(".transition").append("updated"); }); await transition.ready; await transition.updateCallbackDone; }); await onMarkupMutation; const htmlChildren = await inspector.markup.walker.children(htmlNodeFront); const viewTransitionNodeFront = htmlChildren.nodes[2]; is( viewTransitionNodeFront.getAttribute("type"), ":view-transition", "Got expected ::view-transition node front" ); await selectNode(viewTransitionNodeFront, inspector); checkRuleViewContent(view, [ { selector: `::view-transition`, declarations: [{ name: "color", value: `lime` }], }, { header: "Inherited from html", }, { selector: `html:active-view-transition`, inherited: true, declarations: [{ name: "color", value: "peachpuff", overridden: true }], }, { selector: `*`, inherited: true, declarations: [{ name: "cursor", value: "default" }], }, ]); const viewTransitionChildren = await inspector.markup.walker.children( viewTransitionNodeFront ); const viewTransitionGroupNodeFront = viewTransitionChildren.nodes[0]; is( viewTransitionGroupNodeFront.getAttribute("type"), ":view-transition-group", "Got expected ::view-transition-group node front" ); const viewTransitionGroupChildren = await inspector.markup.walker.children( viewTransitionGroupNodeFront ); const viewTransitionImagePairNodeFront = viewTransitionGroupChildren.nodes[0]; is( viewTransitionImagePairNodeFront.getAttribute("type"), ":view-transition-image-pair", "Got expected ::view-transition-image-pair node front" ); const viewTransitionImagePairChildren = await inspector.markup.walker.children(viewTransitionImagePairNodeFront); const [viewTransitionOldNodeFront, viewTransitionNewNodeFront] = viewTransitionImagePairChildren.nodes; is( viewTransitionOldNodeFront.getAttribute("type"), ":view-transition-old", "Got expected ::view-transition-old node front" ); is( viewTransitionNewNodeFront.getAttribute("type"), ":view-transition-new", "Got expected ::view-transition-new node front" ); info("Check rules on ::view-transition-old"); await selectNode(viewTransitionOldNodeFront, inspector); checkRuleViewContent(view, [ { selector: `::view-transition-old(root), ~~::view-transition-new(root)~~`, declarations: [ { name: "animation-duration", value: `1000s` }, { name: "top", value: `1em` }, { name: "gap", value: `10px`, inactiveCSS: true }, ], }, { header: "Inherited from ::view-transition", }, { selector: `::view-transition`, inherited: true, declarations: [{ name: "color", value: `lime` }], }, { header: "Inherited from html", }, { selector: `html:active-view-transition`, inherited: true, declarations: [{ name: "color", value: "peachpuff", overridden: true }], }, { selector: `*`, inherited: true, declarations: [{ name: "cursor", value: "default" }], }, ]); info("Check rules on ::view-transition-new"); await selectNode(viewTransitionNewNodeFront, inspector); checkRuleViewContent(view, [ { selector: `::view-transition-new(root)`, declarations: [ { name: "animation-duration", value: `3600s` }, { name: "color", value: `thistle` }, ], }, { selector: `~~::view-transition-old(root)~~, ::view-transition-new(root)`, declarations: [ { name: "animation-duration", value: `1000s`, overridden: true }, { name: "top", value: `1em`, }, { name: "gap", value: `10px`, inactiveCSS: true }, ], }, { header: "Inherited from ::view-transition", }, { selector: `::view-transition`, inherited: true, declarations: [{ name: "color", value: `lime`, overridden: true }], }, { header: "Inherited from html", }, { selector: `html:active-view-transition`, inherited: true, declarations: [{ name: "color", value: "peachpuff", overridden: true }], }, { selector: `*`, inherited: true, declarations: [{ name: "cursor", value: "default" }], }, ]); });