Skip to content

Commit be048b4

Browse files
committed
Notify Flutter inspector when navigating widget tree with keyboard
1 parent 6046c5b commit be048b4

2 files changed

Lines changed: 124 additions & 2 deletions

File tree

packages/devtools_app/lib/src/screens/inspector/inspector_tree_controller.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ class InspectorTreeController extends DisposableController
399399
_numRows - 1,
400400
),
401401
)?.node;
402-
setSelectedNode(nodeToSelect);
402+
setSelectedNode(nodeToSelect, notifyFlutterInspector: true);
403403
return true;
404404
},
405405
);

packages/devtools_app/test/screens/inspector/inspector_tree_test.dart

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd.
44

55
import 'package:devtools_app/devtools_app.dart';
6-
76
import 'package:devtools_app_shared/ui.dart';
87
import 'package:devtools_app_shared/utils.dart';
98
import 'package:devtools_test/devtools_test.dart';
109
import 'package:devtools_test/helpers.dart';
1110
import 'package:flutter/material.dart';
11+
import 'package:flutter/services.dart';
1212
import 'package:flutter_test/flutter_test.dart' hide Fake;
1313
import 'package:mockito/mockito.dart';
1414

@@ -136,4 +136,126 @@ void main() {
136136
expect(find.richText('Text: "Multiline text content"'), findsOneWidget);
137137
});
138138
});
139+
140+
group('InspectorTreeController keyboard navigation', () {
141+
InspectorTreeController buildTreeController({
142+
required void Function({bool notifyFlutterInspector}) onSelectionChange,
143+
}) {
144+
return InspectorTreeController()
145+
..config = InspectorTreeConfig(
146+
onNodeAdded: (_, _) {},
147+
onClientActiveChange: (_) {},
148+
onSelectionChange: onSelectionChange,
149+
)
150+
..root = (InspectorTreeNode()
151+
..appendChild(InspectorTreeNode())
152+
..appendChild(InspectorTreeNode()));
153+
}
154+
155+
testWidgets(
156+
'navigateDown triggers onSelectionChange with notifyFlutterInspector true',
157+
(WidgetTester tester) async {
158+
bool? capturedNotify;
159+
final treeController = buildTreeController(
160+
onSelectionChange: ({bool notifyFlutterInspector = false}) {
161+
capturedNotify = notifyFlutterInspector;
162+
},
163+
);
164+
165+
await pumpInspectorTree(tester, treeController: treeController);
166+
167+
treeController.navigateDown();
168+
await tester.pump();
169+
170+
expect(capturedNotify, isTrue);
171+
},
172+
);
173+
174+
testWidgets(
175+
'navigateUp triggers onSelectionChange with notifyFlutterInspector true',
176+
(WidgetTester tester) async {
177+
bool? capturedNotify;
178+
final treeController = buildTreeController(
179+
onSelectionChange: ({bool notifyFlutterInspector = false}) {
180+
capturedNotify = notifyFlutterInspector;
181+
},
182+
);
183+
184+
await pumpInspectorTree(tester, treeController: treeController);
185+
186+
// Move selection to the second row so navigateUp has somewhere to go.
187+
treeController.navigateDown();
188+
await tester.pump();
189+
treeController.navigateDown();
190+
await tester.pump();
191+
192+
capturedNotify = null;
193+
treeController.navigateUp();
194+
await tester.pump();
195+
196+
expect(capturedNotify, isTrue);
197+
},
198+
);
199+
});
200+
201+
group('InspectorTree keyboard events', () {
202+
InspectorTreeController buildTreeController({
203+
required void Function({bool notifyFlutterInspector}) onSelectionChange,
204+
}) {
205+
return InspectorTreeController()
206+
..config = InspectorTreeConfig(
207+
onNodeAdded: (_, _) {},
208+
onClientActiveChange: (_) {},
209+
onSelectionChange: onSelectionChange,
210+
)
211+
..root = (InspectorTreeNode()
212+
..appendChild(InspectorTreeNode())
213+
..appendChild(InspectorTreeNode()));
214+
}
215+
216+
testWidgets(
217+
'arrowDown key triggers onSelectionChange with notifyFlutterInspector true',
218+
(WidgetTester tester) async {
219+
bool? capturedNotify;
220+
final treeController = buildTreeController(
221+
onSelectionChange: ({bool notifyFlutterInspector = false}) {
222+
capturedNotify = notifyFlutterInspector;
223+
},
224+
);
225+
226+
await pumpInspectorTree(tester, treeController: treeController);
227+
228+
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
229+
await tester.pump();
230+
231+
expect(capturedNotify, isTrue);
232+
},
233+
);
234+
235+
testWidgets(
236+
'arrowUp key triggers onSelectionChange with notifyFlutterInspector true',
237+
(WidgetTester tester) async {
238+
bool? capturedNotify;
239+
final treeController = buildTreeController(
240+
onSelectionChange: ({bool notifyFlutterInspector = false}) {
241+
capturedNotify = notifyFlutterInspector;
242+
},
243+
);
244+
245+
await pumpInspectorTree(tester, treeController: treeController);
246+
247+
// Move selection to the second row first.
248+
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
249+
await tester.pump();
250+
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
251+
await tester.pump();
252+
253+
capturedNotify = null;
254+
await tester.sendKeyEvent(LogicalKeyboardKey.arrowUp);
255+
await tester.pump();
256+
257+
expect(capturedNotify, isTrue);
258+
},
259+
);
260+
});
139261
}

0 commit comments

Comments
 (0)