summaryrefslogtreecommitdiffstats
path: root/devtools/client/inspector
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:35:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:35:29 +0000
commit59203c63bb777a3bacec32fb8830fba33540e809 (patch)
tree58298e711c0ff0575818c30485b44a2f21bf28a0 /devtools/client/inspector
parentAdding upstream version 126.0.1. (diff)
downloadfirefox-59203c63bb777a3bacec32fb8830fba33540e809.tar.xz
firefox-59203c63bb777a3bacec32fb8830fba33540e809.zip
Adding upstream version 127.0.upstream/127.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'devtools/client/inspector')
-rw-r--r--devtools/client/inspector/rules/test/browser_part2.toml2
-rw-r--r--devtools/client/inspector/rules/test/browser_rules_keyframes-rule-nested.js89
-rw-r--r--devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js99
-rw-r--r--devtools/client/inspector/rules/test/doc_pseudoelement.html20
-rw-r--r--devtools/client/inspector/shared/utils.js6
-rw-r--r--devtools/client/inspector/test/browser_inspector_picker-shift-key.js35
-rw-r--r--devtools/client/inspector/test/head.js8
7 files changed, 246 insertions, 13 deletions
diff --git a/devtools/client/inspector/rules/test/browser_part2.toml b/devtools/client/inspector/rules/test/browser_part2.toml
index 1cffe88e6e..19d7e2997b 100644
--- a/devtools/client/inspector/rules/test/browser_part2.toml
+++ b/devtools/client/inspector/rules/test/browser_part2.toml
@@ -181,6 +181,8 @@ skip-if = [
["browser_rules_keyframeLineNumbers.js"]
+["browser_rules_keyframes-rule-nested.js"]
+
["browser_rules_keyframes-rule-shadowdom.js"]
["browser_rules_keyframes-rule_01.js"]
diff --git a/devtools/client/inspector/rules/test/browser_rules_keyframes-rule-nested.js b/devtools/client/inspector/rules/test/browser_rules_keyframes-rule-nested.js
new file mode 100644
index 0000000000..97b4b21a65
--- /dev/null
+++ b/devtools/client/inspector/rules/test/browser_rules_keyframes-rule-nested.js
@@ -0,0 +1,89 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that nested @keyframes rules are displayed correctly in the rule view
+
+const TEST_URI = `data:text/html,${encodeURIComponent(`
+ <style>
+ body {
+ animation-name: in-layer,
+ in-starting-style,
+ in-media,
+ in-container;
+ animation-duration: 1s, 2s, 3s, 4s;
+ border: 4px solid;
+ outline: 4px solid;
+ }
+
+ @layer {
+ @keyframes in-layer {
+ from { color: red; }
+ to { color: blue; }
+ }
+ }
+
+ @starting-style {
+ /* keyframes is considered as being outside of @starting-style */
+ @keyframes in-starting-style {
+ from { border-color: tomato; }
+ to { border-color: gold; }
+ }
+ }
+
+ @media screen {
+ @keyframes in-media {
+ from { outline-color: purple; }
+ to { outline-color: pink; }
+ }
+ }
+
+ @container (width > 0px) {
+ /* keyframes is considered as being outside of @container */
+ @keyframes in-container {
+ from { background-color: green; }
+ to { background-color: lime; }
+ }
+ }
+ </style>
+ <h1>Nested <code>@keyframes</code></h1>
+`)}`;
+
+add_task(async function () {
+ await pushPref("layout.css.starting-style-at-rules.enabled", true);
+ await addTab(TEST_URI);
+ const { inspector, view } = await openRuleView();
+
+ await selectNode("body", inspector);
+ const headers = Array.from(view.element.querySelectorAll(".ruleview-header"));
+ Assert.deepEqual(
+ headers.map(el => el.textContent),
+ [
+ "Keyframes in-layer",
+ "Keyframes in-starting-style",
+ "Keyframes in-media",
+ "Keyframes in-container",
+ ],
+ "Got expected keyframes sections"
+ );
+
+ info("Check that keyframes' keyframe ancestor rules are not displayed");
+ for (const headerEl of headers) {
+ const keyframeContainerId = headerEl
+ .querySelector("button")
+ .getAttribute("aria-controls");
+ const keyframeContainer = view.element.querySelector(
+ `#${keyframeContainerId}`
+ );
+ ok(
+ !!keyframeContainer,
+ `Got keyframe container for "${headerEl.textContent}"`
+ );
+ is(
+ keyframeContainer.querySelector(".ruleview-rule-ancestor"),
+ null,
+ `ancestor data are not displayed for "${headerEl.textContent}" keyframe rules`
+ );
+ }
+});
diff --git a/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js b/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js
index fcd0302624..d1919c6f36 100644
--- a/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js
+++ b/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js
@@ -5,13 +5,16 @@
// Test that pseudoelements are displayed correctly in the rule view
-const TEST_URI = URL_ROOT + "doc_pseudoelement.html";
+const TEST_URI = URL_ROOT + "doc_pseudoelement.html?#:~:text=fox";
const PSEUDO_PREF = "devtools.inspector.show_pseudo_elements";
add_task(async function () {
await pushPref(PSEUDO_PREF, true);
await pushPref("dom.customHighlightAPI.enabled", true);
+ await pushPref("dom.text_fragments.enabled", true);
await pushPref("layout.css.modern-range-pseudos.enabled", true);
+ await pushPref("full-screen-api.transition-duration.enter", "0 0");
+ await pushPref("full-screen-api.transition-duration.leave", "0 0");
await addTab(TEST_URI);
const { inspector, view } = await openRuleView();
@@ -23,9 +26,11 @@ add_task(async function () {
await testParagraph(inspector, view);
await testBody(inspector, view);
await testList(inspector, view);
- await testDialogBackdrop(inspector, view);
await testCustomHighlight(inspector, view);
await testSlider(inspector, view);
+ await testUrlFragmentTextDirective(inspector, view);
+ // keep this one last as it makes the browser go fullscreen and seem to impact other tests
+ await testBackdrop(inspector, view);
});
async function testTopLeft(inspector, view) {
@@ -288,13 +293,80 @@ async function testList(inspector, view) {
assertGutters(view);
}
-async function testDialogBackdrop(inspector, view) {
+async function testBackdrop(inspector, view) {
+ info("Test ::backdrop for dialog element");
await assertPseudoElementRulesNumbers("dialog", inspector, view, {
elementRulesNb: 3,
backdropRules: 1,
});
+ info("Test ::backdrop for popover element");
+ await assertPseudoElementRulesNumbers(
+ "#in-dialog[popover]",
+ inspector,
+ view,
+ {
+ elementRulesNb: 3,
+ backdropRules: 1,
+ }
+ );
+
assertGutters(view);
+
+ info("Test ::backdrop rules are displayed when elements is fullscreen");
+
+ // Wait for the document being activated, so that
+ // fullscreen request won't be denied.
+ const onTabFocused = SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
+ return ContentTaskUtils.waitForCondition(
+ () => content.browsingContext.isActive && content.document.hasFocus(),
+ "document is active"
+ );
+ });
+ gBrowser.selectedBrowser.focus();
+ await onTabFocused;
+
+ info("Request fullscreen");
+ // Entering fullscreen is triggering an update, wait for it so it doesn't impact
+ // the rest of the test
+ let onInspectorUpdated = view.once("ruleview-refreshed");
+ await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async () => {
+ const canvas = content.document.querySelector("canvas");
+ canvas.requestFullscreen();
+
+ await ContentTaskUtils.waitForCondition(
+ () => content.document.fullscreenElement === canvas,
+ "canvas is fullscreen"
+ );
+ });
+ await onInspectorUpdated;
+
+ await assertPseudoElementRulesNumbers("canvas", inspector, view, {
+ elementRulesNb: 3,
+ backdropRules: 1,
+ });
+
+ assertGutters(view);
+
+ // Exiting fullscreen is triggering an update, wait for it so it doesn't impact
+ // the rest of the test
+ onInspectorUpdated = view.once("ruleview-refreshed");
+ await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async () => {
+ content.document.exitFullscreen();
+ await ContentTaskUtils.waitForCondition(
+ () => content.document.fullscreenElement === null,
+ "canvas is no longer fullscreen"
+ );
+ });
+ await onInspectorUpdated;
+
+ info(
+ "Test ::backdrop rules are not displayed when elements are not fullscreen"
+ );
+ await assertPseudoElementRulesNumbers("canvas", inspector, view, {
+ elementRulesNb: 3,
+ backdropRules: 0,
+ });
}
async function testCustomHighlight(inspector, view) {
@@ -376,6 +448,19 @@ async function testSlider(inspector, view) {
);
}
+async function testUrlFragmentTextDirective(inspector, view) {
+ await assertPseudoElementRulesNumbers(
+ ".url-fragment-text-directives",
+ inspector,
+ view,
+ {
+ elementRulesNb: 3,
+ targetTextRulesNb: 1,
+ }
+ );
+ assertGutters(view);
+}
+
function convertTextPropsToString(textProps) {
return textProps
.map(
@@ -436,6 +521,9 @@ async function assertPseudoElementRulesNumbers(
sliderTrackRules: elementStyle.rules.filter(
rule => rule.pseudoElement === "::slider-track"
),
+ targetTextRules: elementStyle.rules.filter(
+ rule => rule.pseudoElement === "::target-text"
+ ),
};
is(
@@ -493,6 +581,11 @@ async function assertPseudoElementRulesNumbers(
ruleNbs.sliderTrackRulesNb || 0,
selector + " has the correct number of ::slider-track rules"
);
+ is(
+ rules.targetTextRules.length,
+ ruleNbs.targetTextRulesNb || 0,
+ selector + " has the correct number of ::target-text rules"
+ );
// If we do have pseudo element rules displayed, ensure we don't mark their selectors
// as matched or unmatched
diff --git a/devtools/client/inspector/rules/test/doc_pseudoelement.html b/devtools/client/inspector/rules/test/doc_pseudoelement.html
index 8e077e220b..88611d6633 100644
--- a/devtools/client/inspector/rules/test/doc_pseudoelement.html
+++ b/devtools/client/inspector/rules/test/doc_pseudoelement.html
@@ -110,7 +110,11 @@ p:first-letter {
color: purple;
}
-dialog::backdrop {
+:is(
+ dialog,
+ [popover],
+ :fullscreen,
+)::backdrop {
background-color: transparent;
}
@@ -142,6 +146,10 @@ input::slider-thumb {
input::slider-track {
background: seagreen;
}
+
+.url-fragment-text-directives::target-text {
+ background-color: salmon;
+}
</style>
</head>
<body>
@@ -167,7 +175,10 @@ input::slider-track {
<li id="list" class="box">List element</li>
</ol>
- <dialog>In dialog</dialog>
+ <dialog>
+ In dialog
+ <div id="in-dialog" popover>hello</div>
+ </dialog>
<label>Range <input type="range" class="slider"></label>
<label>Not range <input type="text" class="slider"></label>
@@ -177,10 +188,15 @@ input::slider-track {
You can use them to examine, edit, and debug HTML, CSS, and JavaScript.
</section>
+ <section class="url-fragment-text-directives">May the fox be with you</section>
+
+ <canvas></canvas>
+
<script>
"use strict";
// This is the only way to have the ::backdrop style to be applied
document.querySelector("dialog").showModal()
+ document.querySelector("#in-dialog").showPopover()
// Register highlights for ::highlight pseudo elements
const highlightsContainer = document.querySelector(".highlights-container");
diff --git a/devtools/client/inspector/shared/utils.js b/devtools/client/inspector/shared/utils.js
index 542f9897b1..655f143978 100644
--- a/devtools/client/inspector/shared/utils.js
+++ b/devtools/client/inspector/shared/utils.js
@@ -12,7 +12,7 @@ loader.lazyRequireGetter(
);
loader.lazyRequireGetter(
this,
- "getCSSLexer",
+ "InspectorCSSParserWrapper",
"resource://devtools/shared/css/lexer.js",
true
);
@@ -51,11 +51,11 @@ function advanceValidate(keyCode, value, insertionPoint) {
// value. Otherwise it's been inserted in some spot where it has a
// valid meaning, like a comment or string.
value = value.slice(0, insertionPoint) + ";" + value.slice(insertionPoint);
- const lexer = getCSSLexer(value);
+ const lexer = new InspectorCSSParserWrapper(value);
while (true) {
const token = lexer.nextToken();
if (token.endOffset > insertionPoint) {
- if (token.tokenType === "symbol" && token.text === ";") {
+ if (token.tokenType === "Semicolon") {
// The ";" is a terminator.
return true;
}
diff --git a/devtools/client/inspector/test/browser_inspector_picker-shift-key.js b/devtools/client/inspector/test/browser_inspector_picker-shift-key.js
index 2eb1c04709..db1d5510e7 100644
--- a/devtools/client/inspector/test/browser_inspector_picker-shift-key.js
+++ b/devtools/client/inspector/test/browser_inspector_picker-shift-key.js
@@ -13,12 +13,18 @@ const TEST_URI = `data:text/html;charset=utf-8,
<div id="nopointer" style="pointer-events: none">Element with pointer-events: none</div>
<div id="transluscent" style="pointer-events: none;opacity: 0.1">Element with opacity of 0.1</div>
<div id="invisible" style="pointer-events: none;opacity: 0">Element with opacity of 0</div>
+ <div>
+ <header>Hello</header>
+ <div style="z-index:-1;position:relative;">
+ <span id="negative-z-index-child">ZZ</span>
+ </div>
+ </div>
</main>`;
const IS_OSX = Services.appinfo.OS === "Darwin";
add_task(async function () {
- const { inspector, toolbox } = await openInspectorForURL(TEST_URI);
-
+ const { inspector, toolbox, highlighterTestFront } =
+ await openInspectorForURL(TEST_URI);
const body = await getNodeFront("body", inspector);
is(
inspector.selection.nodeFront,
@@ -72,6 +78,31 @@ add_task(async function () {
shiftKey: true,
});
await checkElementSelected("main", inspector);
+
+ info("Shift-clicking element with negative z-index parent works");
+ await hoverElement(
+ inspector,
+ "#negative-z-index-child",
+ undefined,
+ undefined,
+ {
+ shiftKey: true,
+ }
+ );
+ is(
+ await highlighterTestFront.getHighlighterNodeTextContent(
+ "box-model-infobar-id"
+ ),
+ "#negative-z-index-child",
+ "The highlighter is shown on #negative-z-index-child"
+ );
+
+ await clickElement({
+ inspector,
+ selector: "#negative-z-index-child",
+ shiftKey: true,
+ });
+ await checkElementSelected("#negative-z-index-child", inspector);
});
async function clickElement({ selector, inspector, shiftKey }) {
diff --git a/devtools/client/inspector/test/head.js b/devtools/client/inspector/test/head.js
index cb1b00030c..73c8902c6b 100644
--- a/devtools/client/inspector/test/head.js
+++ b/devtools/client/inspector/test/head.js
@@ -131,10 +131,12 @@ function pickElement(inspector, selector, x, y) {
* X-offset from the top-left corner of the element matching the provided selector
* @param {Number} y
* Y-offset from the top-left corner of the element matching the provided selector
+ * @param {Object} eventOptions
+ * Options that will be passed to synthesizeMouse
* @return {Promise} promise that resolves when both the "picker-node-hovered" and
* "highlighter-shown" events are emitted.
*/
-async function hoverElement(inspector, selector, x, y) {
+async function hoverElement(inspector, selector, x, y, eventOptions = {}) {
const { waitForHighlighterTypeShown } = getHighlighterTestHelpers(inspector);
info(`Waiting for element "${selector}" to be hovered`);
const onHovered = inspector.toolbox.nodePicker.once("picker-node-hovered");
@@ -159,7 +161,7 @@ async function hoverElement(inspector, selector, x, y) {
if (isNaN(x) || isNaN(y)) {
BrowserTestUtils.synthesizeMouseAtCenter(
selector,
- { type: "mousemove" },
+ { ...eventOptions, type: "mousemove" },
browsingContext
);
} else {
@@ -167,7 +169,7 @@ async function hoverElement(inspector, selector, x, y) {
selector,
x,
y,
- { type: "mousemove" },
+ { ...eventOptions, type: "mousemove" },
browsingContext
);
}