diff --git a/packages/flutter/lib/src/widgets/widget_inspector.dart b/packages/flutter/lib/src/widgets/widget_inspector.dart index 34ad78bc35..c7ff524e42 100644 --- a/packages/flutter/lib/src/widgets/widget_inspector.dart +++ b/packages/flutter/lib/src/widgets/widget_inspector.dart @@ -1758,9 +1758,25 @@ mixin WidgetInspectorService { } List _getChildrenSummaryTree(String? diagnosticsNodeId, String groupName) { - final DiagnosticsNode? node = toObject(diagnosticsNodeId) as DiagnosticsNode?; + final Object? theObject = toObject(diagnosticsNodeId); final InspectorSerializationDelegate delegate = InspectorSerializationDelegate(groupName: groupName, summaryTree: true, service: this); - return _nodesToJson(node == null ? const [] : _getChildrenFiltered(node, delegate), delegate, parent: node); + + // TODO(polina-c): remove this, when DevTools stops sending DiagnosticsNode. + // https://github.com/flutter/devtools/issues/3951 + if (theObject is DiagnosticsNode) { + return _nodesToJson(_getChildrenFiltered(theObject, delegate), delegate, parent: theObject); + } + + if (theObject is Diagnosticable) { + final DiagnosticsNode node = theObject.toDiagnosticsNode(); + return _nodesToJson(_getChildrenFiltered(node, delegate), delegate, parent: node); + } + + if (theObject == null) { + return []; + } + + throw StateError('Unexpected object type ${theObject.runtimeType}'); } /// Returns a JSON representation of the children of the [DiagnosticsNode] diff --git a/packages/flutter/test/widgets/widget_inspector_test.dart b/packages/flutter/test/widgets/widget_inspector_test.dart index aa64ca4789..90dc05a8dd 100644 --- a/packages/flutter/test/widgets/widget_inspector_test.dart +++ b/packages/flutter/test/widgets/widget_inspector_test.dart @@ -2288,7 +2288,9 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { expect(nestedRelatedProperty, isNot(contains('children'))); }); - testWidgets('ext.flutter.inspector.getRootWidgetSummaryTree', (WidgetTester tester) async { + testWidgets('ext.flutter.inspector.getRootWidgetSummaryTree on $DiagnosticsNode', (WidgetTester tester) async { + // TODO(polina-c): delete this test once getChildrenSummaryTree stops accepting DiagnosticsNode. + // https://github.com/flutter/devtools/issues/3951 const String group = 'test-group'; await tester.pumpWidget( @@ -2397,6 +2399,115 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { expect(childJson['chidlren'], isNull); }, skip: !WidgetInspectorService.instance.isWidgetCreationTracked()); // [intended] Test requires --track-widget-creation flag. + testWidgets('ext.flutter.inspector.getRootWidgetSummaryTree on $Diagnosticable', (WidgetTester tester) async { + const String group = 'test-group'; + + await tester.pumpWidget( + const Directionality( + textDirection: TextDirection.ltr, + child: Stack( + children: [ + Text('a', textDirection: TextDirection.ltr), + Text('b', textDirection: TextDirection.ltr), + Text('c', textDirection: TextDirection.ltr), + ], + ), + ), + ); + final Element elementA = find.text('a').evaluate().first; + + service.disposeAllGroups(); + service.resetPubRootDirectories(); + service.setSelection(elementA, 'my-group'); + final Map jsonA = (await service.testExtension( + WidgetInspectorServiceExtensions.getSelectedWidget.name, + {'objectGroup': 'my-group'}, + ))! as Map; + + service.resetPubRootDirectories(); + Map rootJson = (await service.testExtension( + WidgetInspectorServiceExtensions.getRootWidgetSummaryTree.name, + {'objectGroup': group}, + ))! as Map; + // We haven't yet properly specified which directories are summary tree + // directories so we get an empty tree other than the root that is always + // included. + final Object? rootWidget = service.toObject(rootJson['valueId']! as String); + expect(rootWidget, equals(WidgetsBinding.instance.rootElement)); + List childrenJson = rootJson['children']! as List; + // There are no summary tree children. + expect(childrenJson.length, equals(0)); + + final Map creationLocation = jsonA['creationLocation']! as Map; + expect(creationLocation, isNotNull); + final String testFile = creationLocation['file']! as String; + expect(testFile, endsWith('widget_inspector_test.dart')); + final List segments = Uri.parse(testFile).pathSegments; + // Strip a couple subdirectories away to generate a plausible pub root + // directory. + final String pubRootTest = '/${segments.take(segments.length - 2).join('/')}'; + service.resetPubRootDirectories(); + await service.testExtension( + WidgetInspectorServiceExtensions.addPubRootDirectories.name, + {'arg0': pubRootTest}, + ); + + rootJson = (await service.testExtension( + WidgetInspectorServiceExtensions.getRootWidgetSummaryTree.name, + {'objectGroup': group}, + ))! as Map; + childrenJson = rootJson['children']! as List; + // The tree of nodes returned contains all widgets created directly by the + // test. + childrenJson = rootJson['children']! as List; + expect(childrenJson.length, equals(1)); + + List alternateChildrenJson = (await service.testExtension( + WidgetInspectorServiceExtensions.getChildrenSummaryTree.name, + {'arg': rootJson['valueId']! as String, 'objectGroup': group}, + ))! as List; + expect(alternateChildrenJson.length, equals(1)); + Map childJson = childrenJson[0]! as Map; + Map alternateChildJson = alternateChildrenJson[0]! as Map; + expect(childJson['description'], startsWith('Directionality')); + expect(alternateChildJson['description'], startsWith('Directionality')); + expect(alternateChildJson['valueId'], equals(childJson['valueId'])); + + childrenJson = childJson['children']! as List; + alternateChildrenJson = (await service.testExtension( + WidgetInspectorServiceExtensions.getChildrenSummaryTree.name, + {'arg': childJson['valueId']! as String, 'objectGroup': group}, + ))! as List; + expect(alternateChildrenJson.length, equals(1)); + expect(childrenJson.length, equals(1)); + alternateChildJson = alternateChildrenJson[0]! as Map; + childJson = childrenJson[0]! as Map; + expect(childJson['description'], startsWith('Stack')); + expect(alternateChildJson['description'], startsWith('Stack')); + expect(alternateChildJson['valueId'], equals(childJson['valueId'])); + childrenJson = childJson['children']! as List; + + childrenJson = childJson['children']! as List; + alternateChildrenJson = (await service.testExtension( + WidgetInspectorServiceExtensions.getChildrenSummaryTree.name, + {'arg': childJson['valueId']! as String, 'objectGroup': group}, + ))! as List; + expect(alternateChildrenJson.length, equals(3)); + expect(childrenJson.length, equals(3)); + alternateChildJson = alternateChildrenJson[2]! as Map; + childJson = childrenJson[2]! as Map; + expect(childJson['description'], startsWith('Text')); + expect(alternateChildJson['description'], startsWith('Text')); + expect(alternateChildJson['valueId'], equals(childJson['valueId'])); + alternateChildrenJson = (await service.testExtension( + WidgetInspectorServiceExtensions.getChildrenSummaryTree.name, + {'arg': childJson['valueId']! as String, 'objectGroup': group}, + ))! as List; + expect(alternateChildrenJson.length , equals(0)); + // Tests are failing when this typo is fixed. + expect(childJson['chidlren'], isNull); + }, skip: !WidgetInspectorService.instance.isWidgetCreationTracked()); // [intended] Test requires --track-widget-creation flag. + testWidgets('ext.flutter.inspector.getRootWidgetSummaryTreeWithPreviews', (WidgetTester tester) async { const String group = 'test-group';