summaryrefslogtreecommitdiffstats
path: root/devtools/client/inspector/rules/test/browser_rules_select-and-copy-styles.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/inspector/rules/test/browser_rules_select-and-copy-styles.js')
-rw-r--r--devtools/client/inspector/rules/test/browser_rules_select-and-copy-styles.js255
1 files changed, 255 insertions, 0 deletions
diff --git a/devtools/client/inspector/rules/test/browser_rules_select-and-copy-styles.js b/devtools/client/inspector/rules/test/browser_rules_select-and-copy-styles.js
new file mode 100644
index 0000000000..f9d245828e
--- /dev/null
+++ b/devtools/client/inspector/rules/test/browser_rules_select-and-copy-styles.js
@@ -0,0 +1,255 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that properties can be selected and copied from the rule view
+
+const osString = Services.appinfo.OS;
+
+const TEST_URI = `
+ <style type="text/css">
+ html {
+ color: #000000;
+ }
+ span {
+ font-variant: small-caps; color: #000000;
+ }
+ .nomatches {
+ color: #ff0000;
+ }
+
+ html {
+ body {
+ container-type: inline-size;
+ @container (1px < width) {
+ #nested {
+ background: tomato;
+ color: gold;
+ }
+ }
+ }
+ }
+ </style>
+ <div id="first" style="margin: 10em;
+ font-size: 14pt; font-family: helvetica, sans-serif; color: #AAA">
+ <h1>Some header text</h1>
+ <p id="salutation" style="font-size: 12pt">hi.</p>
+ <p id="body" style="font-size: 12pt">I am a test-case. This text exists
+ solely to provide some things to <span style="color: yellow">
+ highlight</span> and <span style="font-weight: bold">count</span>
+ style list-items in the box at right. If you are reading this,
+ you should go do something else instead. Maybe read a book. Or better
+ yet, write some test-cases for another bit of code.
+ <span style="font-style: italic">some text</span></p>
+ <p id="closing">more text</p>
+ <p>even more text</p>
+ </div>
+ <section id=nested>Nested</section>
+`;
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { inspector, view } = await openRuleView();
+ await selectNode("div", inspector);
+ await checkCopySelection(view);
+ await checkSelectAll(view);
+ await checkCopyEditorValue(view);
+
+ await selectNode("#nested", inspector);
+ await checkCopyNestedRule(view);
+});
+
+async function checkCopySelection(view) {
+ info("Testing selection copy");
+
+ const contentDoc = view.styleDocument;
+ const win = view.styleWindow;
+ const prop = contentDoc.querySelector(".ruleview-property");
+ const values = contentDoc.querySelectorAll(
+ ".ruleview-propertyvaluecontainer"
+ );
+
+ let range = contentDoc.createRange();
+ range.setStart(prop, 0);
+ range.setEnd(values[4], 2);
+ win.getSelection().addRange(range);
+ info("Checking that _Copy() returns the correct clipboard value");
+
+ const expectedPattern =
+ " margin: 10em;[\\r\\n]+" +
+ " font-size: 14pt;[\\r\\n]+" +
+ " font-family: helvetica, sans-serif;[\\r\\n]+" +
+ " color: #AAA;[\\r\\n]+" +
+ "}[\\r\\n]+" +
+ "html {[\\r\\n]+" +
+ " color: #000000;[\\r\\n]*";
+
+ const allMenuItems = openStyleContextMenuAndGetAllItems(view, prop);
+ const menuitemCopy = allMenuItems.find(
+ item =>
+ item.label ===
+ STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copy")
+ );
+
+ ok(menuitemCopy.visible, "Copy menu item is displayed as expected");
+
+ try {
+ await waitForClipboardPromise(
+ () => menuitemCopy.click(),
+ () => checkClipboardData(expectedPattern)
+ );
+ } catch (e) {
+ failedClipboard(expectedPattern);
+ }
+
+ info("Check copying from keyboard");
+ win.getSelection().removeRange(range);
+ // Selecting the declaration `margin: 10em;`
+ range = contentDoc.createRange();
+ range.setStart(prop, 0);
+ range.setEnd(prop, 1);
+ win.getSelection().addRange(range);
+
+ // Dispatching the copy event from the checkbox to make sure we cover Bug 1680893.
+ const declarationCheckbox = contentDoc.querySelector(
+ "input[type=checkbox].ruleview-enableproperty"
+ );
+ const copyEvent = new win.Event("copy", { bubbles: true });
+ await waitForClipboardPromise(
+ () => declarationCheckbox.dispatchEvent(copyEvent),
+ () => checkClipboardData("^ margin: 10em;$")
+ );
+ win.getSelection().removeRange(range);
+}
+
+async function checkSelectAll(view) {
+ info("Testing select-all copy");
+
+ const contentDoc = view.styleDocument;
+ const prop = contentDoc.querySelector(".ruleview-property");
+
+ info(
+ "Checking that _SelectAll() then copy returns the correct " +
+ "clipboard value"
+ );
+ view.contextMenu._onSelectAll();
+ const expectedPattern =
+ "element {[\\r\\n]+" +
+ " margin: 10em;[\\r\\n]+" +
+ " font-size: 14pt;[\\r\\n]+" +
+ " font-family: helvetica, sans-serif;[\\r\\n]+" +
+ " color: #AAA;[\\r\\n]+" +
+ "}[\\r\\n]+" +
+ "html {[\\r\\n]+" +
+ " color: #000000;[\\r\\n]+" +
+ "}[\\r\\n]*";
+
+ const allMenuItems = openStyleContextMenuAndGetAllItems(view, prop);
+ const menuitemCopy = allMenuItems.find(
+ item =>
+ item.label ===
+ STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copy")
+ );
+
+ ok(menuitemCopy.visible, "Copy menu item is displayed as expected");
+
+ try {
+ await waitForClipboardPromise(
+ () => menuitemCopy.click(),
+ () => checkClipboardData(expectedPattern)
+ );
+ } catch (e) {
+ failedClipboard(expectedPattern);
+ }
+}
+
+async function checkCopyEditorValue(view) {
+ info("Testing CSS property editor value copy");
+
+ const ruleEditor = getRuleViewRuleEditor(view, 0);
+ const propEditor = ruleEditor.rule.textProps[0].editor;
+
+ const editor = await focusEditableField(view, propEditor.valueSpan);
+
+ info(
+ "Checking that copying a css property value editor returns the correct" +
+ " clipboard value"
+ );
+
+ const expectedPattern = "10em";
+
+ const allMenuItems = openStyleContextMenuAndGetAllItems(view, editor.input);
+ const menuitemCopy = allMenuItems.find(
+ item =>
+ item.label ===
+ STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copy")
+ );
+
+ ok(menuitemCopy.visible, "Copy menu item is displayed as expected");
+
+ try {
+ await waitForClipboardPromise(
+ () => menuitemCopy.click(),
+ () => checkClipboardData(expectedPattern)
+ );
+ } catch (e) {
+ failedClipboard(expectedPattern);
+ }
+}
+
+async function checkCopyNestedRule(view) {
+ info("Select nested rule");
+ const doc = view.styleDocument;
+ const range = doc.createRange();
+ const nestedRule = doc.querySelector(".ruleview-rule:nth-of-type(2)");
+ range.selectNode(nestedRule);
+ const win = view.styleWindow;
+ win.getSelection().addRange(range);
+
+ const copyEvent = new win.Event("copy", { bubbles: true });
+ const expectedNested = `html {
+ body {
+ @container (1px < width) {
+ #nested {
+ background: tomato;
+ color: gold;
+ }
+ }
+ }
+}
+`;
+
+ await waitForClipboardPromise(
+ () => nestedRule.dispatchEvent(copyEvent),
+ expectedNested
+ );
+}
+
+function checkClipboardData(expectedPattern) {
+ const actual = SpecialPowers.getClipboardData("text/plain");
+ const expectedRegExp = new RegExp(expectedPattern, "g");
+ return expectedRegExp.test(actual);
+}
+
+function failedClipboard(expectedPattern) {
+ // Format expected text for comparison
+ const terminator = osString == "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));
+}