| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'dart:convert'; |
| |
| import 'package:flutter/material.dart'; |
| import 'package:flutter/rendering.dart'; |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter_test/flutter_test.dart'; |
| |
| void main() { |
| testWidgets('WidgetInspector smoke test', (WidgetTester tester) async { |
| // This is a smoke test to verify that adding the inspector doesn't crash. |
| await tester.pumpWidget( |
| new Directionality( |
| textDirection: TextDirection.ltr, |
| child: new Stack( |
| children: const <Widget>[ |
| const Text('a', textDirection: TextDirection.ltr), |
| const Text('b', textDirection: TextDirection.ltr), |
| const Text('c', textDirection: TextDirection.ltr), |
| ], |
| ), |
| ), |
| ); |
| |
| await tester.pumpWidget( |
| new Directionality( |
| textDirection: TextDirection.ltr, |
| child: new WidgetInspector( |
| selectButtonBuilder: null, |
| child: new Stack( |
| children: const <Widget>[ |
| const Text('a', textDirection: TextDirection.ltr), |
| const Text('b', textDirection: TextDirection.ltr), |
| const Text('c', textDirection: TextDirection.ltr), |
| ], |
| ), |
| ), |
| ), |
| ); |
| |
| expect(true, isTrue); // Expect that we reach here without crashing. |
| }); |
| |
| testWidgets('WidgetInspector interaction test', (WidgetTester tester) async { |
| final List<String> log = <String>[]; |
| final GlobalKey selectButtonKey = new GlobalKey(); |
| final GlobalKey inspectorKey = new GlobalKey(); |
| final GlobalKey topButtonKey = new GlobalKey(); |
| |
| Widget selectButtonBuilder(BuildContext context, VoidCallback onPressed) { |
| return new Material(child: new RaisedButton(onPressed: onPressed, key: selectButtonKey)); |
| } |
| // State type is private, hence using dynamic. |
| dynamic getInspectorState() => inspectorKey.currentState; |
| String paragraphText(RenderParagraph paragraph) => paragraph.text.text; |
| |
| await tester.pumpWidget( |
| new Directionality( |
| textDirection: TextDirection.ltr, |
| child: new WidgetInspector( |
| key: inspectorKey, |
| selectButtonBuilder: selectButtonBuilder, |
| child: new Material( |
| child: new ListView( |
| children: <Widget>[ |
| new RaisedButton( |
| key: topButtonKey, |
| onPressed: () { |
| log.add('top'); |
| }, |
| child: const Text('TOP'), |
| ), |
| new RaisedButton( |
| onPressed: () { |
| log.add('bottom'); |
| }, |
| child: const Text('BOTTOM'), |
| ), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| expect(getInspectorState().selection.current, isNull); |
| await tester.tap(find.text('TOP')); |
| await tester.pump(); |
| // Tap intercepted by the inspector |
| expect(log, equals(<String>[])); |
| final InspectorSelection selection = getInspectorState().selection; |
| expect(paragraphText(selection.current), equals('TOP')); |
| final RenderObject topButton = find.byKey(topButtonKey).evaluate().first.renderObject; |
| expect(selection.candidates.contains(topButton), isTrue); |
| |
| await tester.tap(find.text('TOP')); |
| expect(log, equals(<String>['top'])); |
| log.clear(); |
| |
| await tester.tap(find.text('BOTTOM')); |
| expect(log, equals(<String>['bottom'])); |
| log.clear(); |
| // Ensure the inspector selection has not changed to bottom. |
| expect(paragraphText(getInspectorState().selection.current), equals('TOP')); |
| |
| await tester.tap(find.byKey(selectButtonKey)); |
| await tester.pump(); |
| |
| // We are now back in select mode so tapping the bottom button will have |
| // not trigger a click but will cause it to be selected. |
| await tester.tap(find.text('BOTTOM')); |
| expect(log, equals(<String>[])); |
| log.clear(); |
| expect(paragraphText(getInspectorState().selection.current), equals('BOTTOM')); |
| }); |
| |
| testWidgets('WidgetInspector non-invertible transform regression test', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| new Directionality( |
| textDirection: TextDirection.ltr, |
| child: new WidgetInspector( |
| selectButtonBuilder: null, |
| child: new Transform( |
| transform: new Matrix4.identity()..scale(0.0), |
| child: new Stack( |
| children: const <Widget>[ |
| const Text('a', textDirection: TextDirection.ltr), |
| const Text('b', textDirection: TextDirection.ltr), |
| const Text('c', textDirection: TextDirection.ltr), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| await tester.tap(find.byType(Transform)); |
| |
| expect(true, isTrue); // Expect that we reach here without crashing. |
| }); |
| |
| testWidgets('WidgetInspector scroll test', (WidgetTester tester) async { |
| final Key childKey = new UniqueKey(); |
| final GlobalKey selectButtonKey = new GlobalKey(); |
| final GlobalKey inspectorKey = new GlobalKey(); |
| |
| Widget selectButtonBuilder(BuildContext context, VoidCallback onPressed) { |
| return new Material(child: new RaisedButton(onPressed: onPressed, key: selectButtonKey)); |
| } |
| // State type is private, hence using dynamic. |
| dynamic getInspectorState() => inspectorKey.currentState; |
| |
| await tester.pumpWidget( |
| new Directionality( |
| textDirection: TextDirection.ltr, |
| child: new WidgetInspector( |
| key: inspectorKey, |
| selectButtonBuilder: selectButtonBuilder, |
| child: new ListView( |
| children: <Widget>[ |
| new Container( |
| key: childKey, |
| height: 5000.0, |
| ), |
| ], |
| ), |
| ), |
| ), |
| ); |
| expect(tester.getTopLeft(find.byKey(childKey)).dy, equals(0.0)); |
| |
| await tester.fling(find.byType(ListView), const Offset(0.0, -200.0), 200.0); |
| await tester.pump(); |
| |
| // Fling does nothing as are in inspect mode. |
| expect(tester.getTopLeft(find.byKey(childKey)).dy, equals(0.0)); |
| |
| await tester.fling(find.byType(ListView), const Offset(200.0, 0.0), 200.0); |
| await tester.pump(); |
| |
| // Fling still does nothing as are in inspect mode. |
| expect(tester.getTopLeft(find.byKey(childKey)).dy, equals(0.0)); |
| |
| await tester.tap(find.byType(ListView)); |
| await tester.pump(); |
| expect(getInspectorState().selection.current, isNotNull); |
| |
| // Now out of inspect mode due to the click. |
| await tester.fling(find.byType(ListView), const Offset(0.0, -200.0), 200.0); |
| await tester.pump(); |
| |
| expect(tester.getTopLeft(find.byKey(childKey)).dy, equals(-200.0)); |
| |
| await tester.fling(find.byType(ListView), const Offset(0.0, 200.0), 200.0); |
| await tester.pump(); |
| |
| expect(tester.getTopLeft(find.byKey(childKey)).dy, equals(0.0)); |
| }); |
| |
| testWidgets('WidgetInspector long press', (WidgetTester tester) async { |
| bool didLongPress = false; |
| |
| await tester.pumpWidget( |
| new Directionality( |
| textDirection: TextDirection.ltr, |
| child: new WidgetInspector( |
| selectButtonBuilder: null, |
| child: new GestureDetector( |
| onLongPress: () { |
| expect(didLongPress, isFalse); |
| didLongPress = true; |
| }, |
| child: const Text('target', textDirection: TextDirection.ltr), |
| ), |
| ), |
| ), |
| ); |
| |
| await tester.longPress(find.text('target')); |
| // The inspector will swallow the long press. |
| expect(didLongPress, isFalse); |
| }); |
| |
| testWidgets('WidgetInspector offstage', (WidgetTester tester) async { |
| final GlobalKey inspectorKey = new GlobalKey(); |
| final GlobalKey clickTarget = new GlobalKey(); |
| |
| Widget createSubtree({ double width, Key key }) { |
| return new Stack( |
| children: <Widget>[ |
| new Positioned( |
| key: key, |
| left: 0.0, |
| top: 0.0, |
| width: width, |
| height: 100.0, |
| child: new Text(width.toString(), textDirection: TextDirection.ltr), |
| ), |
| ], |
| ); |
| } |
| await tester.pumpWidget( |
| new Directionality( |
| textDirection: TextDirection.ltr, |
| child: new WidgetInspector( |
| key: inspectorKey, |
| selectButtonBuilder: null, |
| child: new Overlay( |
| initialEntries: <OverlayEntry>[ |
| new OverlayEntry( |
| opaque: false, |
| maintainState: true, |
| builder: (BuildContext _) => createSubtree(width: 94.0), |
| ), |
| new OverlayEntry( |
| opaque: true, |
| maintainState: true, |
| builder: (BuildContext _) => createSubtree(width: 95.0), |
| ), |
| new OverlayEntry( |
| opaque: false, |
| maintainState: true, |
| builder: (BuildContext _) => createSubtree(width: 96.0, key: clickTarget), |
| ), |
| ], |
| ), |
| ), |
| ), |
| ); |
| |
| await tester.longPress(find.byKey(clickTarget)); |
| // State type is private, hence using dynamic. |
| final dynamic inspectorState = inspectorKey.currentState; |
| // The object with width 95.0 wins over the object with width 94.0 because |
| // the subtree with width 94.0 is offstage. |
| expect(inspectorState.selection.current.semanticBounds.width, equals(95.0)); |
| |
| // Exactly 2 out of the 3 text elements should be in the candidate list of |
| // objects to select as only 2 are onstage. |
| expect(inspectorState.selection.candidates.where((RenderObject object) => object is RenderParagraph).length, equals(2)); |
| }); |
| |
| test('WidgetInspectorService null id', () { |
| final WidgetInspectorService service = WidgetInspectorService.instance; |
| service.disposeAllGroups(); |
| expect(service.toObject(null), isNull); |
| expect(service.toId(null, 'test-group'), isNull); |
| }); |
| |
| test('WidgetInspectorService dispose group', () { |
| final WidgetInspectorService service = WidgetInspectorService.instance; |
| service.disposeAllGroups(); |
| final Object a = new Object(); |
| const String group1 = 'group-1'; |
| const String group2 = 'group-2'; |
| const String group3 = 'group-3'; |
| final String aId = service.toId(a, group1); |
| expect(service.toId(a, group2), equals(aId)); |
| expect(service.toId(a, group3), equals(aId)); |
| service.disposeGroup(group1); |
| service.disposeGroup(group2); |
| expect(service.toObject(aId), equals(a)); |
| service.disposeGroup(group3); |
| expect(() => service.toObject(aId), throwsFlutterError); |
| }); |
| |
| test('WidgetInspectorService dispose id', () { |
| final WidgetInspectorService service = WidgetInspectorService.instance; |
| service.disposeAllGroups(); |
| final Object a = new Object(); |
| final Object b = new Object(); |
| const String group1 = 'group-1'; |
| const String group2 = 'group-2'; |
| final String aId = service.toId(a, group1); |
| final String bId = service.toId(b, group1); |
| expect(service.toId(a, group2), equals(aId)); |
| service.disposeId(bId, group1); |
| expect(() => service.toObject(bId), throwsFlutterError); |
| service.disposeId(aId, group1); |
| expect(service.toObject(aId), equals(a)); |
| service.disposeId(aId, group2); |
| expect(() => service.toObject(aId), throwsFlutterError); |
| }); |
| |
| test('WidgetInspectorService toObjectForSourceLocation', () { |
| const String group = 'test-group'; |
| const Text widget = const Text('a', textDirection: TextDirection.ltr); |
| final WidgetInspectorService service = WidgetInspectorService.instance; |
| service.disposeAllGroups(); |
| final String id = service.toId(widget, group); |
| expect(service.toObjectForSourceLocation(id), equals(widget)); |
| final Element element = widget.createElement(); |
| final String elementId = service.toId(element, group); |
| expect(service.toObjectForSourceLocation(elementId), equals(widget)); |
| expect(element, isNot(equals(widget))); |
| service.disposeGroup(group); |
| expect(() => service.toObjectForSourceLocation(elementId), throwsFlutterError); |
| }); |
| |
| test('WidgetInspectorService object id test', () { |
| const Text a = const Text('a', textDirection: TextDirection.ltr); |
| const Text b = const Text('b', textDirection: TextDirection.ltr); |
| const Text c = const Text('c', textDirection: TextDirection.ltr); |
| const Text d = const Text('d', textDirection: TextDirection.ltr); |
| |
| const String group1 = 'group-1'; |
| const String group2 = 'group-2'; |
| const String group3 = 'group-3'; |
| final WidgetInspectorService service = WidgetInspectorService.instance; |
| service.disposeAllGroups(); |
| |
| final String aId = service.toId(a, group1); |
| final String bId = service.toId(b, group2); |
| final String cId = service.toId(c, group3); |
| final String dId = service.toId(d, group1); |
| // Make sure we get a consistent id if we add the object to a group multiple |
| // times. |
| expect(aId, equals(service.toId(a, group1))); |
| expect(service.toObject(aId), equals(a)); |
| expect(service.toObject(aId), isNot(equals(b))); |
| expect(service.toObject(bId), equals(b)); |
| expect(service.toObject(cId), equals(c)); |
| expect(service.toObject(dId), equals(d)); |
| // Make sure we get a consistent id even if we add the object to a different |
| // group. |
| expect(aId, equals(service.toId(a, group3))); |
| expect(aId, isNot(equals(bId))); |
| expect(aId, isNot(equals(cId))); |
| |
| service.disposeGroup(group3); |
| }); |
| |
| testWidgets('WidgetInspectorService maybeSetSelection', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| new Directionality( |
| textDirection: TextDirection.ltr, |
| child: new Stack( |
| children: const <Widget>[ |
| const Text('a', textDirection: TextDirection.ltr), |
| const Text('b', textDirection: TextDirection.ltr), |
| const Text('c', textDirection: TextDirection.ltr), |
| ], |
| ), |
| ), |
| ); |
| final Element elementA = find.text('a').evaluate().first; |
| final Element elementB = find.text('b').evaluate().first; |
| |
| final WidgetInspectorService service = WidgetInspectorService.instance; |
| service.disposeAllGroups(); |
| service.selection.clear(); |
| int selectionChangedCount = 0; |
| service.selectionChangedCallback = () => selectionChangedCount++; |
| service.setSelection('invalid selection'); |
| expect(selectionChangedCount, equals(0)); |
| expect(service.selection.currentElement, isNull); |
| service.setSelection(elementA); |
| expect(selectionChangedCount, equals(1)); |
| expect(service.selection.currentElement, equals(elementA)); |
| expect(service.selection.current, equals(elementA.renderObject)); |
| |
| service.setSelection(elementB.renderObject); |
| expect(selectionChangedCount, equals(2)); |
| expect(service.selection.current, equals(elementB.renderObject)); |
| expect(service.selection.currentElement, equals(elementB.renderObject.debugCreator.element)); |
| |
| service.setSelection('invalid selection'); |
| expect(selectionChangedCount, equals(2)); |
| expect(service.selection.current, equals(elementB.renderObject)); |
| |
| service.setSelectionById(service.toId(elementA, 'my-group')); |
| expect(selectionChangedCount, equals(3)); |
| expect(service.selection.currentElement, equals(elementA)); |
| expect(service.selection.current, equals(elementA.renderObject)); |
| |
| service.setSelectionById(service.toId(elementA, 'my-group')); |
| expect(selectionChangedCount, equals(3)); |
| expect(service.selection.currentElement, equals(elementA)); |
| }); |
| |
| testWidgets('WidgetInspectorService getParentChain', (WidgetTester tester) async { |
| const String group = 'test-group'; |
| |
| await tester.pumpWidget( |
| new Directionality( |
| textDirection: TextDirection.ltr, |
| child: new Stack( |
| children: const <Widget>[ |
| const Text('a', textDirection: TextDirection.ltr), |
| const Text('b', textDirection: TextDirection.ltr), |
| const Text('c', textDirection: TextDirection.ltr), |
| ], |
| ), |
| ), |
| ); |
| |
| final WidgetInspectorService service = WidgetInspectorService.instance; |
| service.disposeAllGroups(); |
| final Element elementB = find.text('b').evaluate().first; |
| final String bId = service.toId(elementB, group); |
| final Object jsonList = json.decode(service.getParentChain(bId, group)); |
| expect(jsonList, isList); |
| final List<Object> chainElements = jsonList; |
| final List<Element> expectedChain = elementB.debugGetDiagnosticChain()?.reversed?.toList(); |
| // Sanity check that the chain goes back to the root. |
| expect(expectedChain.first, tester.binding.renderViewElement); |
| |
| expect(chainElements.length, equals(expectedChain.length)); |
| for (int i = 0; i < expectedChain.length; i += 1) { |
| expect(chainElements[i], isMap); |
| final Map<String, Object> chainNode = chainElements[i]; |
| final Element element = expectedChain[i]; |
| expect(chainNode['node'], isMap); |
| final Map<String, Object> jsonNode = chainNode['node']; |
| expect(service.toObject(jsonNode['valueId']), equals(element)); |
| expect(service.toObject(jsonNode['objectId']), const isInstanceOf<DiagnosticsNode>()); |
| |
| expect(chainNode['children'], isList); |
| final List<Object> jsonChildren = chainNode['children']; |
| final List<Element> childrenElements = <Element>[]; |
| element.visitChildren(childrenElements.add); |
| expect(jsonChildren.length, equals(childrenElements.length)); |
| if (i + 1 == expectedChain.length) { |
| expect(chainNode['childIndex'], isNull); |
| } else { |
| expect(chainNode['childIndex'], equals(childrenElements.indexOf(expectedChain[i+1]))); |
| } |
| for (int j = 0; j < childrenElements.length; j += 1) { |
| expect(jsonChildren[j], isMap); |
| final Map<String, Object> childJson = jsonChildren[j]; |
| expect(service.toObject(childJson['valueId']), equals(childrenElements[j])); |
| expect(service.toObject(childJson['objectId']), const isInstanceOf<DiagnosticsNode>()); |
| } |
| } |
| }); |
| |
| test('WidgetInspectorService getProperties', () { |
| final DiagnosticsNode diagnostic = const Text('a', textDirection: TextDirection.ltr).toDiagnosticsNode(); |
| const String group = 'group'; |
| final WidgetInspectorService service = WidgetInspectorService.instance; |
| service.disposeAllGroups(); |
| final String id = service.toId(diagnostic, group); |
| final List<Object> propertiesJson = json.decode(service.getProperties(id, group)); |
| final List<DiagnosticsNode> properties = diagnostic.getProperties(); |
| expect(properties, isNotEmpty); |
| expect(propertiesJson.length, equals(properties.length)); |
| for (int i = 0; i < propertiesJson.length; ++i) { |
| final Map<String, Object> propertyJson = propertiesJson[i]; |
| expect(service.toObject(propertyJson['valueId']), equals(properties[i].value)); |
| expect(service.toObject(propertyJson['objectId']), const isInstanceOf<DiagnosticsNode>()); |
| } |
| }); |
| |
| testWidgets('WidgetInspectorService getChildren', (WidgetTester tester) async { |
| const String group = 'test-group'; |
| |
| await tester.pumpWidget( |
| new Directionality( |
| textDirection: TextDirection.ltr, |
| child: new Stack( |
| children: const <Widget>[ |
| const Text('a', textDirection: TextDirection.ltr), |
| const Text('b', textDirection: TextDirection.ltr), |
| const Text('c', textDirection: TextDirection.ltr), |
| ], |
| ), |
| ), |
| ); |
| final DiagnosticsNode diagnostic = find.byType(Stack).evaluate().first.toDiagnosticsNode(); |
| final WidgetInspectorService service = WidgetInspectorService.instance; |
| service.disposeAllGroups(); |
| final String id = service.toId(diagnostic, group); |
| final List<Object> propertiesJson = json.decode(service.getChildren(id, group)); |
| final List<DiagnosticsNode> children = diagnostic.getChildren(); |
| expect(children.length, equals(3)); |
| expect(propertiesJson.length, equals(children.length)); |
| for (int i = 0; i < propertiesJson.length; ++i) { |
| final Map<String, Object> propertyJson = propertiesJson[i]; |
| expect(service.toObject(propertyJson['valueId']), equals(children[i].value)); |
| expect(service.toObject(propertyJson['objectId']), const isInstanceOf<DiagnosticsNode>()); |
| } |
| }); |
| |
| testWidgets('WidgetInspectorService creationLocation', (WidgetTester tester) async { |
| final WidgetInspectorService service = WidgetInspectorService.instance; |
| |
| await tester.pumpWidget( |
| new Directionality( |
| textDirection: TextDirection.ltr, |
| child: new Stack( |
| children: const <Widget>[ |
| const Text('a'), |
| const Text('b', textDirection: TextDirection.ltr), |
| const Text('c', textDirection: TextDirection.ltr), |
| ], |
| ), |
| ), |
| ); |
| final Element elementA = find.text('a').evaluate().first; |
| final Element elementB = find.text('b').evaluate().first; |
| |
| service.disposeAllGroups(); |
| service.setPubRootDirectories(<Object>[]); |
| service.setSelection(elementA, 'my-group'); |
| final Map<String, Object> jsonA = json.decode(service.getSelectedWidget(null, 'my-group')); |
| final Map<String, Object> creationLocationA = jsonA['creationLocation']; |
| expect(creationLocationA, isNotNull); |
| final String fileA = creationLocationA['file']; |
| final int lineA = creationLocationA['line']; |
| final int columnA = creationLocationA['column']; |
| final List<Object> parameterLocationsA = creationLocationA['parameterLocations']; |
| |
| service.setSelection(elementB, 'my-group'); |
| final Map<String, Object> jsonB = json.decode(service.getSelectedWidget(null, 'my-group')); |
| final Map<String, Object> creationLocationB = jsonB['creationLocation']; |
| expect(creationLocationB, isNotNull); |
| final String fileB = creationLocationB['file']; |
| final int lineB = creationLocationB['line']; |
| final int columnB = creationLocationB['column']; |
| final List<Object> parameterLocationsB = creationLocationB['parameterLocations']; |
| expect(fileA, endsWith('widget_inspector_test.dart')); |
| expect(fileA, equals(fileB)); |
| // We don't hardcode the actual lines the widgets are created on as that |
| // would make this test fragile. |
| expect(lineA + 1, equals(lineB)); |
| // Column numbers are more stable than line numbers. |
| expect(columnA, equals(19)); |
| expect(columnA, equals(columnB)); |
| expect(parameterLocationsA.length, equals(1)); |
| final Map<String, Object> paramA = parameterLocationsA[0]; |
| expect(paramA['name'], equals('data')); |
| expect(paramA['line'], equals(lineA)); |
| expect(paramA['column'], equals(24)); |
| |
| expect(parameterLocationsB.length, equals(2)); |
| final Map<String, Object> paramB1 = parameterLocationsB[0]; |
| expect(paramB1['name'], equals('data')); |
| expect(paramB1['line'], equals(lineB)); |
| expect(paramB1['column'], equals(24)); |
| final Map<String, Object> paramB2 = parameterLocationsB[1]; |
| expect(paramB2['name'], equals('textDirection')); |
| expect(paramB2['line'], equals(lineB)); |
| expect(paramB2['column'], equals(29)); |
| }, skip: !WidgetInspectorService.instance.isWidgetCreationTracked()); // Test requires --track-widget-creation flag. |
| |
| testWidgets('WidgetInspectorService setPubRootDirectories', (WidgetTester tester) async { |
| final WidgetInspectorService service = WidgetInspectorService.instance; |
| |
| await tester.pumpWidget( |
| new Directionality( |
| textDirection: TextDirection.ltr, |
| child: new Stack( |
| children: const <Widget>[ |
| const Text('a'), |
| const Text('b', textDirection: TextDirection.ltr), |
| const Text('c', textDirection: TextDirection.ltr), |
| ], |
| ), |
| ), |
| ); |
| final Element elementA = find.text('a').evaluate().first; |
| |
| service.disposeAllGroups(); |
| service.setPubRootDirectories(<Object>[]); |
| service.setSelection(elementA, 'my-group'); |
| Map<String, Object> jsonObject = json.decode(service.getSelectedWidget(null, 'my-group')); |
| Map<String, Object> creationLocation = jsonObject['creationLocation']; |
| expect(creationLocation, isNotNull); |
| final String fileA = creationLocation['file']; |
| expect(fileA, endsWith('widget_inspector_test.dart')); |
| expect(jsonObject, isNot(contains('createdByLocalProject'))); |
| final List<String> segments = Uri.parse(fileA).pathSegments; |
| // Strip a couple subdirectories away to generate a plausible pub root |
| // directory. |
| final String pubRootTest = '/' + segments.take(segments.length - 2).join('/'); |
| service.setPubRootDirectories(<Object>[pubRootTest]); |
| |
| service.setSelection(elementA, 'my-group'); |
| expect(json.decode(service.getSelectedWidget(null, 'my-group')), contains('createdByLocalProject')); |
| |
| service.setPubRootDirectories(<Object>['/invalid/$pubRootTest']); |
| expect(json.decode(service.getSelectedWidget(null, 'my-group')), isNot(contains('createdByLocalProject'))); |
| |
| service.setPubRootDirectories(<Object>['file://$pubRootTest']); |
| expect(json.decode(service.getSelectedWidget(null, 'my-group')), contains('createdByLocalProject')); |
| |
| service.setPubRootDirectories(<Object>['$pubRootTest/different']); |
| expect(json.decode(service.getSelectedWidget(null, 'my-group')), isNot(contains('createdByLocalProject'))); |
| |
| service.setPubRootDirectories(<Object>[ |
| '/invalid/$pubRootTest', |
| pubRootTest, |
| ]); |
| expect(json.decode(service.getSelectedWidget(null, 'my-group')), contains('createdByLocalProject')); |
| |
| // The RichText child of the Text widget is created by the core framework |
| // not the current package. |
| final Element richText = find.descendant( |
| of: find.text('a'), |
| matching: find.byType(RichText), |
| ).evaluate().first; |
| service.setSelection(richText, 'my-group'); |
| service.setPubRootDirectories(<Object>[pubRootTest]); |
| jsonObject = json.decode(service.getSelectedWidget(null, 'my-group')); |
| expect(jsonObject, isNot(contains('createdByLocalProject'))); |
| creationLocation = jsonObject['creationLocation']; |
| expect(creationLocation, isNotNull); |
| // This RichText widget is created by the build method of the Text widget |
| // thus the creation location is in text.dart not basic.dart |
| final List<String> pathSegmentsFramework = Uri.parse(creationLocation['file']).pathSegments; |
| expect(pathSegmentsFramework.join('/'), endsWith('/packages/flutter/lib/src/widgets/text.dart')); |
| |
| // Strip off /src/widgets/text.dart. |
| final String pubRootFramework = '/' + pathSegmentsFramework.take(pathSegmentsFramework.length - 3).join('/'); |
| service.setPubRootDirectories(<Object>[pubRootFramework]); |
| expect(json.decode(service.getSelectedWidget(null, 'my-group')), contains('createdByLocalProject')); |
| service.setSelection(elementA, 'my-group'); |
| expect(json.decode(service.getSelectedWidget(null, 'my-group')), isNot(contains('createdByLocalProject'))); |
| |
| service.setPubRootDirectories(<Object>[pubRootFramework, pubRootTest]); |
| service.setSelection(elementA, 'my-group'); |
| expect(json.decode(service.getSelectedWidget(null, 'my-group')), contains('createdByLocalProject')); |
| service.setSelection(richText, 'my-group'); |
| expect(json.decode(service.getSelectedWidget(null, 'my-group')), contains('createdByLocalProject')); |
| }, skip: !WidgetInspectorService.instance.isWidgetCreationTracked()); // Test requires --track-widget-creation flag. |
| } |