Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit b71ac3d

Browse files
committed
Bug 1540601 - Ensuring that TreeView filtering works with keyboard. r=nchevobbe
Differential Revision: https://phabricator.services.mozilla.com/D25552 --HG-- extra : moz-landing-system : lando
1 parent 369ab26 commit b71ac3d

3 files changed

Lines changed: 150 additions & 1 deletion

File tree

devtools/client/shared/components/test/mochitest/chrome.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,4 @@ support-files =
3939
[test_tree_15.html]
4040
[test_tree_16.html]
4141
[test_tree-view_01.html]
42+
[test_tree-view_02.html]
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
<!-- This Source Code Form is subject to the terms of the Mozilla Public
2+
- License, v. 2.0. If a copy of the MPL was not distributed with this
3+
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
4+
<!DOCTYPE HTML>
5+
<html>
6+
<!--
7+
Test that TreeView component filtering works with keyboard.
8+
-->
9+
<head>
10+
<meta charset="utf-8">
11+
<title>TreeView component filtering keyboard test</title>
12+
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
13+
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
14+
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
15+
<link rel="stylesheet" href="chrome://devtools/skin/light-theme.css" type="text/css">
16+
<link rel="stylesheet" href="resource://devtools/client/shared/components/tree/TreeView.css" type="text/css">
17+
<style>
18+
.treeRow.hide {
19+
display: none;
20+
}
21+
</style>
22+
</head>
23+
<body>
24+
<pre id="test">
25+
<script src="head.js" type="application/javascript"></script>
26+
<script type="application/javascript">
27+
28+
"use strict";
29+
30+
window.onload = function() {
31+
try {
32+
const React = browserRequire("devtools/client/shared/vendor/react");
33+
const {
34+
Simulate,
35+
findRenderedDOMComponentWithClass,
36+
scryRenderedDOMComponentsWithClass,
37+
} = browserRequire("devtools/client/shared/vendor/react-dom-test-utils");
38+
const TreeView =
39+
browserRequire("devtools/client/shared/components/tree/TreeView");
40+
41+
function testKeyboardInteraction(tree, treeViewEl, rows) {
42+
// Expected tree when filtered (C is filtered)
43+
//
44+
// A
45+
// |-- B
46+
// `-- D
47+
is(window.getComputedStyle(rows[1]).getPropertyValue("display"), "none",
48+
"Row C must be hidden by default.");
49+
50+
const tests = [{
51+
name: "Selected row must be set to the first row on initial focus. " +
52+
"Keyboard focus must be set on TreeView's conatiner.",
53+
action: () => {
54+
Simulate.click(rows[0]);
55+
},
56+
activeElement: treeViewEl,
57+
state: { selected: "/B" },
58+
}, {
59+
name: "Selecting next row must skip hidden row on ArrowDown.",
60+
event: {
61+
type: "keyDown",
62+
el: treeViewEl,
63+
options: { key: "ArrowDown" },
64+
},
65+
state: { selected: "/D" },
66+
}, {
67+
name: "Selecting previous row must be skip hidden row on ArrowUp.",
68+
event: {
69+
type: "keyDown",
70+
el: treeViewEl,
71+
options: { key: "ArrowUp" },
72+
},
73+
state: { selected: "/B" },
74+
}];
75+
76+
for (const test of tests) {
77+
const { action, condition, event, state, name } = test;
78+
79+
info(name);
80+
if (event) {
81+
const { type, options, el } = event;
82+
Simulate[type](el, options);
83+
} else if (action) {
84+
action();
85+
}
86+
87+
for (let key in state) {
88+
is(tree.state[key], state[key], `${key} state is correct.`);
89+
}
90+
}
91+
}
92+
93+
info("Test hiding rows via decorator.");
94+
const props = {
95+
...TEST_TREE_VIEW_INTERFACE,
96+
decorator: {
97+
getRowClass: ({ label }) => {
98+
if (label === "C") {
99+
return ["hide"];
100+
}
101+
}
102+
}
103+
};
104+
let treeView = React.createElement(TreeView, props);
105+
let tree = ReactDOM.render(treeView, document.body);
106+
let treeViewEl = findRenderedDOMComponentWithClass(tree, "treeTable");
107+
let rows = scryRenderedDOMComponentsWithClass(tree, "treeRow");
108+
109+
testKeyboardInteraction(tree, treeViewEl, rows);
110+
111+
// Remove TreeView component.
112+
ReactDOM.unmountComponentAtNode(document.body);
113+
114+
info("Test hiding rows via onFilter.");
115+
props.decorator = null;
116+
props.onFilter = ({ label }) => {
117+
console.log(`onFILTER ${label !== "C"}`)
118+
return label !== "C";
119+
};
120+
treeView = React.createElement(TreeView, props);
121+
tree = ReactDOM.render(treeView, document.body);
122+
treeViewEl = findRenderedDOMComponentWithClass(tree, "treeTable");
123+
rows = scryRenderedDOMComponentsWithClass(tree, "treeRow");
124+
125+
testKeyboardInteraction(tree, treeViewEl, rows);
126+
} catch (e) {
127+
ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
128+
} finally {
129+
SimpleTest.finish();
130+
}
131+
};
132+
</script>
133+
</pre>
134+
</body>
135+
</html>

devtools/client/shared/components/tree/TreeView.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,20 @@ define(function(require, exports, module) {
546546
member: member,
547547
columns: this.state.columns,
548548
id: member.path,
549-
ref: row => row && this.rows.push(row),
549+
ref: row => {
550+
if (!row) {
551+
return;
552+
}
553+
554+
const rowEl = findDOMNode(row);
555+
if (!rowEl || !rowEl.offsetParent) {
556+
// offsetParent returns null when the element has style.display
557+
// set to none (done by TreeView filtering).
558+
return;
559+
}
560+
561+
this.rows.push(row);
562+
},
550563
onClick: this.onClickRow.bind(this, member.path),
551564
onContextMenu: this.onContextMenu.bind(this, member),
552565
});

0 commit comments

Comments
 (0)