summaryrefslogtreecommitdiffstats
path: root/devtools/client/inspector/grids/test
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/inspector/grids/test')
-rw-r--r--devtools/client/inspector/grids/test/browser.toml86
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_accordion-state.js108
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_color-in-rules-grid-toggle.js93
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_display-setting-extend-grid-lines.js59
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_display-setting-show-grid-areas.js59
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_display-setting-show-grid-line-numbers.js65
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_grid-list-color-picker-on-ESC.js75
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_grid-list-color-picker-on-RETURN.js94
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_grid-list-element-rep.js68
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_grid-list-no-grids.js37
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_grid-list-on-iframe-reloaded.js57
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_grid-list-on-mutation-element-added.js100
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_grid-list-on-mutation-element-removed.js63
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_grid-list-on-target-added-removed.js203
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_grid-list-subgrids-z-order.js83
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_grid-list-subgrids_01.js138
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_grid-list-subgrids_02.js72
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_grid-list-toggle-grids_01.js63
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_grid-list-toggle-grids_02.js96
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_grid-list-toggle-multiple-grids.js243
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_grid-outline-cannot-show-outline.js57
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_grid-outline-highlight-area.js77
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_grid-outline-highlight-cell.js65
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_grid-outline-multiple-grids.js76
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_grid-outline-selected-grid.js51
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_grid-outline-updates-on-grid-change.js64
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_grid-outline-writing-mode.js156
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_highlighter-setting-rules-grid-toggle.js75
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_highlighter-toggle-telemetry.js63
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_number-of-css-grids-telemetry.js56
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_persist-color-palette.js58
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_restored-after-reload.js115
-rw-r--r--devtools/client/inspector/grids/test/browser_grids_restored-multiple-grids-after-reload.js156
-rw-r--r--devtools/client/inspector/grids/test/doc_iframe_reloaded.html9
-rw-r--r--devtools/client/inspector/grids/test/doc_subgrid.html56
-rw-r--r--devtools/client/inspector/grids/test/head.js40
-rw-r--r--devtools/client/inspector/grids/test/xpcshell/.eslintrc.js6
-rw-r--r--devtools/client/inspector/grids/test/xpcshell/head.js10
-rw-r--r--devtools/client/inspector/grids/test/xpcshell/test_compare_fragments_geometry.js129
-rw-r--r--devtools/client/inspector/grids/test/xpcshell/xpcshell.toml6
40 files changed, 3187 insertions, 0 deletions
diff --git a/devtools/client/inspector/grids/test/browser.toml b/devtools/client/inspector/grids/test/browser.toml
new file mode 100644
index 0000000000..f492362d97
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser.toml
@@ -0,0 +1,86 @@
+[DEFAULT]
+tags = "devtools"
+subsuite = "devtools"
+support-files = [
+ "doc_iframe_reloaded.html",
+ "doc_subgrid.html",
+ "head.js",
+ "!/devtools/client/inspector/test/head.js",
+ "!/devtools/client/inspector/test/shared-head.js",
+ "!/devtools/client/shared/test/shared-head.js",
+ "!/devtools/client/shared/test/telemetry-test-helpers.js",
+ "!/devtools/client/shared/test/highlighter-test-actor.js",
+]
+
+["browser_grids_accordion-state.js"]
+fail-if = ["a11y_checks"] # Bug 1849028 clicked element may not be focusable and/or labeled
+
+["browser_grids_color-in-rules-grid-toggle.js"]
+
+["browser_grids_display-setting-extend-grid-lines.js"]
+
+["browser_grids_display-setting-show-grid-areas.js"]
+
+["browser_grids_display-setting-show-grid-line-numbers.js"]
+
+["browser_grids_grid-list-color-picker-on-ESC.js"]
+
+["browser_grids_grid-list-color-picker-on-RETURN.js"]
+
+["browser_grids_grid-list-element-rep.js"]
+
+["browser_grids_grid-list-no-grids.js"]
+
+["browser_grids_grid-list-on-iframe-reloaded.js"]
+skip-if = ["verify && (os == 'win' || os == 'linux')"]
+
+["browser_grids_grid-list-on-mutation-element-added.js"]
+skip-if = ["true"] #Bug 1557326
+
+["browser_grids_grid-list-on-mutation-element-removed.js"]
+
+["browser_grids_grid-list-on-target-added-removed.js"]
+
+["browser_grids_grid-list-subgrids-z-order.js"]
+
+["browser_grids_grid-list-subgrids_01.js"]
+
+["browser_grids_grid-list-subgrids_02.js"]
+
+["browser_grids_grid-list-toggle-grids_01.js"]
+
+["browser_grids_grid-list-toggle-grids_02.js"]
+
+["browser_grids_grid-list-toggle-multiple-grids.js"]
+
+["browser_grids_grid-outline-cannot-show-outline.js"]
+
+["browser_grids_grid-outline-highlight-area.js"]
+
+["browser_grids_grid-outline-highlight-cell.js"]
+
+["browser_grids_grid-outline-multiple-grids.js"]
+
+["browser_grids_grid-outline-selected-grid.js"]
+
+["browser_grids_grid-outline-updates-on-grid-change.js"]
+skip-if = [
+ "os == 'linux'",
+ "os == 'mac'",
+ "os == 'win' && (debug || asan)", #Bug 1557181
+]
+
+["browser_grids_grid-outline-writing-mode.js"]
+skip-if = ["verify && os == 'win'"]
+
+["browser_grids_highlighter-setting-rules-grid-toggle.js"]
+
+["browser_grids_highlighter-toggle-telemetry.js"]
+
+["browser_grids_number-of-css-grids-telemetry.js"]
+
+["browser_grids_persist-color-palette.js"]
+
+["browser_grids_restored-after-reload.js"]
+
+["browser_grids_restored-multiple-grids-after-reload.js"]
diff --git a/devtools/client/inspector/grids/test/browser_grids_accordion-state.js b/devtools/client/inspector/grids/test/browser_grids_accordion-state.js
new file mode 100644
index 0000000000..c02fc85dfa
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_accordion-state.js
@@ -0,0 +1,108 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the grid's accordion state is persistent through hide/show in the layout
+// view.
+
+const TEST_URI = `
+ <style type='text/css'>
+ #grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid">
+ <div id="cell1">cell1</div>
+ <div id="cell2">cell2</div>
+ </div>
+`;
+
+const GRID_OPENED_PREF = "devtools.layout.grid.opened";
+const GRID_PANE_SELECTOR = "#layout-grid-section";
+const ACCORDION_HEADER_SELECTOR = ".accordion-header";
+const ACCORDION_CONTENT_SELECTOR = ".accordion-content";
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { inspector, gridInspector, toolbox } = await openLayoutView();
+ const { document: doc } = gridInspector;
+
+ await testAccordionStateAfterClickingHeader(doc);
+ await testAccordionStateAfterSwitchingSidebars(inspector, doc);
+ await testAccordionStateAfterReopeningLayoutView(toolbox);
+
+ Services.prefs.clearUserPref(GRID_OPENED_PREF);
+});
+
+async function testAccordionStateAfterClickingHeader(doc) {
+ const item = await waitFor(() => doc.querySelector(GRID_PANE_SELECTOR));
+ const header = item.querySelector(ACCORDION_HEADER_SELECTOR);
+ const content = item.querySelector(ACCORDION_CONTENT_SELECTOR);
+
+ info("Checking initial state of the grid panel.");
+ ok(
+ !content.hidden && content.childElementCount > 0,
+ "The grid panel content is visible."
+ );
+ ok(
+ Services.prefs.getBoolPref(GRID_OPENED_PREF),
+ `${GRID_OPENED_PREF} is pref on by default.`
+ );
+
+ info("Clicking the grid header to hide the grid panel.");
+ header.click();
+
+ info("Checking the new state of the grid panel.");
+ ok(content.hidden, "The grid panel content is hidden.");
+ ok(
+ !Services.prefs.getBoolPref(GRID_OPENED_PREF),
+ `${GRID_OPENED_PREF} is pref off.`
+ );
+}
+
+async function testAccordionStateAfterSwitchingSidebars(inspector, doc) {
+ info(
+ "Checking the grid accordion state is persistent after switching sidebars."
+ );
+
+ info("Selecting the computed view.");
+ inspector.sidebar.select("computedview");
+
+ info("Selecting the layout view.");
+ inspector.sidebar.select("layoutview");
+
+ const item = await waitFor(() => doc.querySelector(GRID_PANE_SELECTOR));
+ const content = item.querySelector(ACCORDION_CONTENT_SELECTOR);
+
+ info("Checking the state of the grid panel.");
+ ok(content.hidden, "The grid panel content is hidden.");
+ ok(
+ !Services.prefs.getBoolPref(GRID_OPENED_PREF),
+ `${GRID_OPENED_PREF} is pref off.`
+ );
+}
+
+async function testAccordionStateAfterReopeningLayoutView(toolbox) {
+ info(
+ "Checking the grid accordion state is persistent after closing and re-opening the " +
+ "layout view."
+ );
+
+ info("Closing the toolbox.");
+ await toolbox.destroy();
+
+ info("Re-opening the layout view.");
+ const { gridInspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+
+ const item = await waitFor(() => doc.querySelector(GRID_PANE_SELECTOR));
+ const content = item.querySelector(ACCORDION_CONTENT_SELECTOR);
+
+ info("Checking the state of the grid panel.");
+ ok(content.hidden, "The grid panel content is hidden.");
+ ok(
+ !Services.prefs.getBoolPref(GRID_OPENED_PREF),
+ `${GRID_OPENED_PREF} is pref off.`
+ );
+}
diff --git a/devtools/client/inspector/grids/test/browser_grids_color-in-rules-grid-toggle.js b/devtools/client/inspector/grids/test/browser_grids_color-in-rules-grid-toggle.js
new file mode 100644
index 0000000000..a12f4f2435
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_color-in-rules-grid-toggle.js
@@ -0,0 +1,93 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test toggling the grid highlighter in the rule view with changes to the grid color
+// from the layout view.
+
+const TEST_URI = `
+ <style type='text/css'>
+ #grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid">
+ <div id="cell1">cell1</div>
+ <div id="cell2">cell2</div>
+ </div>
+`;
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { inspector, gridInspector, layoutView } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { store } = inspector;
+ const cPicker = layoutView.swatchColorPickerTooltip;
+ const spectrum = cPicker.spectrum;
+ const swatch = doc.querySelector(
+ "#layout-grid-container .layout-color-swatch"
+ );
+
+ info("Scrolling into view of the #grid color swatch.");
+ swatch.scrollIntoView();
+
+ info("Opening the color picker by clicking on the #grid color swatch.");
+ const onColorPickerReady = cPicker.once("ready");
+ swatch.click();
+ await onColorPickerReady;
+
+ await simulateColorPickerChange(cPicker, [0, 255, 0, 0.5]);
+
+ is(
+ swatch.style.backgroundColor,
+ "rgba(0, 255, 0, 0.5)",
+ "The color swatch's background was updated."
+ );
+
+ info("Pressing RETURN to commit the color change.");
+ const onGridColorUpdate = waitUntilState(
+ store,
+ state => state.grids[0].color === "#00FF0080"
+ );
+ const onColorPickerHidden = cPicker.tooltip.once("hidden");
+ focusAndSendKey(spectrum.element.ownerDocument.defaultView, "RETURN");
+ await onColorPickerHidden;
+ await onGridColorUpdate;
+
+ is(
+ swatch.style.backgroundColor,
+ "rgba(0, 255, 0, 0.5)",
+ "The color swatch's background was kept after RETURN."
+ );
+
+ info("Selecting the rule view.");
+ const ruleView = selectRuleView(inspector);
+ const highlighters = ruleView.highlighters;
+
+ await selectNode("#grid", inspector);
+
+ const container = getRuleViewProperty(ruleView, "#grid", "display").valueSpan;
+ const gridToggle = container.querySelector(".js-toggle-grid-highlighter");
+
+ info("Toggling ON the CSS grid highlighter from the rule-view.");
+ const onHighlighterShown = highlighters.once(
+ "grid-highlighter-shown",
+ (nodeFront, options) => {
+ info("Checking the grid highlighter display settings.");
+ const {
+ color,
+ showGridAreasOverlay,
+ showGridLineNumbers,
+ showInfiniteLines,
+ } = options;
+
+ is(color, "#00FF0080", "CSS grid highlighter color is correct.");
+ ok(!showGridAreasOverlay, "Show grid areas overlay option is off.");
+ ok(!showGridLineNumbers, "Show grid line numbers option is off.");
+ ok(!showInfiniteLines, "Show infinite lines option is off.");
+ }
+ );
+ gridToggle.click();
+ await onHighlighterShown;
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_display-setting-extend-grid-lines.js b/devtools/client/inspector/grids/test/browser_grids_display-setting-extend-grid-lines.js
new file mode 100644
index 0000000000..89f2bb36dd
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_display-setting-extend-grid-lines.js
@@ -0,0 +1,59 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the 'Extend grid lines infinitely' grid highlighter setting will update
+// the redux store and pref setting.
+
+const TEST_URI = `
+ <style type='text/css'>
+ #grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid">
+ <div id="cell1">cell1</div>
+ <div id="cell2">cell2</div>
+ </div>
+`;
+
+const SHOW_INFINITE_LINES_PREF = "devtools.gridinspector.showInfiniteLines";
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { inspector, gridInspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { store } = inspector;
+
+ await selectNode("#grid", inspector);
+ const checkbox = doc.getElementById("grid-setting-extend-grid-lines");
+
+ ok(
+ !Services.prefs.getBoolPref(SHOW_INFINITE_LINES_PREF),
+ "'Extend grid lines infinitely' is pref off by default."
+ );
+
+ info("Toggling ON the 'Extend grid lines infinitely' setting.");
+ let onCheckboxChange = waitUntilState(
+ store,
+ state => state.highlighterSettings.showInfiniteLines
+ );
+ checkbox.click();
+ await onCheckboxChange;
+
+ info("Toggling OFF the 'Extend grid lines infinitely' setting.");
+ onCheckboxChange = waitUntilState(
+ store,
+ state => !state.highlighterSettings.showInfiniteLines
+ );
+ checkbox.click();
+ await onCheckboxChange;
+
+ ok(
+ !Services.prefs.getBoolPref(SHOW_INFINITE_LINES_PREF),
+ "'Extend grid lines infinitely' is pref off."
+ );
+
+ Services.prefs.clearUserPref(SHOW_INFINITE_LINES_PREF);
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_display-setting-show-grid-areas.js b/devtools/client/inspector/grids/test/browser_grids_display-setting-show-grid-areas.js
new file mode 100644
index 0000000000..afc091b7ab
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_display-setting-show-grid-areas.js
@@ -0,0 +1,59 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the 'Display grid areas' grid highlighter setting will update
+// the redux store and pref setting.
+
+const TEST_URI = `
+ <style type='text/css'>
+ #grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid">
+ <div id="cell1">cell1</div>
+ <div id="cell2">cell2</div>
+ </div>
+`;
+
+const SHOW_GRID_AREAS_PREF = "devtools.gridinspector.showGridAreas";
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { inspector, gridInspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { store } = inspector;
+
+ await selectNode("#grid", inspector);
+ const checkbox = doc.getElementById("grid-setting-show-grid-areas");
+
+ ok(
+ !Services.prefs.getBoolPref(SHOW_GRID_AREAS_PREF),
+ "'Display grid areas' is pref off by default."
+ );
+
+ info("Toggling ON the 'Display grid areas' setting.");
+ let onCheckboxChange = waitUntilState(
+ store,
+ state => state.highlighterSettings.showGridAreasOverlay
+ );
+ checkbox.click();
+ await onCheckboxChange;
+
+ info("Toggling OFF the 'Display grid areas' setting.");
+ onCheckboxChange = waitUntilState(
+ store,
+ state => !state.highlighterSettings.showGridAreasOverlay
+ );
+ checkbox.click();
+ await onCheckboxChange;
+
+ ok(
+ !Services.prefs.getBoolPref(SHOW_GRID_AREAS_PREF),
+ "'Display grid areas' is pref off."
+ );
+
+ Services.prefs.clearUserPref(SHOW_GRID_AREAS_PREF);
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_display-setting-show-grid-line-numbers.js b/devtools/client/inspector/grids/test/browser_grids_display-setting-show-grid-line-numbers.js
new file mode 100644
index 0000000000..3dee2533cd
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_display-setting-show-grid-line-numbers.js
@@ -0,0 +1,65 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the 'Display numbers on lines' grid highlighter setting will update
+// the redux store and pref setting.
+
+const TEST_URI = `
+ <style type='text/css'>
+ #grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid">
+ <div id="cell1">cell1</div>
+ <div id="cell2">cell2</div>
+ </div>
+`;
+
+const SHOW_GRID_LINE_NUMBERS = "devtools.gridinspector.showGridLineNumbers";
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { inspector, gridInspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { store } = inspector;
+
+ await selectNode("#grid", inspector);
+ const checkbox = doc.getElementById("grid-setting-show-grid-line-numbers");
+
+ info("Checking the initial state of the CSS grid highlighter setting.");
+ ok(
+ !Services.prefs.getBoolPref(SHOW_GRID_LINE_NUMBERS),
+ "'Display numbers on lines' is pref off by default."
+ );
+
+ info("Toggling ON the 'Display numbers on lines' setting.");
+ let onCheckboxChange = waitUntilState(
+ store,
+ state => state.highlighterSettings.showGridLineNumbers
+ );
+ checkbox.click();
+ await onCheckboxChange;
+
+ ok(
+ Services.prefs.getBoolPref(SHOW_GRID_LINE_NUMBERS),
+ "'Display numbers on lines' is pref on."
+ );
+
+ info("Toggling OFF the 'Display numbers on lines' setting.");
+ onCheckboxChange = waitUntilState(
+ store,
+ state => !state.highlighterSettings.showGridLineNumbers
+ );
+ checkbox.click();
+ await onCheckboxChange;
+
+ ok(
+ !Services.prefs.getBoolPref(SHOW_GRID_LINE_NUMBERS),
+ "'Display numbers on lines' is pref off."
+ );
+
+ Services.prefs.clearUserPref(SHOW_GRID_LINE_NUMBERS);
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_grid-list-color-picker-on-ESC.js b/devtools/client/inspector/grids/test/browser_grids_grid-list-color-picker-on-ESC.js
new file mode 100644
index 0000000000..661c65c6e0
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-color-picker-on-ESC.js
@@ -0,0 +1,75 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the grid item's color change in the colorpicker is reverted when ESCAPE is
+// pressed.
+
+const TEST_URI = `
+ <style type='text/css'>
+ #grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid">
+ <div id="cell1">cell1</div>
+ <div id="cell2">cell2</div>
+ </div>
+`;
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { inspector, gridInspector, layoutView } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { store } = inspector;
+ const cPicker = layoutView.swatchColorPickerTooltip;
+ const spectrum = cPicker.spectrum;
+ const swatch = doc.querySelector(
+ "#layout-grid-container .layout-color-swatch"
+ );
+
+ info("Checking the initial state of the Grid Inspector.");
+ is(
+ swatch.style.backgroundColor,
+ "rgb(148, 0, 255)",
+ "The color swatch's background is correct."
+ );
+ is(
+ store.getState().grids[0].color,
+ "#9400FF",
+ "The grid color state is correct."
+ );
+
+ info("Scrolling into view of the #grid color swatch.");
+ swatch.scrollIntoView();
+
+ info("Opening the color picker by clicking on the #grid color swatch.");
+ const onColorPickerReady = cPicker.once("ready");
+ swatch.click();
+ await onColorPickerReady;
+
+ await simulateColorPickerChange(cPicker, [0, 255, 0, 0.5]);
+
+ is(
+ swatch.style.backgroundColor,
+ "rgba(0, 255, 0, 0.5)",
+ "The color swatch's background was updated."
+ );
+
+ info("Pressing ESCAPE to close the tooltip.");
+ const onGridColorUpdate = waitUntilState(
+ store,
+ state => state.grids[0].color === "#9400FF"
+ );
+ const onColorPickerHidden = cPicker.tooltip.once("hidden");
+ focusAndSendKey(spectrum.element.ownerDocument.defaultView, "ESCAPE");
+ await onColorPickerHidden;
+ await onGridColorUpdate;
+
+ is(
+ swatch.style.backgroundColor,
+ "rgb(148, 0, 255)",
+ "The color swatch's background was reverted after ESCAPE."
+ );
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_grid-list-color-picker-on-RETURN.js b/devtools/client/inspector/grids/test/browser_grids_grid-list-color-picker-on-RETURN.js
new file mode 100644
index 0000000000..9e23d68166
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-color-picker-on-RETURN.js
@@ -0,0 +1,94 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the grid item's color change in the colorpicker is committed when RETURN is
+// pressed.
+
+const TEST_URI = `
+ <style type='text/css'>
+ #grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid">
+ <div id="cell1">cell1</div>
+ <div id="cell2">cell2</div>
+ </div>
+`;
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { inspector, gridInspector, layoutView } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { highlighters, store } = inspector;
+ const cPicker = layoutView.swatchColorPickerTooltip;
+ const spectrum = cPicker.spectrum;
+ const swatch = doc.querySelector(
+ "#layout-grid-container .layout-color-swatch"
+ );
+
+ info("Checking the initial state of the Grid Inspector.");
+ is(
+ swatch.style.backgroundColor,
+ "rgb(148, 0, 255)",
+ "The color swatch's background is correct."
+ );
+ is(
+ store.getState().grids[0].color,
+ "#9400FF",
+ "The grid color state is correct."
+ );
+
+ info("Scrolling into view of the #grid color swatch.");
+ swatch.scrollIntoView();
+
+ info("Opening the color picker by clicking on the #grid color swatch.");
+ const onColorPickerReady = cPicker.once("ready");
+ swatch.click();
+ await onColorPickerReady;
+
+ await simulateColorPickerChange(cPicker, [0, 255, 0, 0.5]);
+
+ is(
+ swatch.style.backgroundColor,
+ "rgba(0, 255, 0, 0.5)",
+ "The color swatch's background was updated."
+ );
+
+ info("Pressing RETURN to commit the color change.");
+ const EXPECTED_HEX_COLOR = "#00FF0080";
+ const onGridColorUpdate = waitUntilState(
+ store,
+ state => state.grids[0].color === EXPECTED_HEX_COLOR
+ );
+ const onColorPickerHidden = cPicker.tooltip.once("hidden");
+ const onHighlighterShown = highlighters.once("highlighter-shown");
+ focusAndSendKey(spectrum.element.ownerDocument.defaultView, "RETURN");
+ await onColorPickerHidden;
+ await onGridColorUpdate;
+
+ is(
+ swatch.style.backgroundColor,
+ "rgba(0, 255, 0, 0.5)",
+ "The color swatch's background was kept after RETURN."
+ );
+
+ info("Wait for a bit to ensure the highlighter wasn't shown");
+ const raceResult = await Promise.race([
+ onHighlighterShown.then(() => "HIGHLIGHTED"),
+ wait(1000).then(() => "TIMEOUT"),
+ ]);
+ is(raceResult, "TIMEOUT", "Highlighter wasn't shown");
+
+ info("Check that highlighter does show with the expected color");
+ doc.querySelector("#grid-list input[type=checkbox]").click();
+ const { options } = await onHighlighterShown;
+
+ is(
+ options.color,
+ EXPECTED_HEX_COLOR,
+ "Highlighter was displayed with the right color"
+ );
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_grid-list-element-rep.js b/devtools/client/inspector/grids/test/browser_grids_grid-list-element-rep.js
new file mode 100644
index 0000000000..a1fba8d5e4
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-element-rep.js
@@ -0,0 +1,68 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the grid item's element rep will display the box model higlighter on hover
+// and select the node on click.
+
+const TEST_URI = `
+ <style type='text/css'>
+ #grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid">
+ <div id="cell1">cell1</div>
+ <div id="cell2">cell2</div>
+ </div>
+`;
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { inspector, gridInspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { store } = inspector;
+ const { waitForHighlighterTypeShown } = getHighlighterTestHelpers(inspector);
+
+ const gridList = doc.querySelector("#grid-list");
+ const elementRep = gridList.children[0].querySelector(".open-inspector");
+ info("Scrolling into the view the #grid element node rep.");
+ elementRep.scrollIntoView();
+
+ info("Listen to node-highlight event and mouse over the widget");
+ const onHighlight = waitForHighlighterTypeShown(
+ inspector.highlighters.TYPES.BOXMODEL
+ );
+ EventUtils.synthesizeMouse(
+ elementRep,
+ 10,
+ 5,
+ { type: "mouseover" },
+ doc.defaultView
+ );
+ const { nodeFront } = await onHighlight;
+
+ ok(nodeFront, "nodeFront was returned from highlighting the node.");
+ is(nodeFront.tagName, "DIV", "The highlighted node has the correct tagName.");
+ is(
+ nodeFront.attributes[0].name,
+ "id",
+ "The highlighted node has the correct attributes."
+ );
+ is(
+ nodeFront.attributes[0].value,
+ "grid",
+ "The highlighted node has the correct id."
+ );
+
+ const onSelection = inspector.selection.once("new-node-front");
+ EventUtils.sendMouseEvent({ type: "click" }, elementRep, doc.defaultView);
+ await onSelection;
+
+ is(
+ inspector.selection.nodeFront,
+ store.getState().grids[0].nodeFront,
+ "The selected node is the one stored on the grid item's state."
+ );
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_grid-list-no-grids.js b/devtools/client/inspector/grids/test/browser_grids_grid-list-no-grids.js
new file mode 100644
index 0000000000..ce9cbc7866
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-no-grids.js
@@ -0,0 +1,37 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that no grid list items and a "no grids available" message is displayed when
+// there are no grid containers on the page.
+
+const TEST_URI = `
+ <style type='text/css'>
+ </style>
+ <div id="grid">
+ <div id="cell1">cell1</div>
+ <div id="cell2">cell2</div>
+ </div>
+`;
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { inspector, gridInspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { highlighters } = inspector;
+
+ await selectNode("#grid", inspector);
+ const noGridList = doc.querySelector(
+ "#layout-grid-section .devtools-sidepanel-no-result"
+ );
+ const gridList = doc.getElementById("grid-list");
+
+ info("Checking the initial state of the Grid Inspector.");
+ ok(noGridList, "The message no grid containers is displayed.");
+ ok(!gridList, "No grid containers are listed.");
+ ok(
+ !highlighters.gridHighlighters.size,
+ "No CSS grid highlighter exists in the highlighters overlay."
+ );
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_grid-list-on-iframe-reloaded.js b/devtools/client/inspector/grids/test/browser_grids_grid-list-on-iframe-reloaded.js
new file mode 100644
index 0000000000..b5871414f8
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-on-iframe-reloaded.js
@@ -0,0 +1,57 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the list of grids does refresh when an iframe containing a grid is removed
+// and re-created.
+// See bug 1378306 where this happened with jsfiddle.
+
+const TEST_URI = URL_ROOT + "doc_iframe_reloaded.html";
+
+add_task(async function () {
+ await addTab(TEST_URI);
+ const { gridInspector, inspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { highlighters, store } = inspector;
+ const gridList = doc.getElementById("grid-list");
+ const checkbox = gridList.children[0].querySelector("input");
+
+ info("Clicking on the first checkbox to highlight the grid");
+ const onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ const onCheckboxChange = waitUntilState(
+ store,
+ state => state.grids.length == 1 && state.grids[0].highlighted
+ );
+ checkbox.click();
+ await onHighlighterShown;
+ await onCheckboxChange;
+
+ ok(checkbox.checked, "The checkbox is checked");
+ is(gridList.childNodes.length, 1, "There's one grid in the list");
+ is(highlighters.gridHighlighters.size, 1, "There's a highlighter shown");
+ is(
+ highlighters.state.grids.size,
+ 1,
+ "There's a saved grid state to be restored."
+ );
+
+ info("Reload the iframe in content and expect the grid list to update");
+ const oldGrid = store.getState().grids[0];
+ const onNewListUnchecked = waitUntilState(
+ store,
+ state =>
+ state.grids.length == 1 &&
+ state.grids[0].actorID !== oldGrid.actorID &&
+ !state.grids[0].highlighted
+ );
+ const onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
+ SpecialPowers.spawn(gBrowser.selectedBrowser, [], () =>
+ content.wrappedJSObject.reloadIFrame()
+ );
+ await onNewListUnchecked;
+ await onHighlighterHidden;
+
+ is(gridList.childNodes.length, 1, "There's still one grid in the list");
+ ok(!highlighters.state.grids.size, "No grids to be restored on page reload.");
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_grid-list-on-mutation-element-added.js b/devtools/client/inspector/grids/test/browser_grids_grid-list-on-mutation-element-added.js
new file mode 100644
index 0000000000..e197f03b02
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-on-mutation-element-added.js
@@ -0,0 +1,100 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the grid list updates when a new grid container is added to the page.
+
+const TEST_URI = `
+ <style type='text/css'>
+ .grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid1" class="grid">
+ <div class="cell1">cell1</div>
+ <div class="cell2">cell2</div>
+ </div>
+ <div id="grid2">
+ <div class="cell1">cell1</div>
+ <div class="cell2">cell2</div>
+ </div>
+`;
+
+add_task(async function () {
+ await pushPref("devtools.gridinspector.maxHighlighters", 1);
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { inspector, gridInspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { highlighters, store } = inspector;
+
+ await selectNode("#grid", inspector);
+ const gridList = doc.getElementById("grid-list");
+ const checkbox1 = gridList.children[0].querySelector("input");
+
+ info("Checking the initial state of the Grid Inspector.");
+ is(gridList.childNodes.length, 1, "One grid container is listed.");
+ ok(
+ !highlighters.gridHighlighters.size,
+ "No CSS grid highlighter exists in the highlighters overlay."
+ );
+
+ info("Toggling ON the CSS grid highlighter from the layout panel.");
+ let onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ checkbox1.click();
+ await onHighlighterShown;
+
+ info("Checking the CSS grid highlighter is created.");
+ is(highlighters.gridHighlighters.size, 1, "CSS grid highlighter is shown.");
+
+ info("Adding the #grid2 container in the content page.");
+ const onGridListUpdate = waitUntilState(
+ store,
+ state =>
+ state.grids.length == 2 &&
+ state.grids[0].highlighted &&
+ !state.grids[1].highlighted
+ );
+ SpecialPowers.spawn(gBrowser.selectedBrowser, [], () =>
+ content.document.getElementById("grid2").classList.add("grid")
+ );
+ await onGridListUpdate;
+
+ info("Checking the new Grid Inspector state.");
+ is(gridList.childNodes.length, 2, "Two grid containers are listed.");
+ is(highlighters.gridHighlighters.size, 1, "CSS grid highlighter is shown.");
+
+ const checkbox2 = gridList.children[1].querySelector("input");
+
+ info("Toggling ON the CSS grid highlighter for #grid2.");
+ onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ let onCheckboxChange = waitUntilState(
+ store,
+ state =>
+ state.grids.length == 2 &&
+ !state.grids[0].highlighted &&
+ state.grids[1].highlighted
+ );
+ checkbox2.click();
+ await onHighlighterShown;
+ await onCheckboxChange;
+
+ info("Checking the CSS grid highlighter is still shown.");
+ is(highlighters.gridHighlighters.size, 1, "CSS grid highlighter is shown.");
+
+ info("Toggling OFF the CSS grid highlighter from the layout panel.");
+ const onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
+ onCheckboxChange = waitUntilState(
+ store,
+ state =>
+ state.grids.length == 2 &&
+ !state.grids[0].highlighted &&
+ !state.grids[1].highlighted
+ );
+ checkbox2.click();
+ await onHighlighterHidden;
+ await onCheckboxChange;
+
+ info("Checking the CSS grid highlighter is not shown.");
+ ok(!highlighters.gridHighlighters.size, "No CSS grid highlighter is shown.");
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_grid-list-on-mutation-element-removed.js b/devtools/client/inspector/grids/test/browser_grids_grid-list-on-mutation-element-removed.js
new file mode 100644
index 0000000000..7a60759071
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-on-mutation-element-removed.js
@@ -0,0 +1,63 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the grid item is removed from the grid list when the grid container is
+// removed from the page.
+
+const TEST_URI = `
+ <style type='text/css'>
+ #grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid">
+ <div id="cell1">cell1</div>
+ <div id="cell2">cell2</div>
+ </div>
+`;
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { inspector, gridInspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { highlighters, store } = inspector;
+
+ await selectNode("#grid", inspector);
+ const gridList = doc.getElementById("grid-list");
+ const checkbox = gridList.children[0].querySelector("input");
+
+ info("Checking the initial state of the Grid Inspector.");
+ is(gridList.childNodes.length, 1, "One grid container is listed.");
+ ok(!highlighters.gridHighlighters.size, "No CSS grid highlighter is shown.");
+
+ info("Toggling ON the CSS grid highlighter from the layout panel.");
+ const onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ let onCheckboxChange = waitUntilState(
+ store,
+ state => state.grids.length == 1 && state.grids[0].highlighted
+ );
+ checkbox.click();
+ await onHighlighterShown;
+ await onCheckboxChange;
+
+ info("Checking the CSS grid highlighter is created.");
+ is(highlighters.gridHighlighters.size, 1, "CSS grid highlighter is shown.");
+
+ info("Removing the #grid container in the content page.");
+ const onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
+ onCheckboxChange = waitUntilState(store, state => !state.grids.length);
+ SpecialPowers.spawn(gBrowser.selectedBrowser, [], () =>
+ content.document.getElementById("grid").remove()
+ );
+ await onHighlighterHidden;
+ await onCheckboxChange;
+
+ info("Checking the CSS grid highlighter is not shown.");
+ ok(!highlighters.gridHighlighters.size, "No CSS grid highlighter is shown.");
+ const noGridList = doc.querySelector(
+ "#layout-grid-section .devtools-sidepanel-no-result"
+ );
+ ok(noGridList, "The message no grid containers is displayed.");
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_grid-list-on-target-added-removed.js b/devtools/client/inspector/grids/test/browser_grids_grid-list-on-target-added-removed.js
new file mode 100644
index 0000000000..051fc14e53
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-on-target-added-removed.js
@@ -0,0 +1,203 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the list of grids does refresh when targets are added or removed (e.g. when
+// there's a navigation and iframe are added or removed)
+
+add_task(async function () {
+ await addTab(getDocumentBuilderUrl("example.com", "top-level-com-grid"));
+ const { gridInspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+
+ const checkGridList = (expected, assertionMessage) =>
+ checkGridListItems(doc, expected, assertionMessage);
+
+ checkGridList(
+ ["div#top-level-com-grid"],
+ "One grid item is displayed at first"
+ );
+
+ info(
+ "Check that adding same-origin iframe with a grid will update the grid list"
+ );
+ const sameOriginIframeBrowsingContext = await SpecialPowers.spawn(
+ gBrowser.selectedBrowser,
+ [getDocumentBuilderUrl("example.com", "iframe-com-grid")],
+ src => {
+ const iframe = content.document.createElement("iframe");
+ iframe.id = "same-origin";
+ iframe.src = src;
+ content.document.body.append(iframe);
+ return iframe.browsingContext;
+ }
+ );
+
+ await waitFor(() => getGridListItems(doc).length == 2);
+ checkGridList(
+ ["div#top-level-com-grid", "div#iframe-com-grid"],
+ "The same-origin iframe grid is displayed"
+ );
+
+ info("Check that adding remote iframe with a grid will update the grid list");
+ const remoteIframeBrowsingContext = await SpecialPowers.spawn(
+ gBrowser.selectedBrowser,
+ [getDocumentBuilderUrl("example.org", "iframe-org-grid")],
+ src => {
+ const iframe = content.document.createElement("iframe");
+ iframe.id = "remote";
+ iframe.src = src;
+ content.document.body.append(iframe);
+ return iframe.browsingContext;
+ }
+ );
+
+ await waitFor(() => getGridListItems(doc).length == 3);
+ checkGridList(
+ ["div#top-level-com-grid", "div#iframe-com-grid", "div#iframe-org-grid"],
+ "The remote iframe grid is displayed"
+ );
+
+ info("Check that adding new grids in iframes does update the grid list");
+ SpecialPowers.spawn(sameOriginIframeBrowsingContext, [], () => {
+ const section = content.document.createElement("section");
+ section.id = "com-added-grid-container";
+ section.style = "display: grid;";
+ content.document.body.append(section);
+ });
+
+ await waitFor(() => getGridListItems(doc).length == 4);
+ checkGridList(
+ [
+ "div#top-level-com-grid",
+ "div#iframe-com-grid",
+ "section#com-added-grid-container",
+ "div#iframe-org-grid",
+ ],
+ "The new grid in the same origin iframe is displayed"
+ );
+
+ SpecialPowers.spawn(remoteIframeBrowsingContext, [], () => {
+ const section = content.document.createElement("section");
+ section.id = "org-added-grid-container";
+ section.style = "display: grid;";
+ content.document.body.append(section);
+ });
+
+ await waitFor(() => getGridListItems(doc).length == 5);
+ checkGridList(
+ [
+ "div#top-level-com-grid",
+ "div#iframe-com-grid",
+ "section#com-added-grid-container",
+ "div#iframe-org-grid",
+ "section#org-added-grid-container",
+ ],
+ "The new grid in the same origin iframe is displayed"
+ );
+
+ info("Check that removing iframes will update the grid list");
+ SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
+ content.document.querySelector("iframe#same-origin").remove();
+ });
+
+ await waitFor(() => getGridListItems(doc).length == 3);
+ checkGridList(
+ [
+ "div#top-level-com-grid",
+ "div#iframe-org-grid",
+ "section#org-added-grid-container",
+ ],
+ "The same-origin iframe grids were removed from the list"
+ );
+
+ SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
+ content.document.querySelector("iframe#remote").remove();
+ });
+
+ await waitFor(() => getGridListItems(doc).length == 1);
+ checkGridList(
+ ["div#top-level-com-grid"],
+ "The remote iframe grids were removed as well"
+ );
+
+ info("Navigate to a new origin");
+ await navigateTo(getDocumentBuilderUrl("example.org", "top-level-org-grid"));
+ await waitFor(() => {
+ const listItems = getGridListItems(doc);
+ return (
+ listItems.length == 1 &&
+ listItems[0].textContent.includes("#top-level-org-grid")
+ );
+ });
+ checkGridList(
+ ["div#top-level-org-grid"],
+ "The grid from the new origin document is displayed"
+ );
+
+ info("Check that adding remote iframe will still update the grid list");
+ SpecialPowers.spawn(
+ gBrowser.selectedBrowser,
+ [getDocumentBuilderUrl("example.com", "iframe-com-grid-remote")],
+ src => {
+ const iframe = content.document.createElement("iframe");
+ iframe.id = "remote";
+ iframe.src = src;
+ content.document.body.append(iframe);
+ }
+ );
+
+ await waitFor(() => getGridListItems(doc).length == 2);
+ checkGridList(
+ ["div#top-level-org-grid", "div#iframe-com-grid-remote"],
+ "The grid from the new origin document is displayed"
+ );
+
+ info(
+ "Check that adding same-origin iframe with a grid will update the grid list"
+ );
+ SpecialPowers.spawn(
+ gBrowser.selectedBrowser,
+ [getDocumentBuilderUrl("example.org", "iframe-org-grid-same-origin")],
+ src => {
+ const iframe = content.document.createElement("iframe");
+ iframe.id = "same-origin";
+ iframe.src = src;
+ content.document.body.append(iframe);
+ }
+ );
+ await waitFor(() => getGridListItems(doc).length == 3);
+ checkGridList(
+ [
+ "div#top-level-org-grid",
+ "div#iframe-com-grid-remote",
+ "div#iframe-org-grid-same-origin",
+ ],
+ "The grid from the new same-origin iframe is displayed"
+ );
+});
+
+function getDocumentBuilderUrl(origin, gridContainerId) {
+ return `https://${origin}/document-builder.sjs?html=${encodeURIComponent(
+ `<style>
+ #${gridContainerId} {
+ display: grid;
+ }
+ </style>
+ <div id="${gridContainerId}"></div>`
+ )}`;
+}
+
+function getGridListItems(doc) {
+ return Array.from(doc.querySelectorAll("#grid-list .objectBox-node"));
+}
+
+function checkGridListItems(doc, expectedItems, assertionText) {
+ const gridItems = getGridListItems(doc).map(el => el.textContent);
+ is(
+ JSON.stringify(gridItems.sort()),
+ JSON.stringify(expectedItems.sort()),
+ assertionText
+ );
+}
diff --git a/devtools/client/inspector/grids/test/browser_grids_grid-list-subgrids-z-order.js b/devtools/client/inspector/grids/test/browser_grids_grid-list-subgrids-z-order.js
new file mode 100644
index 0000000000..da1b11f4c8
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-subgrids-z-order.js
@@ -0,0 +1,83 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test the z order of grids.
+
+const TEST_URI = URL_ROOT + "doc_subgrid.html";
+
+add_task(async () => {
+ await addTab(TEST_URI);
+ const { gridInspector, inspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { highlighters, store } = inspector;
+
+ await selectNode("#grid", inspector);
+ await waitUntilState(store, state => state.grids.length === 5);
+
+ const parentEl = doc.getElementById("grid-list");
+ // Input for .container
+ const parentInput = parentEl.children[0].querySelector("input");
+ const subgridEl = parentEl.children[1];
+ // Input for <main>
+ const subgridInput = subgridEl.children[1].querySelector("input");
+ const grandSubgridEl = subgridEl.children[2];
+ // Input for .aside1
+ const grandSubgridInput = grandSubgridEl.children[0].querySelector("input");
+
+ info(
+ "Toggling ON the CSS grid highlighters for .container, <main> and .aside1"
+ );
+ const grandSubgridFront = await toggle(grandSubgridInput, highlighters);
+ const subgridFront = await toggle(subgridInput, highlighters);
+ let parentFront = await toggle(parentInput, highlighters);
+ await waitUntilState(
+ store,
+ state => state.grids.filter(g => g.highlighted).length === 3
+ );
+
+ info("Check z-index of grid highlighting");
+ is(getZIndex(store, parentFront), 0, "z-index of parent grid is 0");
+ is(getZIndex(store, subgridFront), 1, "z-index of subgrid is 1");
+ is(getZIndex(store, grandSubgridFront), 2, "z-index of subgrid is 2");
+
+ info("Toggling OFF the CSS grid highlighters for .container");
+ await toggle(parentInput, highlighters);
+ await waitUntilState(
+ store,
+ state => state.grids.filter(g => g.highlighted).length === 2
+ );
+
+ info("Check z-index keeps even if the parent grid is hidden");
+ is(getZIndex(store, subgridFront), 1, "z-index of subgrid is 1");
+ is(getZIndex(store, grandSubgridFront), 2, "z-index of subgrid is 2");
+
+ info("Toggling ON again the CSS grid highlighters for .container");
+ parentFront = await toggle(parentInput, highlighters);
+ await waitUntilState(
+ store,
+ state => state.grids.filter(g => g.highlighted).length === 3
+ );
+
+ info("Check z-index of all of grids highlighting keeps");
+ is(getZIndex(store, parentFront), 0, "z-index of parent grid is 0");
+ is(getZIndex(store, subgridFront), 1, "z-index of subgrid is 1");
+ is(getZIndex(store, grandSubgridFront), 2, "z-index of subgrid is 2");
+});
+
+function getZIndex(store, nodeFront) {
+ const grids = store.getState().grids;
+ const gridData = grids.find(g => g.nodeFront === nodeFront);
+ return gridData.zIndex;
+}
+
+async function toggle(input, highlighters) {
+ const eventName = input.checked
+ ? "grid-highlighter-hidden"
+ : "grid-highlighter-shown";
+ const onHighlighterEvent = highlighters.once(eventName);
+ input.click();
+ const nodeFront = await onHighlighterEvent;
+ return nodeFront;
+}
diff --git a/devtools/client/inspector/grids/test/browser_grids_grid-list-subgrids_01.js b/devtools/client/inspector/grids/test/browser_grids_grid-list-subgrids_01.js
new file mode 100644
index 0000000000..bcb0faeef8
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-subgrids_01.js
@@ -0,0 +1,138 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the list of grids show the subgrids in the correct nested list and toggling
+// the CSS grid highlighter for a subgrid.
+
+const TEST_URI = URL_ROOT + "doc_subgrid.html";
+
+add_task(async function () {
+ await addTab(TEST_URI);
+ const { gridInspector, inspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { highlighters, store } = inspector;
+
+ await selectNode(".container", inspector);
+ const gridListEl = doc.getElementById("grid-list");
+ const containerSubgridListEl = gridListEl.children[1];
+ const mainSubgridListEl = containerSubgridListEl.querySelector("ul");
+
+ info("Checking the initial state of the Grid Inspector.");
+ is(
+ getGridItemElements(gridListEl).length,
+ 1,
+ "One grid container is listed."
+ );
+ is(
+ getGridItemElements(containerSubgridListEl).length,
+ 2,
+ "Got the correct number of subgrids in div.container"
+ );
+ is(
+ getGridItemElements(mainSubgridListEl).length,
+ 2,
+ "Got the correct number of subgrids in main.subgrid"
+ );
+ ok(
+ !highlighters.gridHighlighters.size &&
+ !highlighters.parentGridHighlighters.size,
+ "No CSS grid highlighter is shown."
+ );
+
+ info("Toggling ON the CSS grid highlighter for header.");
+ let onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ let onCheckboxChange = waitUntilState(
+ store,
+ state => state.grids[1].highlighted
+ );
+ let checkbox = containerSubgridListEl.children[0].querySelector("input");
+ checkbox.click();
+ await onHighlighterShown;
+ await onCheckboxChange;
+
+ info(
+ "Checking the CSS grid highlighter and parent grid highlighter are created."
+ );
+ is(highlighters.gridHighlighters.size, 1, "CSS grid highlighter is shown.");
+ is(
+ highlighters.parentGridHighlighters.size,
+ 1,
+ "CSS grid highlighter for parent grid container is shown."
+ );
+
+ info("Toggling ON the CSS grid highlighter for main.");
+ onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ onCheckboxChange = waitUntilState(
+ store,
+ state => state.grids[1].highlighted && state.grids[2].highlighted
+ );
+ checkbox = containerSubgridListEl.children[1].querySelector("input");
+ checkbox.click();
+ await onHighlighterShown;
+ await onCheckboxChange;
+
+ info("Checking the number of CSS grid highlighters present.");
+ is(
+ highlighters.gridHighlighters.size,
+ 2,
+ "Got the correct number of CSS grid highlighter shown."
+ );
+ is(
+ highlighters.parentGridHighlighters.size,
+ 1,
+ "Only 1 parent grid highlighter should be shown for the same subgrid parent."
+ );
+
+ info("Toggling OFF the CSS grid highlighter for main.");
+ let onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
+ onCheckboxChange = waitUntilState(
+ store,
+ state => state.grids[1].highlighted && !state.grids[2].highlighted
+ );
+ checkbox.click();
+ await onHighlighterHidden;
+ await onCheckboxChange;
+
+ info("Checking the number of CSS grid highlighters present.");
+ is(
+ highlighters.gridHighlighters.size,
+ 1,
+ "Got the correct number of CSS grid highlighter shown."
+ );
+ is(
+ highlighters.parentGridHighlighters.size,
+ 1,
+ "Got the correct number of CSS grid parent highlighter shown."
+ );
+
+ info("Toggling OFF the CSS grid highlighter for header.");
+ onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
+ onCheckboxChange = waitUntilState(
+ store,
+ state => !state.grids[1].highlighted
+ );
+ checkbox = containerSubgridListEl.children[0].querySelector("input");
+ checkbox.click();
+ await onHighlighterHidden;
+ await onCheckboxChange;
+
+ info("Checking the CSS grid highlighter is not shown.");
+ ok(
+ !highlighters.gridHighlighters.size &&
+ !highlighters.parentGridHighlighters.size,
+ "No CSS grid highlighter is shown."
+ );
+});
+
+/**
+ * Returns the grid item elements <li> from the grid list element <ul>.
+ *
+ * @param {Element} gridListEl
+ * The grid list element <ul>.
+ * @return {Array<Element>} containing the grid item elements <li>.
+ */
+function getGridItemElements(gridListEl) {
+ return [...gridListEl.children].filter(node => node.nodeName === "li");
+}
diff --git a/devtools/client/inspector/grids/test/browser_grids_grid-list-subgrids_02.js b/devtools/client/inspector/grids/test/browser_grids_grid-list-subgrids_02.js
new file mode 100644
index 0000000000..83f07e339a
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-subgrids_02.js
@@ -0,0 +1,72 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test the state of grid highlighters after toggling the checkbox of subgrids.
+
+const TEST_URI = URL_ROOT + "doc_subgrid.html";
+
+add_task(async () => {
+ await addTab(TEST_URI);
+ const { gridInspector, inspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { highlighters, store } = inspector;
+
+ await selectNode(".container", inspector);
+ const parentEl = doc.getElementById("grid-list");
+ // Input for .container
+ const parentInput = parentEl.children[0].querySelector("input");
+ const subgridEl = parentEl.children[1];
+ // Input for <main>
+ const subgridInput = subgridEl.children[1].querySelector("input");
+ const grandSubgridEl = subgridEl.children[2];
+ // Input for .aside1
+ const grandSubgridInput = grandSubgridEl.children[0].querySelector("input");
+
+ info(
+ "Toggling ON the CSS grid highlighters for .container, <main> and .aside1"
+ );
+ await toggleHighlighter(parentInput, highlighters);
+ await toggleHighlighter(subgridInput, highlighters);
+ await toggleHighlighter(grandSubgridInput, highlighters);
+ await waitUntilState(
+ store,
+ state => state.grids.filter(g => g.highlighted).length === 3
+ );
+
+ info("Check the state of highlighters");
+ is(
+ highlighters.gridHighlighters.size,
+ 3,
+ "All highlighters are use as normal highlighter"
+ );
+
+ info("Toggling OFF the CSS grid highlighter for <main>");
+ await toggleHighlighter(subgridInput, highlighters);
+ await waitUntilState(
+ store,
+ state => state.grids.filter(g => g.highlighted).length === 2
+ );
+
+ info("Check the state of highlighters after hiding subgrid for <main>");
+ is(
+ highlighters.gridHighlighters.size,
+ 2,
+ "2 highlighters are use as normal highlighter"
+ );
+ is(
+ highlighters.parentGridHighlighters.size,
+ 1,
+ "The highlighter for <main> is used as parent highlighter"
+ );
+});
+
+async function toggleHighlighter(input, highlighters) {
+ const eventName = input.checked
+ ? "grid-highlighter-hidden"
+ : "grid-highlighter-shown";
+ const onHighlighterEvent = highlighters.once(eventName);
+ input.click();
+ await onHighlighterEvent;
+}
diff --git a/devtools/client/inspector/grids/test/browser_grids_grid-list-toggle-grids_01.js b/devtools/client/inspector/grids/test/browser_grids_grid-list-toggle-grids_01.js
new file mode 100644
index 0000000000..f66e70042c
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-toggle-grids_01.js
@@ -0,0 +1,63 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests toggling ON/OFF the grid highlighter from the grid ispector panel.
+
+const TEST_URI = `
+ <style type='text/css'>
+ #grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid">
+ <div id="cell1">cell1</div>
+ <div id="cell2">cell2</div>
+ </div>
+`;
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { gridInspector, inspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { highlighters, store } = inspector;
+
+ await selectNode("#grid", inspector);
+ const gridList = doc.getElementById("grid-list");
+ const checkbox = gridList.children[0].querySelector("input");
+
+ info("Checking the initial state of the Grid Inspector.");
+ is(gridList.childNodes.length, 1, "One grid container is listed.");
+ ok(
+ !checkbox.checked,
+ `Grid item ${checkbox.value} is unchecked in the grid list.`
+ );
+ ok(!highlighters.gridHighlighters.size, "No CSS grid highlighter is shown.");
+
+ info("Toggling ON the CSS grid highlighter from the layout panel.");
+ const onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ let onCheckboxChange = waitUntilState(
+ store,
+ state => state.grids.length == 1 && state.grids[0].highlighted
+ );
+ checkbox.click();
+ await onHighlighterShown;
+ await onCheckboxChange;
+
+ info("Checking the CSS grid highlighter is created.");
+ is(highlighters.gridHighlighters.size, 1, "CSS grid highlighter is shown.");
+
+ info("Toggling OFF the CSS grid highlighter from the layout panel.");
+ const onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
+ onCheckboxChange = waitUntilState(
+ store,
+ state => state.grids.length == 1 && !state.grids[0].highlighted
+ );
+ checkbox.click();
+ await onHighlighterHidden;
+ await onCheckboxChange;
+
+ info("Checking the CSS grid highlighter is not shown.");
+ ok(!highlighters.gridHighlighters.size, "No CSS grid highlighter is shown.");
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_grid-list-toggle-grids_02.js b/devtools/client/inspector/grids/test/browser_grids_grid-list-toggle-grids_02.js
new file mode 100644
index 0000000000..82f3d9bef4
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-toggle-grids_02.js
@@ -0,0 +1,96 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test toggling the grid highlighter in the grid inspector panel with multiple grids in
+// the page.
+
+const TEST_URI = `
+ <style type='text/css'>
+ .grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid1" class="grid">
+ <div class="cell1">cell1</div>
+ <div class="cell2">cell2</div>
+ </div>
+ <div id="grid2" class="grid">
+ <div class="cell1">cell1</div>
+ <div class="cell2">cell2</div>
+ </div>
+`;
+
+add_task(async function () {
+ await pushPref("devtools.gridinspector.maxHighlighters", 1);
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { inspector, gridInspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { highlighters, store } = inspector;
+
+ await selectNode("#grid1", inspector);
+ const gridList = doc.getElementById("grid-list");
+ const checkbox1 = gridList.children[0].querySelector("input");
+ const checkbox2 = gridList.children[1].querySelector("input");
+
+ info("Checking the initial state of the Grid Inspector.");
+ is(gridList.childNodes.length, 2, "2 grid containers are listed.");
+ ok(
+ !checkbox1.checked,
+ `Grid item ${checkbox1.value} is unchecked in the grid list.`
+ );
+ ok(
+ !checkbox2.checked,
+ `Grid item ${checkbox2.value} is unchecked in the grid list.`
+ );
+ ok(!highlighters.gridHighlighters.size, "No CSS grid highlighter is shown.");
+
+ info("Toggling ON the CSS grid highlighter for #grid1.");
+ let onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ let onCheckboxChange = waitUntilState(
+ store,
+ state =>
+ state.grids.length == 2 &&
+ state.grids[0].highlighted &&
+ !state.grids[1].highlighted
+ );
+ checkbox1.click();
+ await onHighlighterShown;
+ await onCheckboxChange;
+
+ info("Checking the CSS grid highlighter is created.");
+ is(highlighters.gridHighlighters.size, 1, "CSS grid highlighter is shown.");
+
+ info("Toggling ON the CSS grid highlighter for #grid2.");
+ onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ onCheckboxChange = waitUntilState(
+ store,
+ state =>
+ state.grids.length == 2 &&
+ !state.grids[0].highlighted &&
+ state.grids[1].highlighted
+ );
+ checkbox2.click();
+ await onHighlighterShown;
+ await onCheckboxChange;
+
+ info("Checking the CSS grid highlighter is still shown.");
+ is(highlighters.gridHighlighters.size, 1, "CSS grid highlighter is shown.");
+
+ info("Toggling OFF the CSS grid highlighter from the layout panel.");
+ const onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
+ onCheckboxChange = waitUntilState(
+ store,
+ state =>
+ state.grids.length == 2 &&
+ !state.grids[0].highlighted &&
+ !state.grids[1].highlighted
+ );
+ checkbox2.click();
+ await onHighlighterHidden;
+ await onCheckboxChange;
+
+ info("Checking the CSS grid highlighter is not shown.");
+ ok(!highlighters.gridHighlighters.size, "No CSS grid highlighter is shown.");
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_grid-list-toggle-multiple-grids.js b/devtools/client/inspector/grids/test/browser_grids_grid-list-toggle-multiple-grids.js
new file mode 100644
index 0000000000..857ff75912
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-toggle-multiple-grids.js
@@ -0,0 +1,243 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test toggling multiple grid highlighters in the grid inspector panel.
+
+const TEST_URI = `
+ <style type='text/css'>
+ .grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid1" class="grid">
+ <div class="cell1">cell1</div>
+ <div class="cell2">cell2</div>
+ </div>
+ <div id="grid2" class="grid">
+ <div class="cell1">cell1</div>
+ <div class="cell2">cell2</div>
+ </div>
+ <div id="grid3" class="grid">
+ <div class="cell1">cell1</div>
+ <div class="cell2">cell2</div>
+ </div>
+ <div id="grid4" class="grid">
+ <div class="cell1">cell1</div>
+ <div class="cell2">cell2</div>
+ </div>
+`;
+
+add_task(async function () {
+ await pushPref("devtools.gridinspector.maxHighlighters", 3);
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { inspector, gridInspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { highlighters, store } = inspector;
+
+ await selectNode("#grid1", inspector);
+ const gridList = doc.getElementById("grid-list");
+ const checkbox1 = gridList.children[0].querySelector("input");
+ const checkbox2 = gridList.children[1].querySelector("input");
+ const checkbox3 = gridList.children[2].querySelector("input");
+ const checkbox4 = gridList.children[3].querySelector("input");
+
+ info("Checking the initial state of the Grid Inspector.");
+ is(gridList.childNodes.length, 4, "4 grid containers are listed.");
+ ok(
+ !checkbox1.checked,
+ `Grid item ${checkbox1.value} is unchecked in the grid list.`
+ );
+ ok(
+ !checkbox2.checked,
+ `Grid item ${checkbox2.value} is unchecked in the grid list.`
+ );
+ ok(
+ !checkbox3.checked,
+ `Grid item ${checkbox3.value} is unchecked in the grid list.`
+ );
+ ok(
+ !checkbox4.checked,
+ `Grid item ${checkbox4.value} is unchecked in the grid list.`
+ );
+ ok(!highlighters.gridHighlighters.size, "No CSS grid highlighter is shown.");
+
+ info("Toggling ON the CSS grid highlighter for #grid1.");
+ let onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ let onCheckboxChange = waitUntilState(
+ store,
+ state =>
+ state.grids.length == 4 &&
+ state.grids[0].highlighted &&
+ !state.grids[0].disabled &&
+ !state.grids[1].highlighted &&
+ !state.grids[1].disabled &&
+ !state.grids[2].highlighted &&
+ !state.grids[2].disabled &&
+ !state.grids[3].highlighted &&
+ !state.grids[3].disabled
+ );
+ checkbox1.click();
+ await onHighlighterShown;
+ await onCheckboxChange;
+
+ info(
+ "Check that the CSS grid highlighter is created and the saved grid state."
+ );
+ is(
+ highlighters.gridHighlighters.size,
+ 1,
+ "Got expected number of grid highlighters shown."
+ );
+ is(
+ highlighters.state.grids.size,
+ 1,
+ "Got expected number of grids in the saved state"
+ );
+
+ info("Toggling ON the CSS grid highlighter for #grid2.");
+ onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ onCheckboxChange = waitUntilState(
+ store,
+ state =>
+ state.grids.length == 4 &&
+ state.grids[0].highlighted &&
+ !state.grids[0].disabled &&
+ state.grids[1].highlighted &&
+ !state.grids[1].disabled &&
+ !state.grids[2].highlighted &&
+ !state.grids[2].disabled &&
+ !state.grids[3].highlighted &&
+ !state.grids[3].disabled
+ );
+ checkbox2.click();
+ await onHighlighterShown;
+ await onCheckboxChange;
+
+ is(
+ highlighters.gridHighlighters.size,
+ 2,
+ "Got expected number of grid highlighters shown."
+ );
+ is(
+ highlighters.state.grids.size,
+ 2,
+ "Got expected number of grids in the saved state"
+ );
+
+ info("Toggling ON the CSS grid highlighter for #grid3.");
+ onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ onCheckboxChange = waitUntilState(
+ store,
+ state =>
+ state.grids.length == 4 &&
+ state.grids[0].highlighted &&
+ !state.grids[0].disabled &&
+ state.grids[1].highlighted &&
+ !state.grids[1].disabled &&
+ state.grids[2].highlighted &&
+ !state.grids[2].disabled &&
+ !state.grids[3].highlighted &&
+ state.grids[3].disabled
+ );
+ checkbox3.click();
+ await onHighlighterShown;
+ await onCheckboxChange;
+
+ is(
+ highlighters.gridHighlighters.size,
+ 3,
+ "Got expected number of grid highlighters shown."
+ );
+ is(
+ highlighters.state.grids.size,
+ 3,
+ "Got expected number of grids in the saved state"
+ );
+
+ info("Toggling OFF the CSS grid highlighter for #grid3.");
+ let onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
+ onCheckboxChange = waitUntilState(
+ store,
+ state =>
+ state.grids.length == 4 &&
+ state.grids[0].highlighted &&
+ !state.grids[0].disabled &&
+ state.grids[1].highlighted &&
+ !state.grids[1].disabled &&
+ !state.grids[2].highlighted &&
+ !state.grids[2].disabled &&
+ !state.grids[3].highlighted &&
+ !state.grids[3].disabled
+ );
+ checkbox3.click();
+ await onHighlighterHidden;
+ await onCheckboxChange;
+
+ is(
+ highlighters.gridHighlighters.size,
+ 2,
+ "Got expected number of grid highlighters shown."
+ );
+ is(
+ highlighters.state.grids.size,
+ 2,
+ "Got expected number of grids in the saved state"
+ );
+
+ info("Toggling OFF the CSS grid highlighter for #grid2.");
+ onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
+ onCheckboxChange = waitUntilState(
+ store,
+ state =>
+ state.grids.length == 4 &&
+ state.grids[0].highlighted &&
+ !state.grids[0].disabled &&
+ !state.grids[1].highlighted &&
+ !state.grids[1].disabled &&
+ !state.grids[2].highlighted &&
+ !state.grids[2].disabled &&
+ !state.grids[3].highlighted &&
+ !state.grids[3].disabled
+ );
+ checkbox2.click();
+ await onHighlighterHidden;
+ await onCheckboxChange;
+
+ is(
+ highlighters.gridHighlighters.size,
+ 1,
+ "Got expected number of grid highlighters shown."
+ );
+ is(
+ highlighters.state.grids.size,
+ 1,
+ "Got expected number of grids in the saved state"
+ );
+
+ info("Toggling OFF the CSS grid highlighter for #grid1.");
+ onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
+ onCheckboxChange = waitUntilState(
+ store,
+ state =>
+ state.grids.length == 4 &&
+ !state.grids[0].highlighted &&
+ !state.grids[0].disabled &&
+ !state.grids[1].highlighted &&
+ !state.grids[1].disabled &&
+ !state.grids[2].highlighted &&
+ !state.grids[2].disabled &&
+ !state.grids[3].highlighted &&
+ !state.grids[3].disabled
+ );
+ checkbox1.click();
+ await onHighlighterHidden;
+ await onCheckboxChange;
+
+ info(
+ "Check that the CSS grid highlighter is not shown and the saved grid state."
+ );
+ ok(!highlighters.gridHighlighters.size, "No CSS grid highlighter is shown.");
+ ok(!highlighters.state.grids.size, "No grids in the saved state");
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_grid-outline-cannot-show-outline.js b/devtools/client/inspector/grids/test/browser_grids_grid-outline-cannot-show-outline.js
new file mode 100644
index 0000000000..a2f293c44d
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-outline-cannot-show-outline.js
@@ -0,0 +1,57 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that grid outline does not show when cells are too small to be drawn and that
+// "Cannot show outline for this grid." message is displayed.
+
+const TEST_URI = `
+ <style type='text/css'>
+ #grid {
+ display: grid;
+ grid-template-columns: repeat(51, 20px);
+ grid-template-rows: repeat(51, 20px);
+ }
+ </style>
+ <div id="grid">
+ <div id="cellA">cell A</div>
+ <div id="cellB">cell B</div>
+ </div>
+`;
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+
+ const { inspector, gridInspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { highlighters, store } = inspector;
+
+ await selectNode("#grid", inspector);
+ const outline = doc.getElementById("grid-outline-container");
+ const gridList = doc.getElementById("grid-list");
+ const checkbox = gridList.children[0].querySelector("input");
+
+ info("Toggling ON the CSS grid highlighter from the layout panel.");
+ const onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ const onGridOutlineRendered = waitForDOM(doc, ".grid-outline-text", 1);
+ const onCheckboxChange = waitUntilState(
+ store,
+ state => state.grids.length == 1 && state.grids[0].highlighted
+ );
+ checkbox.click();
+ await onHighlighterShown;
+ await onCheckboxChange;
+ const elements = await onGridOutlineRendered;
+
+ const cannotShowGridOutline = elements[0];
+
+ info(
+ "Checking the grid outline is not rendered and an appropriate message is shown."
+ );
+ ok(!outline, "Outline component is not shown.");
+ ok(
+ cannotShowGridOutline,
+ "The message 'Cannot show outline for this grid' is displayed."
+ );
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_grid-outline-highlight-area.js b/devtools/client/inspector/grids/test/browser_grids_grid-outline-highlight-area.js
new file mode 100644
index 0000000000..7a93e561cc
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-outline-highlight-area.js
@@ -0,0 +1,77 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the grid area and cell are highlighted when hovering over a grid area in the
+// grid outline.
+
+const TEST_URI = `
+ <style type='text/css'>
+ #grid {
+ display: grid;
+ grid-template-areas:
+ "header"
+ "footer";
+ }
+ .top {
+ grid-area: header;
+ }
+ .bottom {
+ grid-area: footer;
+ }
+ </style>
+ <div id="grid">
+ <div id="cella" className="top">Cell A</div>
+ <div id="cellb" className="bottom">Cell B</div>
+ </div>
+`;
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+
+ const { inspector, gridInspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { store } = inspector;
+ const HIGHLIGHTER_TYPE = inspector.highlighters.TYPES.GRID;
+ const { waitForHighlighterTypeShown } = getHighlighterTestHelpers(inspector);
+
+ const gridList = doc.getElementById("grid-list");
+ const checkbox = gridList.children[0].querySelector("input");
+
+ info("Toggling ON the CSS grid highlighter from the layout panel.");
+ const onHighlighterShown = waitForHighlighterTypeShown(HIGHLIGHTER_TYPE);
+ const onGridOutlineRendered = waitForDOM(doc, "#grid-cell-group rect", 2);
+ const onCheckboxChange = waitUntilState(
+ store,
+ state => state.grids.length == 1 && state.grids[0].highlighted
+ );
+ checkbox.click();
+
+ info("Wait for checkbox to change");
+ await onCheckboxChange;
+
+ info("Wait for highlighter to be shown");
+ await onHighlighterShown;
+
+ info("Wait for outline to be rendered");
+ await onGridOutlineRendered;
+
+ info("Hovering over grid cell A in the grid outline.");
+ const onCellAHighlight = waitForHighlighterTypeShown(HIGHLIGHTER_TYPE);
+
+ synthesizeMouseOverOnGridCell(doc, 0);
+
+ const { options } = await onCellAHighlight;
+
+ info(
+ "Checking the grid highlighter options for the show grid area and cell parameters."
+ );
+ const { showGridCell, showGridArea } = options;
+ const { gridFragmentIndex, rowNumber, columnNumber } = showGridCell;
+
+ is(gridFragmentIndex, "0", "Should be the first grid fragment index.");
+ is(rowNumber, "1", "Should be the first grid row.");
+ is(columnNumber, "1", "Should be the first grid column.");
+ is(showGridArea, "header", "Grid area name should be 'header'.");
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_grid-outline-highlight-cell.js b/devtools/client/inspector/grids/test/browser_grids_grid-outline-highlight-cell.js
new file mode 100644
index 0000000000..0f5f329f9b
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-outline-highlight-cell.js
@@ -0,0 +1,65 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the grid cell is highlighted when hovering over the grid outline of a
+// grid cell.
+
+const TEST_URI = `
+ <style type='text/css'>
+ #grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid">
+ <div id="cella">Cell A</div>
+ <div id="cellb">Cell B</div>
+ </div>
+`;
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+
+ const { inspector, gridInspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { store } = inspector;
+ const HIGHLIGHTER_TYPE = inspector.highlighters.TYPES.GRID;
+ const { waitForHighlighterTypeShown } = getHighlighterTestHelpers(inspector);
+
+ const gridList = doc.getElementById("grid-list");
+ const checkbox = gridList.children[0].querySelector("input");
+
+ info("Toggling ON the CSS grid highlighter from the layout panel.");
+ const onHighlighterShown = waitForHighlighterTypeShown(HIGHLIGHTER_TYPE);
+ const onGridOutlineRendered = waitForDOM(doc, "#grid-cell-group rect", 2);
+ const onCheckboxChange = waitUntilState(
+ store,
+ state => state.grids.length == 1 && state.grids[0].highlighted
+ );
+ checkbox.click();
+
+ info("Wait for checkbox to change");
+ await onCheckboxChange;
+
+ info("Wait for highlighter to be shown");
+ await onHighlighterShown;
+
+ info("Wait for outline to be rendered");
+ await onGridOutlineRendered;
+
+ info("Hovering over grid cell A in the grid outline.");
+ const onCellAHighlight = waitForHighlighterTypeShown(HIGHLIGHTER_TYPE);
+
+ synthesizeMouseOverOnGridCell(doc, 0);
+
+ const { options } = await onCellAHighlight;
+
+ info("Checking show grid cell options are correct.");
+ const { showGridCell } = options;
+ const { gridFragmentIndex, rowNumber, columnNumber } = showGridCell;
+
+ is(gridFragmentIndex, "0", "Should be the first grid fragment index.");
+ is(rowNumber, "1", "Should be the first grid row.");
+ is(columnNumber, "1", "Should be the first grid column.");
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_grid-outline-multiple-grids.js b/devtools/client/inspector/grids/test/browser_grids_grid-outline-multiple-grids.js
new file mode 100644
index 0000000000..a65cfd7528
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-outline-multiple-grids.js
@@ -0,0 +1,76 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the grid outline is not shown when more than one grid is highlighted.
+
+const TEST_URI = `
+ <style type='text/css'>
+ .grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid1" class="grid">
+ <div class="cell1">cell1</div>
+ <div class="cell2">cell2</div>
+ </div>
+ <div id="grid2" class="grid">
+ <div class="cell1">cell1</div>
+ <div class="cell2">cell2</div>
+ </div>
+`;
+
+add_task(async function () {
+ await pushPref("devtools.gridinspector.maxHighlighters", 2);
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { inspector, gridInspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { highlighters, store } = inspector;
+
+ await selectNode("#grid1", inspector);
+ const gridList = doc.getElementById("grid-list");
+ const checkbox1 = gridList.children[0].querySelector("input");
+ const checkbox2 = gridList.children[1].querySelector("input");
+
+ info("Toggling ON the CSS grid highlighter for #grid1.");
+ let onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ const onGridOutlineRendered = waitForDOM(doc, "#grid-cell-group rect", 2);
+ let onCheckboxChange = waitUntilState(
+ store,
+ state =>
+ state.grids.length === 2 &&
+ state.grids[0].highlighted &&
+ !state.grids[1].highlighted
+ );
+ checkbox1.click();
+ await onHighlighterShown;
+ await onCheckboxChange;
+ const elements = await onGridOutlineRendered;
+
+ info("Checking the grid outline for #grid1 is shown.");
+ ok(
+ doc.getElementById("grid-outline-container"),
+ "Grid outline container is rendered."
+ );
+ is(elements.length, 2, "Grid outline is shown.");
+
+ info("Toggling ON the CSS grid highlighter for #grid2.");
+ onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ onCheckboxChange = waitUntilState(
+ store,
+ state =>
+ state.grids.length === 2 &&
+ state.grids[0].highlighted &&
+ state.grids[1].highlighted
+ );
+ checkbox2.click();
+ await onHighlighterShown;
+ await onCheckboxChange;
+
+ info("Checking the grid outline is not shown.");
+ ok(
+ !doc.getElementById("grid-outline-container"),
+ "Grid outline is not rendered."
+ );
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_grid-outline-selected-grid.js b/devtools/client/inspector/grids/test/browser_grids_grid-outline-selected-grid.js
new file mode 100644
index 0000000000..ada2a635e4
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-outline-selected-grid.js
@@ -0,0 +1,51 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the grid outline is shown when a grid container is selected.
+
+const TEST_URI = `
+ <style type='text/css'>
+ #grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid">
+ <div id="cella">Cell A</div>
+ <div id="cellb">Cell B</div>
+ <div id="cellc">Cell C</div>
+ </div>
+`;
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+
+ const { inspector, gridInspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { highlighters, store } = inspector;
+
+ const gridList = doc.getElementById("grid-list");
+ const checkbox = gridList.children[0].querySelector("input");
+
+ info("Checking the initial state of the Grid Inspector.");
+ ok(
+ !doc.getElementById("grid-outline-container"),
+ "There should be no grid outline shown."
+ );
+
+ info("Toggling ON the CSS grid highlighter from the layout panel.");
+ const onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ const onCheckboxChange = waitUntilState(
+ store,
+ state => state.grids.length == 1 && state.grids[0].highlighted
+ );
+ const onGridOutlineRendered = waitForDOM(doc, "#grid-cell-group rect", 3);
+ checkbox.click();
+ await onHighlighterShown;
+ await onCheckboxChange;
+ const elements = await onGridOutlineRendered;
+
+ info("Checking the grid outline is shown.");
+ is(elements.length, 3, "Grid outline is shown.");
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_grid-outline-updates-on-grid-change.js b/devtools/client/inspector/grids/test/browser_grids_grid-outline-updates-on-grid-change.js
new file mode 100644
index 0000000000..778217cc40
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-outline-updates-on-grid-change.js
@@ -0,0 +1,64 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the grid outline does reflect the grid in the page even after the grid has
+// changed.
+
+const TEST_URI = `
+ <style>
+ .container {
+ display: grid;
+ grid-template-columns: repeat(2, 20vw);
+ grid-auto-rows: 20px;
+ }
+ </style>
+ <div class="container">
+ <div>item 1</div>
+ <div>item 2</div>
+ </div>
+`;
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+
+ const { inspector, gridInspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { highlighters, store } = inspector;
+
+ info("Clicking on the first checkbox to highlight the grid");
+ const checkbox = doc.querySelector("#grid-list input");
+
+ const onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ const onCheckboxChange = waitUntilState(
+ store,
+ state => state.grids.length == 1 && state.grids[0].highlighted
+ );
+ const onGridOutlineRendered = waitForDOM(doc, ".grid-outline-cell", 2);
+
+ checkbox.click();
+
+ await onHighlighterShown;
+ await onCheckboxChange;
+ let elements = await onGridOutlineRendered;
+
+ info("Checking the grid outline is shown.");
+ is(elements.length, 2, "Grid outline is shown.");
+
+ info("Changing the grid in the page");
+ const onReflow = inspector.once("reflow-in-selected-target");
+ const onGridOutlineChanged = waitForDOM(doc, ".grid-outline-cell", 4);
+
+ await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
+ const div = content.document.createElement("div");
+ div.textContent = "item 3";
+ content.document.querySelector(".container").appendChild(div);
+ });
+
+ await onReflow;
+ elements = await onGridOutlineChanged;
+
+ info("Checking the grid outline is correct.");
+ is(elements.length, 4, "Grid outline was changed.");
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_grid-outline-writing-mode.js b/devtools/client/inspector/grids/test/browser_grids_grid-outline-writing-mode.js
new file mode 100644
index 0000000000..c27a8b481f
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-outline-writing-mode.js
@@ -0,0 +1,156 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the grid outline adjusts to match the container's writing mode.
+
+const TEST_URI = `
+ <style type='text/css'>
+ .grid {
+ display: grid;
+ width: 400px;
+ height: 300px;
+ }
+ .rtl {
+ direction: rtl;
+ }
+ .v-rl {
+ writing-mode: vertical-rl;
+ }
+ .v-lr {
+ writing-mode: vertical-lr;
+ }
+ .s-rl {
+ writing-mode: sideways-rl;
+ }
+ .s-lr {
+ writing-mode: sideways-lr;
+ }
+ </style>
+ <div class="grid">
+ <div id="cella">Cell A</div>
+ <div id="cellb">Cell B</div>
+ <div id="cellc">Cell C</div>
+ </div>
+ <div class="grid rtl">
+ <div id="cella">Cell A</div>
+ <div id="cellb">Cell B</div>
+ <div id="cellc">Cell C</div>
+ </div>
+ <div class="grid v-rl">
+ <div id="cella">Cell A</div>
+ <div id="cellb">Cell B</div>
+ <div id="cellc">Cell C</div>
+ </div>
+ <div class="grid v-lr">
+ <div id="cella">Cell A</div>
+ <div id="cellb">Cell B</div>
+ <div id="cellc">Cell C</div>
+ </div>
+ <div class="grid s-rl">
+ <div id="cella">Cell A</div>
+ <div id="cellb">Cell B</div>
+ <div id="cellc">Cell C</div>
+ </div>
+ <div class="grid s-lr">
+ <div id="cella">Cell A</div>
+ <div id="cellb">Cell B</div>
+ <div id="cellc">Cell C</div>
+ </div>
+`;
+
+add_task(async function () {
+ await pushPref("devtools.gridinspector.maxHighlighters", 1);
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+
+ const { inspector, gridInspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { highlighters, store } = inspector;
+
+ info("Checking the initial state of the Grid Inspector.");
+ ok(
+ !doc.getElementById("grid-outline-container"),
+ "There should be no grid outline shown."
+ );
+
+ let elements;
+
+ elements = await enableGrid(doc, highlighters, store, 0);
+ is(
+ elements[0].style.transform,
+ "matrix(1, 0, 0, 1, 0, 0)",
+ "Transform matches for horizontal-tb and ltr."
+ );
+ await disableGrid(doc, highlighters, store, 0);
+
+ elements = await enableGrid(doc, highlighters, store, 1);
+ is(
+ elements[0].style.transform,
+ "matrix(-1, 0, 0, 1, 200, 0)",
+ "Transform matches for horizontal-tb and rtl"
+ );
+ await disableGrid(doc, highlighters, store, 1);
+
+ elements = await enableGrid(doc, highlighters, store, 2);
+ is(
+ elements[0].style.transform,
+ "matrix(6.12323e-17, 1, -1, 6.12323e-17, 200, 0)",
+ "Transform matches for vertical-rl and ltr"
+ );
+ await disableGrid(doc, highlighters, store, 2);
+
+ elements = await enableGrid(doc, highlighters, store, 3);
+ is(
+ elements[0].style.transform,
+ "matrix(-6.12323e-17, 1, 1, 6.12323e-17, 0, 0)",
+ "Transform matches for vertical-lr and ltr"
+ );
+ await disableGrid(doc, highlighters, store, 3);
+
+ elements = await enableGrid(doc, highlighters, store, 4);
+ is(
+ elements[0].style.transform,
+ "matrix(6.12323e-17, 1, -1, 6.12323e-17, 200, 0)",
+ "Transform matches for sideways-rl and ltr"
+ );
+ await disableGrid(doc, highlighters, store, 4);
+
+ elements = await enableGrid(doc, highlighters, store, 5);
+ is(
+ elements[0].style.transform,
+ "matrix(6.12323e-17, -1, 1, 6.12323e-17, -9.18485e-15, 150)",
+ "Transform matches for sideways-lr and ltr"
+ );
+ await disableGrid(doc, highlighters, store, 5);
+});
+
+async function enableGrid(doc, highlighters, store, index) {
+ info(`Enabling the CSS grid highlighter for grid ${index}.`);
+ const onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ const onCheckboxChange = waitUntilState(
+ store,
+ state => state.grids.length == 6 && state.grids[index].highlighted
+ );
+ const onGridOutlineRendered = waitForDOM(doc, "#grid-cell-group");
+ const gridList = doc.getElementById("grid-list");
+ gridList.children[index].querySelector("input").click();
+ await onHighlighterShown;
+ await onCheckboxChange;
+ return onGridOutlineRendered;
+}
+
+async function disableGrid(doc, highlighters, store, index) {
+ info(`Disabling the CSS grid highlighter for grid ${index}.`);
+ const onHighlighterShown = highlighters.once("grid-highlighter-hidden");
+ const onCheckboxChange = waitUntilState(
+ store,
+ state => state.grids.length == 6 && !state.grids[index].highlighted
+ );
+ const onGridOutlineRemoved = waitForDOM(doc, "#grid-cell-group", 0);
+ const gridList = doc.getElementById("grid-list");
+ gridList.children[index].querySelector("input").click();
+ await onHighlighterShown;
+ await onCheckboxChange;
+ return onGridOutlineRemoved;
+}
diff --git a/devtools/client/inspector/grids/test/browser_grids_highlighter-setting-rules-grid-toggle.js b/devtools/client/inspector/grids/test/browser_grids_highlighter-setting-rules-grid-toggle.js
new file mode 100644
index 0000000000..c2c22b8b87
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_highlighter-setting-rules-grid-toggle.js
@@ -0,0 +1,75 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test toggling the grid highlighter in the rule view with changes in the grid
+// display setting from the layout view.
+
+const TEST_URI = `
+ <style type='text/css'>
+ #grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid">
+ <div id="cell1">cell1</div>
+ <div id="cell2">cell2</div>
+ </div>
+`;
+
+const SHOW_INFINITE_LINES_PREF = "devtools.gridinspector.showInfiniteLines";
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { inspector, gridInspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { store } = inspector;
+
+ const checkbox = doc.getElementById("grid-setting-extend-grid-lines");
+
+ ok(
+ !Services.prefs.getBoolPref(SHOW_INFINITE_LINES_PREF),
+ "'Extend grid lines infinitely' is pref off by default."
+ );
+
+ info("Toggling ON the 'Extend grid lines infinitely' setting.");
+ const onCheckboxChange = waitUntilState(
+ store,
+ state => state.highlighterSettings.showInfiniteLines
+ );
+ checkbox.click();
+ await onCheckboxChange;
+
+ info("Selecting the rule view.");
+ const ruleView = selectRuleView(inspector);
+ const highlighters = ruleView.highlighters;
+
+ await selectNode("#grid", inspector);
+
+ const container = getRuleViewProperty(ruleView, "#grid", "display").valueSpan;
+ const gridToggle = container.querySelector(".js-toggle-grid-highlighter");
+
+ info("Toggling ON the CSS grid highlighter from the rule-view.");
+ const onHighlighterShown = highlighters.once(
+ "grid-highlighter-shown",
+ (nodeFront, options) => {
+ info("Checking the grid highlighter display settings.");
+ const {
+ color,
+ showGridAreasOverlay,
+ showGridLineNumbers,
+ showInfiniteLines,
+ } = options;
+
+ is(color, "#9400FF", "CSS grid highlighter color is correct.");
+ ok(!showGridAreasOverlay, "Show grid areas overlay option is off.");
+ ok(!showGridLineNumbers, "Show grid line numbers option is off.");
+ ok(showInfiniteLines, "Show infinite lines option is on.");
+ }
+ );
+ gridToggle.click();
+ await onHighlighterShown;
+
+ Services.prefs.clearUserPref(SHOW_INFINITE_LINES_PREF);
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_highlighter-toggle-telemetry.js b/devtools/client/inspector/grids/test/browser_grids_highlighter-toggle-telemetry.js
new file mode 100644
index 0000000000..329acf3713
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_highlighter-toggle-telemetry.js
@@ -0,0 +1,63 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that the telemetry count is correct when the grid highlighter is activated from
+// the layout view.
+
+const TEST_URI = `
+ <style type='text/css'>
+ #grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid">
+ <div id="cell1">cell1</div>
+ <div id="cell2">cell2</div>
+ </div>
+`;
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ startTelemetry();
+ const { gridInspector, inspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { highlighters, store } = inspector;
+
+ await selectNode("#grid", inspector);
+ const gridList = doc.getElementById("grid-list");
+ const checkbox = gridList.children[0].querySelector("input");
+
+ info("Toggling ON the CSS grid highlighter from the layout panel.");
+ const onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ let onCheckboxChange = waitUntilState(
+ store,
+ state => state.grids.length == 1 && state.grids[0].highlighted
+ );
+ checkbox.click();
+ await onHighlighterShown;
+ await onCheckboxChange;
+
+ info("Toggling OFF the CSS grid highlighter from the layout panel.");
+ const onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
+ onCheckboxChange = waitUntilState(
+ store,
+ state => state.grids.length == 1 && !state.grids[0].highlighted
+ );
+ checkbox.click();
+ await onHighlighterHidden;
+ await onCheckboxChange;
+
+ checkResults();
+});
+
+function checkResults() {
+ checkTelemetry("devtools.grid.gridinspector.opened", "", 1, "scalar");
+ checkTelemetry(
+ "DEVTOOLS_GRID_HIGHLIGHTER_TIME_ACTIVE_SECONDS",
+ "",
+ null,
+ "hasentries"
+ );
+}
diff --git a/devtools/client/inspector/grids/test/browser_grids_number-of-css-grids-telemetry.js b/devtools/client/inspector/grids/test/browser_grids_number-of-css-grids-telemetry.js
new file mode 100644
index 0000000000..6ec6b32a63
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_number-of-css-grids-telemetry.js
@@ -0,0 +1,56 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the telemetry count for the number of CSS Grid Elements on a page navigation
+// is correct when the toolbox is opened.
+
+const TEST_URI1 = `
+ <div></div>
+`;
+
+const TEST_URI2 = `
+ <style type='text/css'>
+ #grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid">
+ <div id="cell1">cell1</div>
+ <div id="cell2">cell2</div>
+ </div>
+`;
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI1));
+
+ startTelemetry();
+
+ const { inspector } = await openLayoutView();
+ const { store } = inspector;
+
+ info("Navigate to TEST_URI2");
+
+ const onGridListUpdate = waitUntilState(
+ store,
+ state => state.grids.length == 1
+ );
+ await navigateTo(
+ "data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI2)
+ );
+ await onGridListUpdate;
+
+ checkResults();
+});
+
+function checkResults() {
+ // Check for:
+ // - 1 CSS Grid Element
+ checkTelemetry(
+ "DEVTOOLS_NUMBER_OF_CSS_GRIDS_IN_A_PAGE",
+ "",
+ { 0: 0, 1: 1, 2: 0 },
+ "array"
+ );
+}
diff --git a/devtools/client/inspector/grids/test/browser_grids_persist-color-palette.js b/devtools/client/inspector/grids/test/browser_grids_persist-color-palette.js
new file mode 100644
index 0000000000..0a4e10dfa0
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_persist-color-palette.js
@@ -0,0 +1,58 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the when a custom color has been previously set, we initialize
+// the grid with that color.
+
+const TEST_URI = `
+ <style type='text/css'>
+ #grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid">
+ <div class="cell1">cell1</div>
+ <div class="cell2">cell2</div>
+ </div>
+`;
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { inspector, gridInspector, layoutView, toolbox } =
+ await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { store } = inspector;
+ const cPicker = layoutView.swatchColorPickerTooltip;
+ const swatch = doc.querySelector(
+ "#layout-grid-container .layout-color-swatch"
+ );
+
+ info("Scrolling into view of the #grid color swatch.");
+ swatch.scrollIntoView();
+
+ info("Opening the color picker by clicking on the #grid color swatch.");
+ const onColorPickerReady = cPicker.once("ready");
+ swatch.click();
+ await onColorPickerReady;
+
+ await simulateColorPickerChange(cPicker, [51, 48, 0, 1]);
+
+ info("Closing the toolbox.");
+ await toolbox.destroy();
+ info("Open the toolbox again.");
+ await openLayoutView();
+
+ info("Check that the previously set custom color is used.");
+ is(
+ swatch.style.backgroundColor,
+ "rgb(51, 48, 0)",
+ "The color swatch's background is correct."
+ );
+ is(
+ store.getState().grids[0].color,
+ "#333000",
+ "The grid color state is correct."
+ );
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_restored-after-reload.js b/devtools/client/inspector/grids/test/browser_grids_restored-after-reload.js
new file mode 100644
index 0000000000..412bf98af9
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_restored-after-reload.js
@@ -0,0 +1,115 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the grid highlighter is re-displayed after reloading a page and the grid
+// item is highlighted.
+
+const TEST_URI = `
+ <style type='text/css'>
+ #grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid">
+ <div id="cell1">cell1</div>
+ <div id="cell2">cell2</div>
+ </div>
+`;
+
+const OTHER_URI = `
+ <style type='text/css'>
+ #grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid">
+ <div id="cell1">cell1</div>
+ <div id="cell2">cell2</div>
+ <div id="cell3">cell3</div>
+ </div>
+`;
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { gridInspector, inspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { highlighters, store } = inspector;
+ const HIGHLIGHTER_TYPE = inspector.highlighters.TYPES.GRID;
+ const { waitForHighlighterTypeRestored, waitForHighlighterTypeDiscarded } =
+ getHighlighterTestHelpers(inspector);
+
+ await selectNode("#grid", inspector);
+ const gridList = doc.getElementById("grid-list");
+ const checkbox = gridList.children[0].querySelector("input");
+
+ info("Toggling ON the CSS grid highlighter from the layout panel.");
+ const onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ const onCheckboxChange = waitUntilState(
+ store,
+ state => state.grids.length == 1 && state.grids[0].highlighted
+ );
+ checkbox.click();
+ await onHighlighterShown;
+ await onCheckboxChange;
+
+ info(
+ "Check that the CSS grid highlighter is created and the saved grid state."
+ );
+ is(highlighters.gridHighlighters.size, 1, "CSS grid highlighter is shown.");
+ is(
+ highlighters.state.grids.size,
+ 1,
+ "There's a saved grid state to be restored."
+ );
+
+ info(
+ "Reload the page, expect the highlighter to be displayed once again and " +
+ "grid is checked"
+ );
+ const onRestored = waitForHighlighterTypeRestored(HIGHLIGHTER_TYPE);
+ let onGridListRestored = waitUntilState(
+ store,
+ state => state.grids.length == 1 && state.grids[0].highlighted
+ );
+
+ const onReloaded = inspector.once("reloaded");
+ await reloadBrowser();
+ info("Wait for inspector to be reloaded after page reload");
+ await onReloaded;
+
+ await onRestored;
+ await onGridListRestored;
+
+ info(
+ "Check that the grid highlighter can be displayed after reloading the page"
+ );
+ is(highlighters.gridHighlighters.size, 1, "CSS grid highlighter is shown.");
+ is(
+ highlighters.state.grids.size,
+ 1,
+ "The saved grid state has the correct number of saved states."
+ );
+
+ info(
+ "Navigate to another URL, and check that the highlighter is hidden and " +
+ "grid is unchecked"
+ );
+ const otherUri =
+ "data:text/html;charset=utf-8," + encodeURIComponent(OTHER_URI);
+ const onDiscarded = waitForHighlighterTypeDiscarded(HIGHLIGHTER_TYPE);
+ onGridListRestored = waitUntilState(
+ store,
+ state => state.grids.length == 1 && !state.grids[0].highlighted
+ );
+ await navigateTo(otherUri);
+ await onDiscarded;
+ await onGridListRestored;
+
+ info(
+ "Check that the grid highlighter is hidden after navigating to a different page"
+ );
+ ok(!highlighters.gridHighlighters.size, "CSS grid highlighter is hidden.");
+ ok(!highlighters.state.grids.size, "No grids to be restored on page reload.");
+});
diff --git a/devtools/client/inspector/grids/test/browser_grids_restored-multiple-grids-after-reload.js b/devtools/client/inspector/grids/test/browser_grids_restored-multiple-grids-after-reload.js
new file mode 100644
index 0000000000..81ac7619ff
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_restored-multiple-grids-after-reload.js
@@ -0,0 +1,156 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the grid highlighters are re-displayed after reloading a page and multiple
+// grids are highlighted.
+
+const TEST_URI = `
+ <style type='text/css'>
+ .grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid1" class="grid">
+ <div class="cell1">cell1</div>
+ <div class="cell2">cell2</div>
+ </div>
+ <div id="grid2" class="grid">
+ <div class="cell1">cell1</div>
+ <div class="cell2">cell2</div>
+ </div>
+ <div id="grid3" class="grid">
+ <div class="cell1">cell1</div>
+ <div class="cell2">cell2</div>
+ </div>
+ <div id="grid4" class="grid">
+ <div class="cell1">cell1</div>
+ <div class="cell2">cell2</div>
+ </div>
+`;
+
+add_task(async function () {
+ await pushPref("devtools.gridinspector.maxHighlighters", 3);
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { gridInspector, inspector } = await openLayoutView();
+ const { document: doc } = gridInspector;
+ const { highlighters, store } = inspector;
+
+ await selectNode("#grid1", inspector);
+ const gridList = doc.getElementById("grid-list");
+ const checkbox1 = gridList.children[0].querySelector("input");
+ const checkbox2 = gridList.children[1].querySelector("input");
+ const checkbox3 = gridList.children[2].querySelector("input");
+
+ info("Toggling ON the CSS grid highlighter for #grid1.");
+ let onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ let onCheckboxChange = waitUntilState(
+ store,
+ state =>
+ state.grids.length == 4 &&
+ state.grids[0].highlighted &&
+ !state.grids[0].disabled &&
+ !state.grids[1].highlighted &&
+ !state.grids[1].disabled &&
+ !state.grids[2].highlighted &&
+ !state.grids[2].disabled &&
+ !state.grids[3].highlighted &&
+ !state.grids[3].disabled
+ );
+ checkbox1.click();
+ await onHighlighterShown;
+ await onCheckboxChange;
+
+ info("Toggling ON the CSS grid highlighter for #grid2.");
+ onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ onCheckboxChange = waitUntilState(
+ store,
+ state =>
+ state.grids.length == 4 &&
+ state.grids[0].highlighted &&
+ !state.grids[0].disabled &&
+ state.grids[1].highlighted &&
+ !state.grids[1].disabled &&
+ !state.grids[2].highlighted &&
+ !state.grids[2].disabled &&
+ !state.grids[3].highlighted &&
+ !state.grids[3].disabled
+ );
+ checkbox2.click();
+ await onHighlighterShown;
+ await onCheckboxChange;
+
+ info("Toggling ON the CSS grid highlighter for #grid3.");
+ onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ onCheckboxChange = waitUntilState(
+ store,
+ state =>
+ state.grids.length == 4 &&
+ state.grids[0].highlighted &&
+ !state.grids[0].disabled &&
+ state.grids[1].highlighted &&
+ !state.grids[1].disabled &&
+ state.grids[2].highlighted &&
+ !state.grids[2].disabled &&
+ !state.grids[3].highlighted &&
+ state.grids[3].disabled
+ );
+ checkbox3.click();
+ await onHighlighterShown;
+ await onCheckboxChange;
+
+ info(
+ "Check that the CSS grid highlighters are created and the saved grid state."
+ );
+ is(
+ highlighters.gridHighlighters.size,
+ 3,
+ "Got expected number of grid highlighters shown."
+ );
+ is(
+ highlighters.state.grids.size,
+ 3,
+ "Got expected number of grids in the saved state"
+ );
+
+ info(
+ "Reload the page, expect the highlighters to be displayed once again and " +
+ "grids are checked"
+ );
+ const onStateRestored = waitForNEvents(
+ highlighters,
+ "highlighter-restored",
+ 3
+ );
+ const onGridListRestored = waitUntilState(
+ store,
+ state =>
+ state.grids.length == 4 &&
+ state.grids[0].highlighted &&
+ !state.grids[0].disabled &&
+ state.grids[1].highlighted &&
+ !state.grids[1].disabled &&
+ state.grids[2].highlighted &&
+ !state.grids[2].disabled &&
+ !state.grids[3].highlighted &&
+ state.grids[3].disabled
+ );
+ await reloadBrowser();
+ await onStateRestored;
+ await onGridListRestored;
+
+ info(
+ "Check that the grid highlighters can be displayed after reloading the page"
+ );
+ is(
+ highlighters.gridHighlighters.size,
+ 3,
+ "Got expected number of grid highlighters shown."
+ );
+ is(
+ highlighters.state.grids.size,
+ 3,
+ "Got expected number of grids in the saved state"
+ );
+});
diff --git a/devtools/client/inspector/grids/test/doc_iframe_reloaded.html b/devtools/client/inspector/grids/test/doc_iframe_reloaded.html
new file mode 100644
index 0000000000..a452dd4d8c
--- /dev/null
+++ b/devtools/client/inspector/grids/test/doc_iframe_reloaded.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<iframe srcdoc="<style>.grid{display:grid;}</style><div class='grid'><span>a</span><span>b</span></div>"></iframe>
+<script>
+"use strict";
+function reloadIFrame() { // eslint-disable-line no-unused-vars
+ const iFrame = document.querySelector("iframe");
+ iFrame.setAttribute("srcdoc", iFrame.getAttribute("srcdoc"));
+}
+</script>
diff --git a/devtools/client/inspector/grids/test/doc_subgrid.html b/devtools/client/inspector/grids/test/doc_subgrid.html
new file mode 100644
index 0000000000..fef13bcc5c
--- /dev/null
+++ b/devtools/client/inspector/grids/test/doc_subgrid.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8" />
+ <style>
+ .container {
+ display: grid;
+ grid-gap: 5px;
+ grid-template: auto / 1fr 3fr 1fr;
+ background: lightyellow;
+ }
+
+ .subgrid {
+ display: grid;
+ grid: subgrid / subgrid;
+ }
+
+ header, aside, section, footer {
+ background: lightblue;
+ font-family: sans-serif;
+ font-size: 3em;
+ }
+
+ header, footer {
+ grid-column: span 3;
+ }
+
+ main {
+ grid-column: span 3;
+ }
+
+ .aside1 {
+ grid-column: 1;
+ }
+
+ .aside2 {
+ grid-column: 3;
+ }
+
+ section {
+ grid-column: 2;
+ }
+ </style>
+</head>
+<body>
+ <div class="container">
+ <header class="subgrid">Header</header>
+ <main class="subgrid">
+ <aside class="aside1 subgrid">aside</aside>
+ <section>section</section>
+ <aside class="aside2 subgrid">aside2</aside>
+ </main>
+ <footer>footer</footer>
+ </div>
+</body>
+</html>
diff --git a/devtools/client/inspector/grids/test/head.js b/devtools/client/inspector/grids/test/head.js
new file mode 100644
index 0000000000..5b54004abc
--- /dev/null
+++ b/devtools/client/inspector/grids/test/head.js
@@ -0,0 +1,40 @@
+/* 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
+);
+
+const asyncStorage = require("resource://devtools/shared/async-storage.js");
+
+Services.prefs.setIntPref("devtools.toolbox.footer.height", 350);
+registerCleanupFunction(async function () {
+ Services.prefs.clearUserPref("devtools.toolbox.footer.height");
+ await asyncStorage.removeItem("gridInspectorHostColors");
+});
+
+/**
+ * Simulate a mouseover event on a grid cell currently rendered in the grid
+ * inspector.
+ *
+ * @param {Document} doc
+ * The owner document for the grid inspector.
+ * @param {Number} gridCellIndex
+ * The index (0-based) of the grid cell that should be hovered.
+ */
+function synthesizeMouseOverOnGridCell(doc, gridCellIndex = 0) {
+ // Make sure to retrieve the current live grid item before attempting to
+ // interact with it using mouse APIs.
+ const gridCell = doc.querySelectorAll("#grid-cell-group rect")[gridCellIndex];
+
+ EventUtils.synthesizeMouseAtCenter(
+ gridCell,
+ { type: "mouseover" },
+ doc.defaultView
+ );
+}
diff --git a/devtools/client/inspector/grids/test/xpcshell/.eslintrc.js b/devtools/client/inspector/grids/test/xpcshell/.eslintrc.js
new file mode 100644
index 0000000000..86bd54c245
--- /dev/null
+++ b/devtools/client/inspector/grids/test/xpcshell/.eslintrc.js
@@ -0,0 +1,6 @@
+"use strict";
+
+module.exports = {
+ // Extend from the common devtools xpcshell eslintrc config.
+ extends: "../../../../../.eslintrc.xpcshell.js",
+};
diff --git a/devtools/client/inspector/grids/test/xpcshell/head.js b/devtools/client/inspector/grids/test/xpcshell/head.js
new file mode 100644
index 0000000000..733c0400da
--- /dev/null
+++ b/devtools/client/inspector/grids/test/xpcshell/head.js
@@ -0,0 +1,10 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* eslint no-unused-vars: [2, {"vars": "local"}] */
+
+const { require } = ChromeUtils.importESModule(
+ "resource://devtools/shared/loader/Loader.sys.mjs"
+);
diff --git a/devtools/client/inspector/grids/test/xpcshell/test_compare_fragments_geometry.js b/devtools/client/inspector/grids/test/xpcshell/test_compare_fragments_geometry.js
new file mode 100644
index 0000000000..57f617a3ec
--- /dev/null
+++ b/devtools/client/inspector/grids/test/xpcshell/test_compare_fragments_geometry.js
@@ -0,0 +1,129 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const {
+ compareFragmentsGeometry,
+} = require("resource://devtools/client/inspector/grids/utils/utils.js");
+
+const TESTS = [
+ {
+ desc: "No fragments",
+ grids: [[], []],
+ expected: true,
+ },
+ {
+ desc: "Different number of fragments",
+ grids: [
+ [{}, {}, {}],
+ [{}, {}],
+ ],
+ expected: false,
+ },
+ {
+ desc: "Different number of columns",
+ grids: [
+ [{ cols: { lines: [{}, {}] }, rows: { lines: [] } }],
+ [{ cols: { lines: [{}] }, rows: { lines: [] } }],
+ ],
+ expected: false,
+ },
+ {
+ desc: "Different number of rows",
+ grids: [
+ [{ cols: { lines: [{}, {}] }, rows: { lines: [{}] } }],
+ [{ cols: { lines: [{}, {}] }, rows: { lines: [{}, {}] } }],
+ ],
+ expected: false,
+ },
+ {
+ desc: "Different number of rows and columns",
+ grids: [
+ [{ cols: { lines: [{}] }, rows: { lines: [{}] } }],
+ [{ cols: { lines: [{}, {}] }, rows: { lines: [{}, {}] } }],
+ ],
+ expected: false,
+ },
+ {
+ desc: "Different column sizes",
+ grids: [
+ [
+ {
+ cols: { lines: [{ start: 0 }, { start: 500 }] },
+ rows: { lines: [] },
+ },
+ ],
+ [
+ {
+ cols: { lines: [{ start: 0 }, { start: 1000 }] },
+ rows: { lines: [] },
+ },
+ ],
+ ],
+ expected: false,
+ },
+ {
+ desc: "Different row sizes",
+ grids: [
+ [
+ {
+ cols: { lines: [{ start: 0 }, { start: 500 }] },
+ rows: { lines: [{ start: -100 }] },
+ },
+ ],
+ [
+ {
+ cols: { lines: [{ start: 0 }, { start: 500 }] },
+ rows: { lines: [{ start: 0 }] },
+ },
+ ],
+ ],
+ expected: false,
+ },
+ {
+ desc: "Different row and column sizes",
+ grids: [
+ [
+ {
+ cols: { lines: [{ start: 0 }, { start: 500 }] },
+ rows: { lines: [{ start: -100 }] },
+ },
+ ],
+ [
+ {
+ cols: { lines: [{ start: 0 }, { start: 505 }] },
+ rows: { lines: [{ start: 0 }] },
+ },
+ ],
+ ],
+ expected: false,
+ },
+ {
+ desc: "Complete structure, same fragments",
+ grids: [
+ [
+ {
+ cols: { lines: [{ start: 0 }, { start: 100.3 }, { start: 200.6 }] },
+ rows: { lines: [{ start: 0 }, { start: 1000 }, { start: 2000 }] },
+ },
+ ],
+ [
+ {
+ cols: { lines: [{ start: 0 }, { start: 100.3 }, { start: 200.6 }] },
+ rows: { lines: [{ start: 0 }, { start: 1000 }, { start: 2000 }] },
+ },
+ ],
+ ],
+ expected: true,
+ },
+];
+
+function run_test() {
+ for (const { desc, grids, expected } of TESTS) {
+ if (desc) {
+ info(desc);
+ }
+ equal(compareFragmentsGeometry(grids[0], grids[1]), expected);
+ }
+}
diff --git a/devtools/client/inspector/grids/test/xpcshell/xpcshell.toml b/devtools/client/inspector/grids/test/xpcshell/xpcshell.toml
new file mode 100644
index 0000000000..83e821f9cd
--- /dev/null
+++ b/devtools/client/inspector/grids/test/xpcshell/xpcshell.toml
@@ -0,0 +1,6 @@
+[DEFAULT]
+tags = "devtools"
+firefox-appdir = "browser"
+head = "head.js"
+
+["test_compare_fragments_geometry.js"]