Allow requesting a reduced widget tree with getRootWidgetTree service extension (#157309)

This commit is contained in:
Elliott Brooks 2024-10-23 12:30:55 -07:00 committed by GitHub
parent 99ddbc308f
commit 802bae0111
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 380 additions and 45 deletions

View File

@ -1605,12 +1605,29 @@ abstract class DiagnosticsNode {
/// by this method and interactive tree views in the Flutter IntelliJ /// by this method and interactive tree views in the Flutter IntelliJ
/// plugin. /// plugin.
@mustCallSuper @mustCallSuper
Map<String, Object?> toJsonMap(DiagnosticsSerializationDelegate delegate) { Map<String, Object?> toJsonMap(
DiagnosticsSerializationDelegate delegate, {
bool fullDetails = true,
}) {
Map<String, Object?> result = <String, Object?>{}; Map<String, Object?> result = <String, Object?>{};
assert(() { assert(() {
final bool hasChildren = getChildren().isNotEmpty; final bool hasChildren = getChildren().isNotEmpty;
result = <String, Object?>{ final Map<String, Object?> essentialDetails = <String, Object?>{
'description': toDescription(), 'description': toDescription(),
'shouldIndent': style != DiagnosticsTreeStyle.flat &&
style != DiagnosticsTreeStyle.error,
...delegate.additionalNodeProperties(this, fullDetails: fullDetails),
if (delegate.subtreeDepth > 0)
'children': toJsonList(
delegate.filterChildren(getChildren(), this),
this,
delegate,
fullDetails: fullDetails,
),
};
result = !fullDetails ? essentialDetails : <String, Object?>{
...essentialDetails,
'type': runtimeType.toString(), 'type': runtimeType.toString(),
if (name != null) if (name != null)
'name': name, 'name': name,
@ -1634,18 +1651,12 @@ abstract class DiagnosticsNode {
'allowWrap': allowWrap, 'allowWrap': allowWrap,
if (allowNameWrap) if (allowNameWrap)
'allowNameWrap': allowNameWrap, 'allowNameWrap': allowNameWrap,
...delegate.additionalNodeProperties(this),
if (delegate.includeProperties) if (delegate.includeProperties)
'properties': toJsonList( 'properties': toJsonList(
delegate.filterProperties(getProperties(), this), delegate.filterProperties(getProperties(), this),
this, this,
delegate, delegate,
), fullDetails: fullDetails,
if (delegate.subtreeDepth > 0)
'children': toJsonList(
delegate.filterChildren(getChildren(), this),
this,
delegate,
), ),
}; };
return true; return true;
@ -1661,8 +1672,9 @@ abstract class DiagnosticsNode {
static List<Map<String, Object?>> toJsonList( static List<Map<String, Object?>> toJsonList(
List<DiagnosticsNode>? nodes, List<DiagnosticsNode>? nodes,
DiagnosticsNode? parent, DiagnosticsNode? parent,
DiagnosticsSerializationDelegate delegate, DiagnosticsSerializationDelegate delegate, {
) { bool fullDetails = true,
}) {
bool truncated = false; bool truncated = false;
if (nodes == null) { if (nodes == null) {
return const <Map<String, Object?>>[]; return const <Map<String, Object?>>[];
@ -1674,7 +1686,10 @@ abstract class DiagnosticsNode {
truncated = true; truncated = true;
} }
final List<Map<String, Object?>> json = nodes.map<Map<String, Object?>>((DiagnosticsNode node) { final List<Map<String, Object?>> json = nodes.map<Map<String, Object?>>((DiagnosticsNode node) {
return node.toJsonMap(delegate.delegateForNode(node)); return node.toJsonMap(
delegate.delegateForNode(node),
fullDetails: fullDetails,
);
}).toList(); }).toList();
if (truncated) { if (truncated) {
json.last['truncated'] = true; json.last['truncated'] = true;
@ -1857,8 +1872,17 @@ class StringProperty extends DiagnosticsProperty<String> {
final bool quoted; final bool quoted;
@override @override
Map<String, Object?> toJsonMap(DiagnosticsSerializationDelegate delegate) { Map<String, Object?> toJsonMap(
final Map<String, Object?> json = super.toJsonMap(delegate); DiagnosticsSerializationDelegate delegate, {
bool fullDetails = true,
}) {
final Map<String, Object?> json = super.toJsonMap(
delegate,
fullDetails: fullDetails,
);
if (!fullDetails) {
return json;
}
json['quoted'] = quoted; json['quoted'] = quoted;
return json; return json;
} }
@ -1913,8 +1937,18 @@ abstract class _NumProperty<T extends num> extends DiagnosticsProperty<T> {
}) : super.lazy(); }) : super.lazy();
@override @override
Map<String, Object?> toJsonMap(DiagnosticsSerializationDelegate delegate) { Map<String, Object?> toJsonMap(
final Map<String, Object?> json = super.toJsonMap(delegate); DiagnosticsSerializationDelegate delegate, {
bool fullDetails = true,
}) {
final Map<String, Object?> json = super.toJsonMap(
delegate,
fullDetails: fullDetails,
);
if (!fullDetails) {
return json;
}
if (unit != null) { if (unit != null) {
json['unit'] = unit; json['unit'] = unit;
} }
@ -2097,8 +2131,17 @@ class FlagProperty extends DiagnosticsProperty<bool> {
); );
@override @override
Map<String, Object?> toJsonMap(DiagnosticsSerializationDelegate delegate) { Map<String, Object?> toJsonMap(
final Map<String, Object?> json = super.toJsonMap(delegate); DiagnosticsSerializationDelegate delegate, {
bool fullDetails = true,
}) {
final Map<String, Object?> json = super.toJsonMap(
delegate,
fullDetails: fullDetails,
);
if (!fullDetails) {
return json;
}
if (ifTrue != null) { if (ifTrue != null) {
json['ifTrue'] = ifTrue; json['ifTrue'] = ifTrue;
} }
@ -2219,8 +2262,17 @@ class IterableProperty<T> extends DiagnosticsProperty<Iterable<T>> {
} }
@override @override
Map<String, Object?> toJsonMap(DiagnosticsSerializationDelegate delegate) { Map<String, Object?> toJsonMap(
final Map<String, Object?> json = super.toJsonMap(delegate); DiagnosticsSerializationDelegate delegate, {
bool fullDetails = true,
}) {
final Map<String, Object?> json = super.toJsonMap(
delegate,
fullDetails: fullDetails,
);
if (!fullDetails) {
return json;
}
if (value != null) { if (value != null) {
json['values'] = value!.map<String>((T value) => value.toString()).toList(); json['values'] = value!.map<String>((T value) => value.toString()).toList();
} }
@ -2357,8 +2409,17 @@ class ObjectFlagProperty<T> extends DiagnosticsProperty<T> {
} }
@override @override
Map<String, Object?> toJsonMap(DiagnosticsSerializationDelegate delegate) { Map<String, Object?> toJsonMap(
final Map<String, Object?> json = super.toJsonMap(delegate); DiagnosticsSerializationDelegate delegate, {
bool fullDetails = true,
}) {
final Map<String, Object?> json = super.toJsonMap(
delegate,
fullDetails: fullDetails,
);
if (!fullDetails) {
return json;
}
if (ifPresent != null) { if (ifPresent != null) {
json['ifPresent'] = ifPresent; json['ifPresent'] = ifPresent;
} }
@ -2435,8 +2496,17 @@ class FlagsSummary<T> extends DiagnosticsProperty<Map<String, T?>> {
} }
@override @override
Map<String, Object?> toJsonMap(DiagnosticsSerializationDelegate delegate) { Map<String, Object?> toJsonMap(
final Map<String, Object?> json = super.toJsonMap(delegate); DiagnosticsSerializationDelegate delegate, {
bool fullDetails = true,
}) {
final Map<String, Object?> json = super.toJsonMap(
delegate,
fullDetails: fullDetails,
);
if (!fullDetails) {
return json;
}
if (value.isNotEmpty) { if (value.isNotEmpty) {
json['values'] = _formattedValues().toList(); json['values'] = _formattedValues().toList();
} }
@ -2555,7 +2625,10 @@ class DiagnosticsProperty<T> extends DiagnosticsNode {
final bool allowNameWrap; final bool allowNameWrap;
@override @override
Map<String, Object?> toJsonMap(DiagnosticsSerializationDelegate delegate) { Map<String, Object?> toJsonMap(
DiagnosticsSerializationDelegate delegate, {
bool fullDetails = true,
}) {
final T? v = value; final T? v = value;
List<Map<String, Object?>>? properties; List<Map<String, Object?>>? properties;
if (delegate.expandPropertyValues && delegate.includeProperties && v is Diagnosticable && getProperties().isEmpty) { if (delegate.expandPropertyValues && delegate.includeProperties && v is Diagnosticable && getProperties().isEmpty) {
@ -2565,9 +2638,16 @@ class DiagnosticsProperty<T> extends DiagnosticsNode {
delegate.filterProperties(v.toDiagnosticsNode().getProperties(), this), delegate.filterProperties(v.toDiagnosticsNode().getProperties(), this),
this, this,
delegate, delegate,
fullDetails: fullDetails,
); );
} }
final Map<String, Object?> json = super.toJsonMap(delegate); final Map<String, Object?> json = super.toJsonMap(
delegate,
fullDetails: fullDetails,
);
if (!fullDetails) {
return json;
}
if (properties != null) { if (properties != null) {
json['properties'] = properties; json['properties'] = properties;
} }
@ -3503,7 +3583,10 @@ abstract class DiagnosticsSerializationDelegate {
/// ///
/// This method is called for every [DiagnosticsNode] that's included in /// This method is called for every [DiagnosticsNode] that's included in
/// the serialization. /// the serialization.
Map<String, Object?> additionalNodeProperties(DiagnosticsNode node); Map<String, Object?> additionalNodeProperties(
DiagnosticsNode node, {
bool fullDetails = true,
});
/// Filters the list of [DiagnosticsNode]s that will be included as children /// Filters the list of [DiagnosticsNode]s that will be included as children
/// for the given `owner` node. /// for the given `owner` node.
@ -3595,7 +3678,10 @@ class _DefaultDiagnosticsSerializationDelegate implements DiagnosticsSerializati
}); });
@override @override
Map<String, Object?> additionalNodeProperties(DiagnosticsNode node) { Map<String, Object?> additionalNodeProperties(
DiagnosticsNode node, {
bool fullDetails = true,
}) {
return const <String, Object?>{}; return const <String, Object?>{};
} }

View File

@ -495,8 +495,17 @@ class ColorProperty extends DiagnosticsProperty<Color> {
}); });
@override @override
Map<String, Object?> toJsonMap(DiagnosticsSerializationDelegate delegate) { Map<String, Object?> toJsonMap(
final Map<String, Object?> json = super.toJsonMap(delegate); DiagnosticsSerializationDelegate delegate, {
bool fullDetails = true,
}) {
final Map<String, Object?> json = super.toJsonMap(
delegate,
fullDetails: fullDetails,
);
if (!fullDetails) {
return json;
}
if (value != null) { if (value != null) {
json['valueProperties'] = <String, Object>{ json['valueProperties'] = <String, Object>{
'red': value!.red, 'red': value!.red,

View File

@ -5379,13 +5379,18 @@ class _ElementDiagnosticableTreeNode extends DiagnosticableTreeNode {
final bool stateful; final bool stateful;
@override @override
Map<String, Object?> toJsonMap(DiagnosticsSerializationDelegate delegate) { Map<String, Object?> toJsonMap(
final Map<String, Object?> json = super.toJsonMap(delegate); DiagnosticsSerializationDelegate delegate, {
bool fullDetails = true,
}) {
final Map<String, Object?> json = super.toJsonMap(delegate, fullDetails: fullDetails,);
final Element element = value as Element; final Element element = value as Element;
if (!element.debugIsDefunct) { if (!element.debugIsDefunct) {
json['widgetRuntimeType'] = element.widget.runtimeType.toString(); json['widgetRuntimeType'] = element.widget.runtimeType.toString();
} }
json['stateful'] = stateful; if (fullDetails) {
json['stateful'] = stateful;
}
return json; return json;
} }
} }

View File

@ -121,8 +121,17 @@ class IconDataProperty extends DiagnosticsProperty<IconData> {
}); });
@override @override
Map<String, Object?> toJsonMap(DiagnosticsSerializationDelegate delegate) { Map<String, Object?> toJsonMap(
final Map<String, Object?> json = super.toJsonMap(delegate); DiagnosticsSerializationDelegate delegate, {
bool fullDetails = true,
}) {
final Map<String, Object?> json = super.toJsonMap(
delegate,
fullDetails: fullDetails,
);
if (!fullDetails) {
return json;
}
if (value != null) { if (value != null) {
json['valueProperties'] = <String, Object>{ json['valueProperties'] = <String, Object>{
'codePoint': value!.codePoint, 'codePoint': value!.codePoint,

View File

@ -1729,9 +1729,11 @@ mixin WidgetInspectorService {
Map<String, Object?>? _nodeToJson( Map<String, Object?>? _nodeToJson(
DiagnosticsNode? node, DiagnosticsNode? node,
InspectorSerializationDelegate delegate, InspectorSerializationDelegate delegate, {
bool fullDetails = true,
}
) { ) {
return node?.toJsonMap(delegate); return node?.toJsonMap(delegate, fullDetails: fullDetails);
} }
bool _isValueCreatedByLocalProject(Object? value) { bool _isValueCreatedByLocalProject(Object? value) {
@ -1801,8 +1803,14 @@ mixin WidgetInspectorService {
List<DiagnosticsNode> nodes, List<DiagnosticsNode> nodes,
InspectorSerializationDelegate delegate, { InspectorSerializationDelegate delegate, {
required DiagnosticsNode? parent, required DiagnosticsNode? parent,
bool fullDetails = true,
}) { }) {
return DiagnosticsNode.toJsonList(nodes, parent, delegate); return DiagnosticsNode.toJsonList(
nodes,
parent,
delegate,
fullDetails: fullDetails,
);
} }
/// Returns a JSON representation of the properties of the [DiagnosticsNode] /// Returns a JSON representation of the properties of the [DiagnosticsNode]
@ -1976,11 +1984,14 @@ mixin WidgetInspectorService {
final String groupName = parameters['groupName']!; final String groupName = parameters['groupName']!;
final bool isSummaryTree = parameters['isSummaryTree'] == 'true'; final bool isSummaryTree = parameters['isSummaryTree'] == 'true';
final bool withPreviews = parameters['withPreviews'] == 'true'; final bool withPreviews = parameters['withPreviews'] == 'true';
// If the "fullDetails" parameter is not provided, default to true.
final bool fullDetails = parameters['fullDetails'] != 'false';
final Map<String, Object?>? result = _getRootWidgetTreeImpl( final Map<String, Object?>? result = _getRootWidgetTreeImpl(
groupName: groupName, groupName: groupName,
isSummaryTree: isSummaryTree, isSummaryTree: isSummaryTree,
withPreviews: withPreviews, withPreviews: withPreviews,
fullDetails: fullDetails,
); );
return Future<Map<String, dynamic>>.value(<String, dynamic>{ return Future<Map<String, dynamic>>.value(<String, dynamic>{
@ -1992,6 +2003,7 @@ mixin WidgetInspectorService {
required String groupName, required String groupName,
required bool isSummaryTree, required bool isSummaryTree,
required bool withPreviews, required bool withPreviews,
bool fullDetails = true,
Map<String, Object>? Function( Map<String, Object>? Function(
DiagnosticsNode, InspectorSerializationDelegate)? DiagnosticsNode, InspectorSerializationDelegate)?
addAdditionalPropertiesCallback, addAdditionalPropertiesCallback,
@ -2032,6 +2044,7 @@ mixin WidgetInspectorService {
? combinedAddAdditionalPropertiesCallback ? combinedAddAdditionalPropertiesCallback
: null, : null,
), ),
fullDetails: fullDetails,
); );
} }
@ -3788,19 +3801,24 @@ class InspectorSerializationDelegate implements DiagnosticsSerializationDelegate
bool get _interactive => groupName != null; bool get _interactive => groupName != null;
@override @override
Map<String, Object?> additionalNodeProperties(DiagnosticsNode node) { Map<String, Object?> additionalNodeProperties(
DiagnosticsNode node, {
bool fullDetails = true,
}) {
final Map<String, Object?> result = <String, Object?>{}; final Map<String, Object?> result = <String, Object?>{};
final Object? value = node.value; final Object? value = node.value;
if (summaryTree && fullDetails) {
result['summaryTree'] = true;
}
if (_interactive) { if (_interactive) {
result['valueId'] = service.toId(value, groupName!); result['valueId'] = service.toId(value, groupName!);
} }
if (summaryTree) {
result['summaryTree'] = true;
}
final _Location? creationLocation = _getCreationLocation(value); final _Location? creationLocation = _getCreationLocation(value);
if (creationLocation != null) { if (creationLocation != null) {
result['locationId'] = _toLocationId(creationLocation); if (fullDetails) {
result['creationLocation'] = creationLocation.toJsonMap(); result['locationId'] = _toLocationId(creationLocation);
result['creationLocation'] = creationLocation.toJsonMap();
}
if (service._isLocalCreationLocation(creationLocation.file)) { if (service._isLocalCreationLocation(creationLocation.file)) {
_nodesCreatedByLocalProject.add(node); _nodesCreatedByLocalProject.add(node);
result['createdByLocalProject'] = true; result['createdByLocalProject'] = true;

View File

@ -24,6 +24,16 @@ void main() {
}); });
group('Serialization', () { group('Serialization', () {
const List<String> essentialDiagnosticKeys = <String>[
'description',
'shouldIndent',
];
const List<String> detailedDiagnosticKeys = <String>[
'type',
'hasChildren',
'allowWrap',
];
final TestTree testTree = TestTree( final TestTree testTree = TestTree(
properties: <DiagnosticsNode>[ properties: <DiagnosticsNode>[
StringProperty('stringProperty1', 'value1', quoted: false), StringProperty('stringProperty1', 'value1', quoted: false),
@ -70,6 +80,46 @@ void main() {
final Map<String, Object?> result = testTree.toDiagnosticsNode().toJsonMap(const DiagnosticsSerializationDelegate()); final Map<String, Object?> result = testTree.toDiagnosticsNode().toJsonMap(const DiagnosticsSerializationDelegate());
expect(result.containsKey('properties'), isFalse); expect(result.containsKey('properties'), isFalse);
expect(result.containsKey('children'), isFalse); expect(result.containsKey('children'), isFalse);
for (final String keyName in essentialDiagnosticKeys) {
expect(
result.containsKey(keyName),
isTrue,
reason: '$keyName is included.',
);
}
for (final String keyName in detailedDiagnosticKeys) {
expect(
result.containsKey(keyName),
isTrue,
reason: '$keyName is included.',
);
}
});
test('without full details', () {
final Map<String, Object?> result = testTree
.toDiagnosticsNode()
.toJsonMap(
const DiagnosticsSerializationDelegate(), fullDetails: false
);
expect(result.containsKey('properties'), isFalse);
expect(result.containsKey('children'), isFalse);
for (final String keyName in essentialDiagnosticKeys) {
expect(
result.containsKey(keyName),
isTrue,
reason: '$keyName is included.',
);
}
for (final String keyName in detailedDiagnosticKeys) {
expect(
result.containsKey(keyName),
isFalse,
reason: '$keyName is not included.',
);
}
}); });
test('subtreeDepth 1', () { test('subtreeDepth 1', () {
@ -279,7 +329,10 @@ class TestDiagnosticsSerializationDelegate implements DiagnosticsSerializationDe
final NodeDelegator? nodeDelegator; final NodeDelegator? nodeDelegator;
@override @override
Map<String, Object> additionalNodeProperties(DiagnosticsNode node) { Map<String, Object> additionalNodeProperties(
DiagnosticsNode node, {
bool fullDetails = true,
}) {
return additionalNodePropertiesMap; return additionalNodePropertiesMap;
} }

View File

@ -1982,6 +1982,14 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService {
return childJson['createdByLocalProject'] == true; return childJson['createdByLocalProject'] == true;
} }
/// Returns whether the child is missing the "type" field.
///
/// This should always be true for nodes in the widget tree without
/// full details.
bool isMissingType(Map<String, Object?> childJson) {
return childJson['type'] == null;
}
/// Returns whether the child has a description matching [description]. /// Returns whether the child has a description matching [description].
bool hasDescription( bool hasDescription(
Map<String, Object?> childJson, { Map<String, Object?> childJson, {
@ -2278,6 +2286,79 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService {
}, },
))! as Map<String, Object?>; ))! as Map<String, Object?>;
expect(
allChildrenSatisfyCondition(rootJson,
condition: isMissingType,
),
isFalse,
);
expect(
allChildrenSatisfyCondition(rootJson,
condition: wasCreatedByLocalProject,
),
isFalse,
);
expect(
oneChildSatisfiesCondition(rootJson, condition: (Map<String, Object?> child) {
return hasDescription(child, description: 'Text') &&
wasCreatedByLocalProject(child) &&
!hasTextPreview(child, preview: 'a');
},
),
isTrue,
);
expect(
oneChildSatisfiesCondition(rootJson, condition: (Map<String, Object?> child) {
return hasDescription(child, description: 'Text') &&
wasCreatedByLocalProject(child) &&
!hasTextPreview(child, preview: 'b');
},
),
isTrue,
);
expect(
oneChildSatisfiesCondition(rootJson, condition: (Map<String, Object?> child) {
return hasDescription(child, description: 'Text') &&
wasCreatedByLocalProject(child) &&
!hasTextPreview(child, preview: 'c');
},
),
isTrue,
);
});
testWidgets(
'tree without full details using ext.flutter.inspector.getRootWidgetTree',
(WidgetTester tester) async {
const String group = 'test-group';
await pumpWidgetTreeWithABC(tester);
final Element elementA = findElementABC('a');
final Map<String, dynamic> jsonA =
await selectedWidgetResponseForElement(elementA);
final Map<String, Object?> creationLocation =
verifyAndReturnCreationLocation(jsonA);
final String testFile = verifyAndReturnTestFile(creationLocation);
addPubRootDirectoryFor(testFile);
final Map<String, Object?> rootJson = (await service.testExtension(
WidgetInspectorServiceExtensions.getRootWidgetTree.name,
<String, String>{
'groupName': group,
'isSummaryTree': 'false',
'withPreviews': 'false',
'fullDetails': 'false',
},
))! as Map<String, Object?>;
expect(
allChildrenSatisfyCondition(rootJson,
condition: isMissingType,
),
isTrue,
);
expect( expect(
allChildrenSatisfyCondition(rootJson, allChildrenSatisfyCondition(rootJson,
condition: wasCreatedByLocalProject, condition: wasCreatedByLocalProject,
@ -2337,6 +2418,79 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService {
}, },
))! as Map<String, Object?>; ))! as Map<String, Object?>;
expect(
allChildrenSatisfyCondition(rootJson,
condition: isMissingType,
),
isFalse,
);
expect(
allChildrenSatisfyCondition(rootJson,
condition: wasCreatedByLocalProject,
),
isFalse,
);
expect(
oneChildSatisfiesCondition(rootJson, condition: (Map<String, Object?> child) {
return hasDescription(child, description: 'Text') &&
wasCreatedByLocalProject(child) &&
hasTextPreview(child, preview: 'a');
},
),
isTrue,
);
expect(
oneChildSatisfiesCondition(rootJson, condition: (Map<String, Object?> child) {
return hasDescription(child, description: 'Text') &&
wasCreatedByLocalProject(child) &&
hasTextPreview(child, preview: 'b');
},
),
isTrue,
);
expect(
oneChildSatisfiesCondition(rootJson, condition: (Map<String, Object?> child) {
return hasDescription(child, description: 'Text') &&
wasCreatedByLocalProject(child) &&
hasTextPreview(child, preview: 'c');
},
),
isTrue,
);
});
testWidgets(
'tree without full details and with previews using ext.flutter.inspector.getRootWidgetTree',
(WidgetTester tester) async {
const String group = 'test-group';
await pumpWidgetTreeWithABC(tester);
final Element elementA = findElementABC('a');
final Map<String, dynamic> jsonA =
await selectedWidgetResponseForElement(elementA);
final Map<String, Object?> creationLocation =
verifyAndReturnCreationLocation(jsonA);
final String testFile = verifyAndReturnTestFile(creationLocation);
addPubRootDirectoryFor(testFile);
final Map<String, Object?> rootJson = (await service.testExtension(
WidgetInspectorServiceExtensions.getRootWidgetTree.name,
<String, String>{
'groupName': group,
'isSummaryTree': 'false',
'withPreviews': 'true',
'fullDetails': 'false',
},
))! as Map<String, Object?>;
expect(
allChildrenSatisfyCondition(rootJson,
condition: isMissingType,
),
isTrue,
);
expect( expect(
allChildrenSatisfyCondition(rootJson, allChildrenSatisfyCondition(rootJson,
condition: wasCreatedByLocalProject, condition: wasCreatedByLocalProject,
@ -5390,6 +5544,7 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService {
node.toJsonMap(const DiagnosticsSerializationDelegate()), node.toJsonMap(const DiagnosticsSerializationDelegate()),
equals(<String, dynamic>{ equals(<String, dynamic>{
'description': 'description of the deep link', 'description': 'description of the deep link',
'shouldIndent': true,
'type': 'DevToolsDeepLinkProperty', 'type': 'DevToolsDeepLinkProperty',
'name': '', 'name': '',
'style': 'singleLine', 'style': 'singleLine',