Unverified Commit 7214cb28 authored by Polina Cherkasova's avatar Polina Cherkasova Committed by GitHub

Accept Diagnosticable as input in inspector API. (#128962)

parent 5ab5d82a
...@@ -1762,7 +1762,7 @@ mixin WidgetInspectorService { ...@@ -1762,7 +1762,7 @@ mixin WidgetInspectorService {
DiagnosticsNode? _idToDiagnosticsNode(String? diagnosticsOrDiagnosticableId) { DiagnosticsNode? _idToDiagnosticsNode(String? diagnosticsOrDiagnosticableId) {
// TODO(polina-c): start always assuming Diagnosticable, when DevTools stops sending DiagnosticsNode to // TODO(polina-c): start always assuming Diagnosticable, when DevTools stops sending DiagnosticsNode to
// getChildrenSummaryTree and getProperties. // APIs that invoke this method.
// https://github.com/flutter/devtools/issues/3951 // https://github.com/flutter/devtools/issues/3951
final Object? theObject = toObject(diagnosticsOrDiagnosticableId); final Object? theObject = toObject(diagnosticsOrDiagnosticableId);
if (theObject is DiagnosticsNode) { if (theObject is DiagnosticsNode) {
...@@ -1788,17 +1788,17 @@ mixin WidgetInspectorService { ...@@ -1788,17 +1788,17 @@ mixin WidgetInspectorService {
} }
/// Returns a JSON representation of the children of the [DiagnosticsNode] /// Returns a JSON representation of the children of the [DiagnosticsNode]
/// object that `diagnosticsNodeId` references providing information needed /// object that [diagnosticsOrDiagnosticableId] references providing information needed
/// for the details subtree view. /// for the details subtree view.
/// ///
/// The details subtree shows properties inline and includes all children /// The details subtree shows properties inline and includes all children
/// rather than a filtered set of important children. /// rather than a filtered set of important children.
String getChildrenDetailsSubtree(String diagnosticsNodeId, String groupName) { String getChildrenDetailsSubtree(String diagnosticsOrDiagnosticableId, String groupName) {
return _safeJsonEncode(_getChildrenDetailsSubtree(diagnosticsNodeId, groupName)); return _safeJsonEncode(_getChildrenDetailsSubtree(diagnosticsOrDiagnosticableId, groupName));
} }
List<Object> _getChildrenDetailsSubtree(String? diagnosticsNodeId, String groupName) { List<Object> _getChildrenDetailsSubtree(String? diagnosticsOrDiagnosticableId, String groupName) {
final DiagnosticsNode? node = toObject(diagnosticsNodeId) as DiagnosticsNode?; final DiagnosticsNode? node = _idToDiagnosticsNode(diagnosticsOrDiagnosticableId);
// With this value of minDepth we only expand one extra level of important nodes. // With this value of minDepth we only expand one extra level of important nodes.
final InspectorSerializationDelegate delegate = InspectorSerializationDelegate(groupName: groupName, includeProperties: true, service: this); final InspectorSerializationDelegate delegate = InspectorSerializationDelegate(groupName: groupName, includeProperties: true, service: this);
return _nodesToJson(node == null ? const <DiagnosticsNode>[] : _getChildrenFiltered(node, delegate), delegate, parent: node); return _nodesToJson(node == null ? const <DiagnosticsNode>[] : _getChildrenFiltered(node, delegate), delegate, parent: node);
...@@ -1910,19 +1910,19 @@ mixin WidgetInspectorService { ...@@ -1910,19 +1910,19 @@ mixin WidgetInspectorService {
/// * [getChildrenDetailsSubtree], a method to get children of a node /// * [getChildrenDetailsSubtree], a method to get children of a node
/// in the details subtree. /// in the details subtree.
String getDetailsSubtree( String getDetailsSubtree(
String id, String diagnosticsOrDiagnosticableId,
String groupName, { String groupName, {
int subtreeDepth = 2, int subtreeDepth = 2,
}) { }) {
return _safeJsonEncode(_getDetailsSubtree( id, groupName, subtreeDepth)); return _safeJsonEncode(_getDetailsSubtree(diagnosticsOrDiagnosticableId, groupName, subtreeDepth));
} }
Map<String, Object?>? _getDetailsSubtree( Map<String, Object?>? _getDetailsSubtree(
String? id, String? diagnosticsOrDiagnosticableId,
String? groupName, String? groupName,
int subtreeDepth, int subtreeDepth,
) { ) {
final DiagnosticsNode? root = toObject(id) as DiagnosticsNode?; final DiagnosticsNode? root = _idToDiagnosticsNode(diagnosticsOrDiagnosticableId);
if (root == null) { if (root == null) {
return null; return null;
} }
...@@ -1942,6 +1942,8 @@ mixin WidgetInspectorService { ...@@ -1942,6 +1942,8 @@ mixin WidgetInspectorService {
/// If the currently selected [Element] is identical to the [Element] /// If the currently selected [Element] is identical to the [Element]
/// referenced by `previousSelectionId` then the previous [DiagnosticsNode] is /// referenced by `previousSelectionId` then the previous [DiagnosticsNode] is
/// reused. /// reused.
// TODO(polina-c): delete [previousSelectionId] when it is not used in DevTools
// https://github.com/flutter/devtools/issues/3951
@protected @protected
String getSelectedWidget(String? previousSelectionId, String groupName) { String getSelectedWidget(String? previousSelectionId, String groupName) {
return _safeJsonEncode(_getSelectedWidget(previousSelectionId, groupName)); return _safeJsonEncode(_getSelectedWidget(previousSelectionId, groupName));
...@@ -2020,18 +2022,18 @@ mixin WidgetInspectorService { ...@@ -2020,18 +2022,18 @@ mixin WidgetInspectorService {
Future<Map<String, Object?>> _getLayoutExplorerNode( Future<Map<String, Object?>> _getLayoutExplorerNode(
Map<String, String> parameters, Map<String, String> parameters,
) { ) {
final String? id = parameters['id']; final String? diagnosticsOrDiagnosticableId = parameters['id'];
final int subtreeDepth = int.parse(parameters['subtreeDepth']!); final int subtreeDepth = int.parse(parameters['subtreeDepth']!);
final String? groupName = parameters['groupName']; final String? groupName = parameters['groupName'];
Map<String, dynamic>? result = <String, dynamic>{}; Map<String, dynamic>? result = <String, dynamic>{};
final Object? root = toObject(id); final DiagnosticsNode? root = _idToDiagnosticsNode(diagnosticsOrDiagnosticableId);
if (root == null) { if (root == null) {
return Future<Map<String, dynamic>>.value(<String, dynamic>{ return Future<Map<String, dynamic>>.value(<String, dynamic>{
'result': result, 'result': result,
}); });
} }
result = _nodeToJson( result = _nodeToJson(
root as DiagnosticsNode, root,
InspectorSerializationDelegate( InspectorSerializationDelegate(
groupName: groupName, groupName: groupName,
summaryTree: true, summaryTree: true,
...@@ -2232,6 +2234,8 @@ mixin WidgetInspectorService { ...@@ -2232,6 +2234,8 @@ mixin WidgetInspectorService {
/// If the currently selected [Element] is identical to the [Element] /// If the currently selected [Element] is identical to the [Element]
/// referenced by `previousSelectionId` then the previous [DiagnosticsNode] is /// referenced by `previousSelectionId` then the previous [DiagnosticsNode] is
/// reused. /// reused.
// TODO(polina-c): delete paramater [previousSelectionId] when it is not used in DevTools
// https://github.com/flutter/devtools/issues/3951
String getSelectedSummaryWidget(String previousSelectionId, String groupName) { String getSelectedSummaryWidget(String previousSelectionId, String groupName) {
return _safeJsonEncode(_getSelectedSummaryWidget(previousSelectionId, groupName)); return _safeJsonEncode(_getSelectedSummaryWidget(previousSelectionId, groupName));
} }
......
...@@ -900,6 +900,8 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { ...@@ -900,6 +900,8 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService {
}); });
test('WidgetInspectorService getProperties for $DiagnosticsNode', () { test('WidgetInspectorService getProperties for $DiagnosticsNode', () {
// TODO(polina-c): delete this test once getChildrenDetailsSubtree stops accepting DiagnosticsNode.
// https://github.com/flutter/devtools/issues/3951
final DiagnosticsNode diagnostic = const Text('a', textDirection: TextDirection.ltr).toDiagnosticsNode(); final DiagnosticsNode diagnostic = const Text('a', textDirection: TextDirection.ltr).toDiagnosticsNode();
const String group = 'group'; const String group = 'group';
service.disposeAllGroups(); service.disposeAllGroups();
...@@ -2124,6 +2126,8 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { ...@@ -2124,6 +2126,8 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService {
}); });
test('ext.flutter.inspector.getProperties for $DiagnosticsNode', () async { test('ext.flutter.inspector.getProperties for $DiagnosticsNode', () async {
// TODO(polina-c): delete this test once getChildrenDetailsSubtree stops accepting DiagnosticsNode.
// https://github.com/flutter/devtools/issues/3951
final DiagnosticsNode diagnostic = const Text('a', textDirection: TextDirection.ltr).toDiagnosticsNode(); final DiagnosticsNode diagnostic = const Text('a', textDirection: TextDirection.ltr).toDiagnosticsNode();
const String group = 'group'; const String group = 'group';
final String id = service.toId(diagnostic, group)!; final String id = service.toId(diagnostic, group)!;
...@@ -5090,7 +5094,9 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { ...@@ -5090,7 +5094,9 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService {
expect(box2.localToGlobal(Offset.zero), equals(position2)); expect(box2.localToGlobal(Offset.zero), equals(position2));
}); });
testWidgets('getChildrenDetailsSubtree', (WidgetTester tester) async { testWidgets('getChildrenDetailsSubtree with $DiagnosticsNode', (WidgetTester tester) async {
// TODO(polina-c): delete this test once getChildrenDetailsSubtree stops accepting DiagnosticsNode.
// https://github.com/flutter/devtools/issues/3951
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
title: 'Hello, World', title: 'Hello, World',
...@@ -5150,6 +5156,66 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { ...@@ -5150,6 +5156,66 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService {
expect(appBars.single, isNot(contains('children'))); expect(appBars.single, isNot(contains('children')));
}, skip: !WidgetInspectorService.instance.isWidgetCreationTracked()); // [intended] Test requires --track-widget-creation flag. }, skip: !WidgetInspectorService.instance.isWidgetCreationTracked()); // [intended] Test requires --track-widget-creation flag.
testWidgets('getChildrenDetailsSubtree with $Diagnosticable', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
title: 'Hello, World',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: const Text('Hello, World'),
),
body: const Center(
child: Text('Hello, World!'),
),
),
),
);
service.setSelection(find.text('Hello, World!').evaluate().first, 'my-group');
// Figure out the pubRootDirectory
final Map<String, Object?> jsonObject = (await service.testExtension(
WidgetInspectorServiceExtensions.getSelectedWidget.name,
<String, String>{'objectGroup': 'my-group'},
))! as Map<String, Object?>;
final Map<String, Object?> creationLocation = jsonObject['creationLocation']! as Map<String, Object?>;
expect(creationLocation, isNotNull);
final String file = creationLocation['file']! as String;
expect(file, endsWith('widget_inspector_test.dart'));
final List<String> segments = Uri.parse(file).pathSegments;
// Strip a couple subdirectories away to generate a plausible pub rootdirectory.
final String pubRootTest = '/${segments.take(segments.length - 2).join('/')}';
service.resetPubRootDirectories();
service.addPubRootDirectories(<String>[pubRootTest]);
final String summary = service.getRootWidgetSummaryTree('foo1');
// ignore: avoid_dynamic_calls
final List<Object?> childrenOfRoot = json.decode(summary)['children'] as List<Object?>;
final List<Object?> childrenOfMaterialApp = (childrenOfRoot.first! as Map<String, Object?>)['children']! as List<Object?>;
final Map<String, Object?> scaffold = childrenOfMaterialApp.first! as Map<String, Object?>;
expect(scaffold['description'], 'Scaffold');
final String objectId = scaffold['valueId']! as String;
final String details = service.getDetailsSubtree(objectId, 'foo2');
// ignore: avoid_dynamic_calls
final List<Object?> detailedChildren = json.decode(details)['children'] as List<Object?>;
final List<Map<String, Object?>> appBars = <Map<String, Object?>>[];
void visitChildren(List<Object?> children) {
for (final Map<String, Object?> child in children.cast<Map<String, Object?>>()) {
if (child['description'] == 'AppBar') {
appBars.add(child);
}
if (child.containsKey('children')) {
visitChildren(child['children']! as List<Object?>);
}
}
}
visitChildren(detailedChildren);
expect(appBars.single, isNot(contains('children')));
}, skip: !WidgetInspectorService.instance.isWidgetCreationTracked()); // [intended] Test requires --track-widget-creation flag.
testWidgets('InspectorSerializationDelegate addAdditionalPropertiesCallback', (WidgetTester tester) async { testWidgets('InspectorSerializationDelegate addAdditionalPropertiesCallback', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment