summaryrefslogtreecommitdiffstats
path: root/devtools/client/inspector/computed/test/head.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /devtools/client/inspector/computed/test/head.js
parentInitial commit. (diff)
downloadthunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz
thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--devtools/client/inspector/computed/test/head.js267
1 files changed, 267 insertions, 0 deletions
diff --git a/devtools/client/inspector/computed/test/head.js b/devtools/client/inspector/computed/test/head.js
new file mode 100644
index 0000000000..6d9a0f5b01
--- /dev/null
+++ b/devtools/client/inspector/computed/test/head.js
@@ -0,0 +1,267 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+/* eslint no-unused-vars: [2, {"vars": "local"}] */
+
+"use strict";
+
+// Import the inspector's head.js first (which itself imports shared-head.js).
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/devtools/client/inspector/test/head.js",
+ this
+);
+
+registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("devtools.defaultColorUnit");
+});
+
+/**
+ * Dispatch the copy event on the given element
+ */
+function fireCopyEvent(element) {
+ const evt = element.ownerDocument.createEvent("Event");
+ evt.initEvent("copy", true, true);
+ element.dispatchEvent(evt);
+}
+
+/**
+ * Get references to the name and value span nodes corresponding to a given
+ * property name in the computed-view
+ *
+ * @param {CssComputedView} view
+ * The instance of the computed view panel
+ * @param {String} name
+ * The name of the property to retrieve
+ * @return an object {nameSpan, valueSpan}
+ */
+function getComputedViewProperty(view, name) {
+ let prop;
+ for (const property of view.styleDocument.querySelectorAll(
+ "#computed-container .computed-property-view"
+ )) {
+ const nameSpan = property.querySelector(".computed-property-name");
+ const valueSpan = property.querySelector(".computed-property-value");
+
+ if (nameSpan.firstChild.textContent === name) {
+ prop = { nameSpan, valueSpan };
+ break;
+ }
+ }
+ return prop;
+}
+
+/**
+ * Get an instance of PropertyView from the computed-view.
+ *
+ * @param {CssComputedView} view
+ * The instance of the computed view panel
+ * @param {String} name
+ * The name of the property to retrieve
+ * @return {PropertyView}
+ */
+function getComputedViewPropertyView(view, name) {
+ let propView;
+ for (const propertyView of view.propertyViews) {
+ if (propertyView._propertyInfo.name === name) {
+ propView = propertyView;
+ break;
+ }
+ }
+ return propView;
+}
+
+/**
+ * Get a reference to the computed-property-content element for a given property name in
+ * the computed-view.
+ * A computed-property-content element always follows (nextSibling) the property itself
+ * and is only shown when the twisty icon is expanded on the property.
+ * A computed-property-content element contains matched rules, with selectors,
+ * properties, values and stylesheet links
+ *
+ * @param {CssComputedView} view
+ * The instance of the computed view panel
+ * @param {String} name
+ * The name of the property to retrieve
+ * @return {Promise} A promise that resolves to the property matched rules
+ * container
+ */
+var getComputedViewMatchedRules = async function (view, name) {
+ let expander;
+ let propertyContent;
+ for (const property of view.styleDocument.querySelectorAll(
+ "#computed-container .computed-property-view"
+ )) {
+ const nameSpan = property.querySelector(".computed-property-name");
+ if (nameSpan.firstChild.textContent === name) {
+ expander = property.querySelector(".computed-expandable");
+ propertyContent = property.nextSibling;
+ break;
+ }
+ }
+
+ if (!expander.hasAttribute("open")) {
+ // Need to expand the property
+ const onExpand = view.inspector.once("computed-view-property-expanded");
+ expander.click();
+ await onExpand;
+
+ await waitFor(() => expander.hasAttribute("open"));
+ }
+
+ return propertyContent;
+};
+
+/**
+ * Get the text value of the property corresponding to a given name in the
+ * computed-view
+ *
+ * @param {CssComputedView} view
+ * The instance of the computed view panel
+ * @param {String} name
+ * The name of the property to retrieve
+ * @return {String} The property value
+ */
+function getComputedViewPropertyValue(view, name, propertyName) {
+ return getComputedViewProperty(view, name, propertyName).valueSpan
+ .textContent;
+}
+
+/**
+ * Expand a given property, given its index in the current property list of
+ * the computed view
+ *
+ * @param {CssComputedView} view
+ * The instance of the computed view panel
+ * @param {Number} index
+ * The index of the property to be expanded
+ * @return a promise that resolves when the property has been expanded, or
+ * rejects if the property was not found
+ */
+function expandComputedViewPropertyByIndex(view, index) {
+ info("Expanding property " + index + " in the computed view");
+ const expandos = view.styleDocument.querySelectorAll(".computed-expandable");
+ if (!expandos.length || !expandos[index]) {
+ return Promise.reject();
+ }
+
+ const onExpand = view.inspector.once("computed-view-property-expanded");
+ expandos[index].click();
+ return onExpand;
+}
+
+/**
+ * Get a rule-link from the computed-view given its index
+ *
+ * @param {CssComputedView} view
+ * The instance of the computed view panel
+ * @param {Number} index
+ * The index of the link to be retrieved
+ * @return {DOMNode} The link at the given index, if one exists, null otherwise
+ */
+function getComputedViewLinkByIndex(view, index) {
+ const links = view.styleDocument.querySelectorAll(
+ ".rule-link .computed-link"
+ );
+ return links[index];
+}
+
+/**
+ * Trigger the select all action in the computed view.
+ *
+ * @param {CssComputedView} view
+ * The instance of the computed view panel
+ */
+function selectAllText(view) {
+ info("Selecting all the text");
+ view.contextMenu._onSelectAll();
+}
+
+/**
+ * Select all the text, copy it, and check the content in the clipboard.
+ *
+ * @param {CssComputedView} view
+ * The instance of the computed view panel
+ * @param {String} expectedPattern
+ * A regular expression used to check the content of the clipboard
+ */
+async function copyAllAndCheckClipboard(view, expectedPattern) {
+ selectAllText(view);
+ const contentDoc = view.styleDocument;
+ const prop = contentDoc.querySelector(
+ "#computed-container .computed-property-view"
+ );
+
+ try {
+ info("Trigger a copy event and wait for the clipboard content");
+ await waitForClipboardPromise(
+ () => fireCopyEvent(prop),
+ () => checkClipboard(expectedPattern)
+ );
+ } catch (e) {
+ failClipboardCheck(expectedPattern);
+ }
+}
+
+/**
+ * Select some text, copy it, and check the content in the clipboard.
+ *
+ * @param {CssComputedView} view
+ * The instance of the computed view panel
+ * @param {Object} positions
+ * The start and end positions of the text to be selected. This must be an object
+ * like this:
+ * { start: {prop: 1, offset: 0}, end: {prop: 3, offset: 5} }
+ * @param {String} expectedPattern
+ * A regular expression used to check the content of the clipboard
+ */
+async function copySomeTextAndCheckClipboard(view, positions, expectedPattern) {
+ info("Testing selection copy");
+
+ const contentDocument = view.styleDocument;
+ const props = contentDocument.querySelectorAll(
+ "#computed-container .computed-property-view"
+ );
+
+ info("Create the text selection range");
+ const range = contentDocument.createRange();
+ range.setStart(props[positions.start.prop], positions.start.offset);
+ range.setEnd(props[positions.end.prop], positions.end.offset);
+ contentDocument.defaultView.getSelection().addRange(range);
+
+ try {
+ info("Trigger a copy event and wait for the clipboard content");
+ await waitForClipboardPromise(
+ () => fireCopyEvent(props[0]),
+ () => checkClipboard(expectedPattern)
+ );
+ } catch (e) {
+ failClipboardCheck(expectedPattern);
+ }
+}
+
+function checkClipboard(expectedPattern) {
+ const actual = SpecialPowers.getClipboardData("text/plain");
+ const expectedRegExp = new RegExp(expectedPattern, "g");
+ return expectedRegExp.test(actual);
+}
+
+function failClipboardCheck(expectedPattern) {
+ // Format expected text for comparison
+ const terminator = Services.appinfo.OS == "WINNT" ? "\r\n" : "\n";
+ expectedPattern = expectedPattern.replace(/\[\\r\\n\][+*]/g, terminator);
+ expectedPattern = expectedPattern.replace(/\\\(/g, "(");
+ expectedPattern = expectedPattern.replace(/\\\)/g, ")");
+
+ let actual = SpecialPowers.getClipboardData("text/plain");
+
+ // Trim the right hand side of our strings. This is because expectedPattern
+ // accounts for windows sometimes adding a newline to our copied data.
+ expectedPattern = expectedPattern.trimRight();
+ actual = actual.trimRight();
+
+ dump(
+ "TEST-UNEXPECTED-FAIL | Clipboard text does not match expected ... " +
+ "results (escaped for accurate comparison):\n"
+ );
+ info("Actual: " + escape(actual));
+ info("Expected: " + escape(expectedPattern));
+}