diff --git a/flutter-candidate.txt b/flutter-candidate.txt index c206b1535bb..99dc991e18d 100644 --- a/flutter-candidate.txt +++ b/flutter-candidate.txt @@ -1 +1 @@ -2b6b9d12589875842e64f4b78fd0f11337755aaa +c2ea27002b9c4ab1aff1db6eb1960e4299aca369 diff --git a/packages/devtools_app/test/screens/inspector/inspector_integration_test.dart b/packages/devtools_app/test/screens/inspector/inspector_integration_test.dart index 822cd941b71..013ec0747a6 100644 --- a/packages/devtools_app/test/screens/inspector/inspector_integration_test.dart +++ b/packages/devtools_app/test/screens/inspector/inspector_integration_test.dart @@ -17,15 +17,13 @@ import '../../test_infra/matchers/matchers.dart'; const inspectorChangeSettleTime = Duration(seconds: 2); void main() { + const windowSize = Size(2600.0, 1200.0); // We need to use real async in this test so we need to use this binding. initializeLiveTestWidgetsFlutterBindingWithAssets(); - const windowSize = Size(2600.0, 1200.0); - final env = FlutterTestEnvironment( - const FlutterRunConfiguration(withDebugger: true), - ); + late FlutterTestEnvironment env; - env.afterEverySetup = () async { + Future resetInspectorSelection() async { final service = serviceConnection.inspectorService; if (env.reuseTestEnvironment) { // Ensure the previous test did not set the selection on the device. @@ -37,19 +35,26 @@ void main() { isAlive: null, ); } - }; + } - setUp(() async { - await env.setupEnvironment(); - // Ensure the legacy inspector is enabled: - preferences.inspector.setLegacyInspectorEnabled(true); - }); + group('screenshot tests', () { + setUpAll(() { + env = FlutterTestEnvironment( + const FlutterRunConfiguration(withDebugger: true), + ); + env.afterEverySetup = resetInspectorSelection; + }); - tearDownAll(() async { - await env.tearDownEnvironment(force: true); - }); + setUp(() async { + await env.setupEnvironment(); + // Ensure the legacy inspector is enabled: + preferences.inspector.setLegacyInspectorEnabled(true); + }); + + tearDownAll(() async { + await env.tearDownEnvironment(force: true); + }); - group('screenshot tests', () { testWidgetsWithWindowSize('navigation', windowSize, ( WidgetTester tester, ) async { @@ -99,6 +104,9 @@ void main() { matchesDevToolsGolden( '../../test_infra/goldens/integration_inspector_select_center_details_tree.png', ), + // Implementation widgets from Flutter framework are not guaranteed to + // be stable. + skip: 'https://github.com/flutter/flutter/issues/172037', ); // Select the RichText row. @@ -109,6 +117,9 @@ void main() { matchesDevToolsGolden( '../../test_infra/goldens/integration_inspector_richtext_selected.png', ), + // Implementation widgets from Flutter framework are not guaranteed to + // be stable. + skip: 'https://github.com/flutter/flutter/issues/172037', ); // Test hovering over the icon shown when a property has its default @@ -131,6 +142,9 @@ void main() { matchesDevToolsGolden( '../../test_infra/goldens/integration_inspector_scaffold_selected.png', ), + // Implementation widgets from Flutter framework are not guaranteed to + // be stable. + skip: 'https://github.com/flutter/flutter/issues/172037', ); // The important thing about this is that the details tree should scroll @@ -143,6 +157,9 @@ void main() { matchesDevToolsGolden( '../../test_infra/goldens/integration_animated_physical_model_selected.png', ), + // Implementation widgets from Flutter framework are not guaranteed to + // be stable. + skip: 'https://github.com/flutter/flutter/issues/172037', ); await env.tearDownEnvironment(); @@ -401,15 +418,25 @@ void main() { }); group('widget errors', () { - testWidgetsWithWindowSize('show navigator and error labels', windowSize, ( - WidgetTester tester, - ) async { + setUpAll(() async { + env = FlutterTestEnvironment( + testAppDirectory: 'test/test_infra/fixtures/inspector_app', + const FlutterRunConfiguration(withDebugger: true), + ); await env.setupEnvironment( config: const FlutterRunConfiguration( withDebugger: true, entryScript: 'lib/overflow_errors.dart', ), ); + env.afterEverySetup = resetInspectorSelection; + // Enable the legacy inspector. + preferences.inspector.setLegacyInspectorEnabled(true); + }); + + testWidgetsWithWindowSize('show navigator and error labels', windowSize, ( + WidgetTester tester, + ) async { expect(serviceConnection.serviceManager.service, equals(env.service)); expect(serviceConnection.serviceManager.isolateManager, isNotNull); diff --git a/packages/devtools_app/test/screens/inspector_v2/inspector_integration_test.dart b/packages/devtools_app/test/screens/inspector_v2/inspector_integration_test.dart index 5ee0258b176..6d4e0cbfb3e 100644 --- a/packages/devtools_app/test/screens/inspector_v2/inspector_integration_test.dart +++ b/packages/devtools_app/test/screens/inspector_v2/inspector_integration_test.dart @@ -15,6 +15,7 @@ import 'package:devtools_app/src/screens/inspector/inspector_screen_body.dart' import 'package:devtools_app/src/screens/inspector_shared/inspector_controls.dart'; import 'package:devtools_app/src/screens/inspector_v2/inspector_screen_body.dart'; import 'package:devtools_app/src/screens/inspector_v2/inspector_tree_controller.dart'; +import 'package:devtools_app/src/screens/inspector_v2/layout_explorer/ui/utils.dart'; import 'package:devtools_app/src/screens/inspector_v2/widget_properties/properties_view.dart'; import 'package:devtools_app_shared/ui.dart'; import 'package:devtools_test/helpers.dart'; @@ -41,17 +42,18 @@ void main() { final env = FlutterTestEnvironment( const FlutterRunConfiguration(withDebugger: true), - useTempDirectory: true, + testAppDirectory: 'test/test_infra/fixtures/inspector_app', ); env.afterEverySetup = () async { final service = serviceConnection.inspectorService; + await _resetPubRootDirectories(service as InspectorService); if (env.reuseTestEnvironment) { // Ensure the previous test did not set the selection on the device. // TODO(jacobr): add a proper method to WidgetInspectorService that does // this. setSelection currently ignores null selection requests which is // a misfeature. - await service!.inspectorLibrary.eval( + await service.inspectorLibrary.eval( 'WidgetInspectorService.instance.selection.clear()', isAlive: null, ); @@ -99,7 +101,7 @@ void main() { await _loadInspectorUI(tester); // Expect the Center widget to be visible in the widget tree. - final centerWidgetFinder = find.richText('Center'); + final centerWidgetFinder = find.richText('CustomCenter'); expect(centerWidgetFinder, findsOneWidget); // Trigger a hot-restart and wait for the first Flutter frame. @@ -128,8 +130,8 @@ void main() { ) async { await _loadInspectorUI(tester); - // Select the Center widget (row index #16) - await tester.tap(find.richText('Center')); + // Select the CustomCenter widget (row index #4) + await tester.tap(find.richText('CustomCenter')); await tester.pumpAndSettle(inspectorChangeSettleTime); await expectLater( find.byType(InspectorScreenBody), @@ -160,13 +162,13 @@ void main() { // Toggle implementation widgets on. await _toggleImplementationWidgets(tester); - // Before hidden widgets are expanded, confirm the HeroControllerScope - // is hidden: - final hideableNodeFinder = findNodeMatching('HeroControllerScope'); + // Before hidden widgets are expanded, confirm the implementing + // Container of CustomContainer is hidden: + final hideableNodeFinder = findNodeMatching('Container'); expect(hideableNodeFinder, findsNothing); - // Expand the hidden group that contains the HeroControllerScope: - final moreWidgetsRow = findChildRowOf('MaterialApp'); + // Expand the hidden group that contains the Container: + final moreWidgetsRow = findChildRowOf('CustomContainer'); final expandButton = findExpandCollapseButtonForRow( rowFinder: moreWidgetsRow, isExpand: true, @@ -178,12 +180,12 @@ void main() { matchesDevToolsGolden( '../../test_infra/goldens/integration_inspector_v2_implementation_widgets_expanded.png', ), - // Re-enable and update goldens once Flutter version in DevTools - // includes https://github.com/flutter/flutter/pull/169229. - skip: 'https://github.com/flutter/devtools/issues/9206', + // Implementation widgets from Flutter framework are not guaranteed to + // be stable. + skip: 'https://github.com/flutter/flutter/issues/172037', ); - // Confirm the HeroControllerScope is visible, and select it: + // Confirm the Container is visible, and select it: expect(hideableNodeFinder, findsOneWidget); await tester.tap(hideableNodeFinder); await tester.pumpAndSettle(inspectorChangeSettleTime); @@ -192,15 +194,15 @@ void main() { matchesDevToolsGolden( '../../test_infra/goldens/integration_inspector_v2_hideable_widget_selected.png', ), - // Re-enable and update goldens once Flutter version in DevTools - // includes https://github.com/flutter/flutter/pull/169229. - skip: 'https://github.com/flutter/devtools/issues/9206', + // Implementation widgets from Flutter framework are not guaranteed to + // be stable. + skip: 'https://github.com/flutter/flutter/issues/172037', ); - // Collapse the hidden group that contains the HeroControllerScope: - final scrollConfigurationRow = findChildRowOf('MaterialApp'); + // Collapse the hidden group that contains the Container: + final collapsibleRow = findChildRowOf('CustomContainer'); final collapseButton = findExpandCollapseButtonForRow( - rowFinder: scrollConfigurationRow, + rowFinder: collapsibleRow, isExpand: false, ); await tester.tap(collapseButton); @@ -222,32 +224,33 @@ void main() { // Toggle implementation widgets on. await _toggleImplementationWidgets(tester); - // Before searching, confirm the HeroControllerScope is hidden: - final hideableNodeFinder = findNodeMatching('HeroControllerScope'); + // Before searching, confirm the implementing DefaultTextStyle of + // CustomApp is hidden: + final hideableNodeFinder = findNodeMatching('DefaultTextStyle'); expect(hideableNodeFinder, findsNothing); - // Search for the HeroControllerScope: + // Search for the DefaultTextStyle: final searchButtonFinder = find.ancestor( of: find.byIcon(Icons.search), matching: find.byType(ToolbarAction), ); await tester.tap(searchButtonFinder); await tester.pumpAndSettle(inspectorChangeSettleTime); - await tester.enterText(find.byType(TextField), 'HeroControllerScope'); + await tester.enterText(find.byType(TextField), 'DefaultTextStyle'); await tester.pumpAndSettle(inspectorChangeSettleTime); await tester.tap(find.byIcon(Icons.close)); await tester.pumpAndSettle(inspectorChangeSettleTime); - // Confirm the HeroControllerScope is visible and selected: + // Confirm the DefaultTextStyle is visible and selected: expect(hideableNodeFinder, findsOneWidget); await expectLater( find.byType(InspectorScreenBody), matchesDevToolsGolden( '../../test_infra/goldens/integration_inspector_v2_hideable_widget_selected_from_search.png', ), - // Re-enable and update goldens once Flutter version in DevTools - // includes https://github.com/flutter/flutter/pull/169229. - skip: 'https://github.com/flutter/devtools/issues/9206', + // Implementation widgets from Flutter framework are not guaranteed to + // be stable. + skip: 'https://github.com/flutter/flutter/issues/172037', ); }); }); @@ -308,53 +311,58 @@ void main() { tester.state(find.byType(InspectorScreenBody)) as InspectorScreenBodyState; - // Find the first Text diagnostic node. + // Find the CustomText diagnostic node. final diagnostics = state.controller.inspectorTree.rowsInTree.value.map( (row) => row!.node.diagnostic, ); - final textDiagnostic = diagnostics.firstWhere( - (d) => d?.description == 'Text', + final customTextDiagnostic = diagnostics.firstWhere( + (d) => d?.description == 'CustomText', )!; - expect(textDiagnostic.isCreatedByLocalProject, isTrue); + expect(customTextDiagnostic.isCreatedByLocalProject, isTrue); // Toggle implementation widgets off. await _toggleImplementationWidgets(tester); - // Verify the Text diagnostic node is still in the tree. + // Verify the CustomText diagnostic node is still in the tree. final diagnosticsNow = state.controller.inspectorTree.rowsInTree.value.map( (row) => row!.node.diagnostic, ); expect( - diagnosticsNow.any((d) => d?.valueRef == textDiagnostic.valueRef), + diagnosticsNow.any((d) => d?.valueRef == customTextDiagnostic.valueRef), isTrue, ); - // Get the RichText child of the Text diagnostic node. + // Get the implementing Text child of the CustomText diagnostic node. final service = serviceConnection.inspectorService as InspectorService; final group = service.createObjectGroup('test-group'); - final textSubtree = await group.getDetailsSubtree(textDiagnostic); - final richTextDiagnostic = (await textSubtree!.children)!.firstWhere( - (child) => child.description == 'RichText', + final customTextSubtree = await group.getDetailsSubtree( + customTextDiagnostic, + ); + final textDiagnostic = (await customTextSubtree!.children)!.firstWhere( + (child) => child.description == 'Text', ); - // Verify the RichText child is an implementation node that is not in the tree. - expect(richTextDiagnostic.isCreatedByLocalProject, isFalse); + // Verify the Text child is an implementation node that is not in the tree. + expect(textDiagnostic.isCreatedByLocalProject, isFalse); expect( - diagnosticsNow.any((d) => d?.valueRef == richTextDiagnostic.valueRef), + diagnosticsNow.any((d) => d?.valueRef == textDiagnostic.valueRef), isFalse, ); - // Mimic selecting the RichText diagnostic node with the on-device inspector. - await group.setSelectionInspector(richTextDiagnostic.valueRef, false); + // Mimic selecting the Text diagnostic node with the on-device inspector. + await group.setSelectionInspector(textDiagnostic.valueRef, false); await tester.pumpAndSettle(inspectorChangeSettleTime); - // Verify the Text node is now selected. + // Verify the CustomText node is now selected. final selectedNode = state.controller.selectedNode.value; - expect(selectedNode!.diagnostic!.valueRef, equals(textDiagnostic.valueRef)); + expect( + selectedNode!.diagnostic!.valueRef, + equals(customTextDiagnostic.valueRef), + ); // Verify the notification about selecting an implementation widget is displayed. expect( - find.text('Selected an implementation widget of Text: RichText.'), + find.text('Selected an implementation widget of CustomText: Text.'), findsOneWidget, ); }); @@ -364,8 +372,8 @@ void main() { ) async { await _loadInspectorUI(tester); - // Select the Center widget (row index #16) - await tester.tap(find.richText('Center')); + // Select the CustomCenter widget (row index #4) + await tester.tap(find.richText('CustomCenter')); await tester.pumpAndSettle(inspectorChangeSettleTime); // Disable Inspector V2: @@ -432,10 +440,6 @@ void main() { 'textPreview', 'children', 'createdByLocalProject', - // TODO(elliette): Once we update to the Flutter version with - // https://github.com/flutter/flutter/pull/159701, this should be - // deleted. - 'truncated', ]; const extraneousDetailsForTreeNode = [ 'creationLocation', @@ -511,58 +515,55 @@ void main() { ); } - testWidgetsWithWindowSize('changing parent widget of selected', windowSize, ( - WidgetTester tester, - ) async { - await _loadInspectorUI(tester); + testWidgetsWithWindowSize( + 'changing parent widget of selected', + windowSize, + (WidgetTester tester) async { + await _loadInspectorUI(tester); - // Toggle implementation widgets on. - await _toggleImplementationWidgets(tester); + // Toggle implementation widgets on. + await _toggleImplementationWidgets(tester); - // Give time for the initial animation to complete. - await tester.pumpAndSettle(inspectorChangeSettleTime); + // Give time for the initial animation to complete. + await tester.pumpAndSettle(inspectorChangeSettleTime); - // Verify the Text widget is after the Center widget. - expect( - _treeRowsAreInOrder( - treeRowDescriptions: ['Center', 'Text: "Hello, World!"'], - startingAtIndex: 15, - ), - isTrue, - ); + // Verify the CustomButton widget is after the CustomCenter widget. + expect( + _treeRowsAreInOrder( + treeRowDescriptions: ['CustomCenter', 'CustomButton'], + startingAtIndex: 7, + ), + isTrue, + ); - // Select the Text widget (row index #16). - await tester.tap(_findTreeRowMatching('Text: "Hello, World!"')); - await tester.pumpAndSettle(inspectorChangeSettleTime); + // Verify the CustomButton widget is not visible in the properties view. + expect(_findWidgetLabelMatching('CustomButton'), findsNothing); - // Verify the Text widget is selected (its properties are displayed): - verifyPropertyIsVisible( - name: 'data', - value: '"Hello, World!"', - tester: tester, - ); + // Select the CustomButton widget. + await tester.tap(_findTreeRowMatching('CustomButton')); + await tester.pumpAndSettle(inspectorChangeSettleTime); - // Make edit to main.dart to replace Center with an Align. - makeEditToFlutterMain(toReplace: 'Center', replaceWith: 'Align'); - await env.flutter!.hotReload(); - await tester.pumpAndSettle(inspectorChangeSettleTime); + // Verify the CustomButton widget is now visible in the properties view. + expect(_findWidgetLabelMatching('CustomButton'), findsOneWidget); - // Verify the Align is now in the widget tree instead of Center. - expect( - _treeRowsAreInOrder( - treeRowDescriptions: ['Align', 'Text: "Hello, World!"'], - startingAtIndex: 15, - ), - isTrue, - ); + // Make edit to main.dart to replace CustomCenter with an Align. + makeEditToFlutterMain(toReplace: 'CustomCenter', replaceWith: 'Align'); + await env.flutter!.hotReload(); + await tester.pumpAndSettle(inspectorChangeSettleTime); - // Verify the Text widget is still selected (its properties are displayed): - verifyPropertyIsVisible( - name: 'data', - value: '"Hello, World!"', - tester: tester, - ); - }); + // Verify the Align is now in the widget tree instead of Center. + expect( + _treeRowsAreInOrder( + treeRowDescriptions: ['Align', 'CustomButton'], + startingAtIndex: 7, + ), + isTrue, + ); + + // Verify the CustomButton widget is still selected. + expect(_findWidgetLabelMatching('CustomButton'), findsOneWidget); + }, + ); }); group('widget errors', () { @@ -652,7 +653,7 @@ Future _waitForFlutterFrame( } Finder findNodeMatching(String text) => find.ancestor( - of: find.richTextContaining(text), + of: find.richText(text), matching: find.byType(DescriptionDisplay), ); @@ -777,5 +778,24 @@ Finder _findTreeRowMatching(String description) => find.ancestor( matching: find.byType(InspectorRowContent), ); +Finder _findWidgetLabelMatching(String description) => find.ancestor( + of: find.richText(description), + matching: find.byType(WidgetLabel), +); + T _getWidgetFromFinder(Finder finder) => finder.first.evaluate().first.widget as T; + +Future _resetPubRootDirectories(InspectorService inspectorService) async { + final currentPubRootDirectories = await inspectorService + .getPubRootDirectories(); + if (currentPubRootDirectories != null) { + await inspectorService.removePubRootDirectories(currentPubRootDirectories); + } + + final rootLibrary = await serviceConnection.serviceManager + .mainIsolateRootLibraryUriAsString(); + if (rootLibrary != null) { + await inspectorService.addPubRootDirectories([rootLibrary]); + } +} diff --git a/packages/devtools_app/test/test_infra/fixtures/custom_widgets/README.md b/packages/devtools_app/test/test_infra/fixtures/custom_widgets/README.md new file mode 100644 index 00000000000..6b6c5074041 --- /dev/null +++ b/packages/devtools_app/test/test_infra/fixtures/custom_widgets/README.md @@ -0,0 +1,8 @@ + +# custom_widgets + +A basic custom widget library used in test_infra/fixtures/inspector_app. \ No newline at end of file diff --git a/packages/devtools_app/test/test_infra/fixtures/custom_widgets/lib/custom_widgets.dart b/packages/devtools_app/test/test_infra/fixtures/custom_widgets/lib/custom_widgets.dart new file mode 100644 index 00000000000..f08d2280698 --- /dev/null +++ b/packages/devtools_app/test/test_infra/fixtures/custom_widgets/lib/custom_widgets.dart @@ -0,0 +1,5 @@ +// Copyright 2025 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. + +export './src/widgets.dart'; diff --git a/packages/devtools_app/test/test_infra/fixtures/custom_widgets/lib/src/widgets.dart b/packages/devtools_app/test/test_infra/fixtures/custom_widgets/lib/src/widgets.dart new file mode 100644 index 00000000000..4084be21830 --- /dev/null +++ b/packages/devtools_app/test/test_infra/fixtures/custom_widgets/lib/src/widgets.dart @@ -0,0 +1,144 @@ +// Copyright 2025 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. + +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +class CustomApp extends StatelessWidget { + const CustomApp({ + super.key, + required this.home, + }); + + final Widget home; + + @override + Widget build(BuildContext context) { + return Directionality( + textDirection: TextDirection.ltr, + child: DefaultTextStyle( + style: const TextStyle( + color: Color(0xFF000000), + fontSize: 14, + fontFamily: 'Roboto', + ), + child: home, + ), + ); + } +} + +class CustomContainer extends StatelessWidget { + const CustomContainer({ + super.key, + this.child, + this.width, + this.height, + this.color, + this.padding, + this.margin, + this.decoration, + }); + + final Widget? child; + final double? width; + final double? height; + final Color? color; + final EdgeInsetsGeometry? padding; + final EdgeInsetsGeometry? margin; + final Decoration? decoration; + + @override + Widget build(BuildContext context) { + // ignore: avoid-wrapping-in-padding, for testing purposes. + return Padding( + padding: padding ?? EdgeInsets.zero, + child: Container( + width: width, + height: height, + margin: margin, + decoration: decoration, + color: color, + child: child, + )); + } +} + +class CustomCenter extends Align { + const CustomCenter( + {super.key, super.widthFactor, super.heightFactor, super.child}); +} + +class CustomText extends StatelessWidget { + const CustomText( + this.data, { + super.key, + this.style, + }); + + final String data; + final TextStyle? style; + + @override + Widget build(BuildContext context) { + return Text( + data, + style: style, + ); + } +} + +class CustomButton extends StatefulWidget { + const CustomButton({ + super.key, + required this.onPressed, + required this.child, + }); + + final VoidCallback? onPressed; + final Widget child; + + @override + State createState() => _CustomButtonState(); +} + +class _CustomButtonState extends State { + bool _isPressed = false; + + void _onTapDown(TapDownDetails details) { + setState(() { + _isPressed = true; + }); + } + + void _onTapUp(TapUpDetails details) { + setState(() { + _isPressed = false; + }); + widget.onPressed?.call(); + } + + void _onTapCancel() { + setState(() { + _isPressed = false; + }); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTapDown: _onTapDown, + onTapUp: _onTapUp, + onTapCancel: _onTapCancel, + child: CustomContainer( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), + decoration: BoxDecoration( + color: _isPressed ? const Color(0xFF0D47A1) : const Color(0xFF2196F3), + borderRadius: BorderRadius.circular(8), + ), + child: widget.child, + ), + ); + } +} diff --git a/packages/devtools_app/test/test_infra/fixtures/custom_widgets/pubspec.yaml b/packages/devtools_app/test/test_infra/fixtures/custom_widgets/pubspec.yaml new file mode 100644 index 00000000000..ffe19a4c0cf --- /dev/null +++ b/packages/devtools_app/test/test_infra/fixtures/custom_widgets/pubspec.yaml @@ -0,0 +1,10 @@ +name: custom_widgets +version: 1.0.0 + +environment: + sdk: ^3.2.0 + flutter: '>=3.0.0' + +dependencies: + flutter: + sdk: flutter diff --git a/packages/devtools_app/test/test_infra/fixtures/inspector_app/.gitignore b/packages/devtools_app/test/test_infra/fixtures/inspector_app/.gitignore new file mode 100644 index 00000000000..47e0b4d6214 --- /dev/null +++ b/packages/devtools_app/test/test_infra/fixtures/inspector_app/.gitignore @@ -0,0 +1,71 @@ +# Miscellaneous +*.class +*.lock +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# Visual Studio Code related +.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.packages +.pub-cache/ +.pub/ +build/ + +# Android related +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/packages/devtools_app/test/test_infra/fixtures/inspector_app/README.md b/packages/devtools_app/test/test_infra/fixtures/inspector_app/README.md new file mode 100644 index 00000000000..33bcb56808d --- /dev/null +++ b/packages/devtools_app/test/test_infra/fixtures/inspector_app/README.md @@ -0,0 +1,21 @@ + + +# inspector_app + +App for running DevTools integration tests for the Inspector panel. + +## `main.dart` + +Contains an app built with widgets from the test_infra/fixtures/custom_widgets +widget library which is used by the Inspector integration test to verify that +the implementation are displayed correctly in the widget tree. + +## `overflow_errors.dart` + +Contains an app which includes overflow errors which is used by the Inspector +integration test to verify that those errors are displayed correctly in the +widget tree. diff --git a/packages/devtools_app/test/test_infra/fixtures/inspector_app/lib/main.dart b/packages/devtools_app/test/test_infra/fixtures/inspector_app/lib/main.dart new file mode 100644 index 00000000000..8387b9d658d --- /dev/null +++ b/packages/devtools_app/test/test_infra/fixtures/inspector_app/lib/main.dart @@ -0,0 +1,38 @@ +// Copyright 2025 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. + +import 'package:custom_widgets/custom_widgets.dart'; +import 'package:flutter/material.dart'; + +void main() { + runApp( + const CustomApp( + home: HomeScreen(), + ), + ); +} + +class HomeScreen extends StatelessWidget { + const HomeScreen({super.key}); + + @override + Widget build(BuildContext context) { + return CustomContainer( + color: Colors.cyanAccent, + child: CustomCenter( + child: CustomButton( + onPressed: () {}, + child: const CustomText( + 'Click Me!', + style: TextStyle( + color: Colors.white, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ); + } +} diff --git a/packages/devtools_app/test/test_infra/fixtures/flutter_app/lib/overflow_errors.dart b/packages/devtools_app/test/test_infra/fixtures/inspector_app/lib/overflow_errors.dart similarity index 100% rename from packages/devtools_app/test/test_infra/fixtures/flutter_app/lib/overflow_errors.dart rename to packages/devtools_app/test/test_infra/fixtures/inspector_app/lib/overflow_errors.dart diff --git a/packages/devtools_app/test/test_infra/fixtures/inspector_app/pubspec.yaml b/packages/devtools_app/test/test_infra/fixtures/inspector_app/pubspec.yaml new file mode 100644 index 00000000000..5c9e2f08421 --- /dev/null +++ b/packages/devtools_app/test/test_infra/fixtures/inspector_app/pubspec.yaml @@ -0,0 +1,24 @@ +# Copyright 2025 The Flutter Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. +name: inspector_app +description: App for running Inspector integration tests. +publish_to: 'none' +version: 1.0.0 + +environment: + sdk: ^3.2.0 + flutter: '>=3.0.0' + +dependencies: + flutter: + sdk: flutter + custom_widgets: + path: ../custom_widgets + +dev_dependencies: + flutter_test: + sdk: flutter + +flutter: + uses-material-design: true diff --git a/packages/devtools_app/test/test_infra/goldens/codeview_scrollbars.png b/packages/devtools_app/test/test_infra/goldens/codeview_scrollbars.png index d32db90ccef..3773f9d2fb1 100644 Binary files a/packages/devtools_app/test/test_infra/goldens/codeview_scrollbars.png and b/packages/devtools_app/test/test_infra/goldens/codeview_scrollbars.png differ diff --git a/packages/devtools_app/test/test_infra/goldens/integration_inspector_v2_implementation_widgets_collapsed.png b/packages/devtools_app/test/test_infra/goldens/integration_inspector_v2_implementation_widgets_collapsed.png index f7c02b175de..e148d4679f1 100644 Binary files a/packages/devtools_app/test/test_infra/goldens/integration_inspector_v2_implementation_widgets_collapsed.png and b/packages/devtools_app/test/test_infra/goldens/integration_inspector_v2_implementation_widgets_collapsed.png differ diff --git a/packages/devtools_app/test/test_infra/goldens/integration_inspector_v2_implementation_widgets_hidden.png b/packages/devtools_app/test/test_infra/goldens/integration_inspector_v2_implementation_widgets_hidden.png index 5c572b5a89a..f1347bd6ecc 100644 Binary files a/packages/devtools_app/test/test_infra/goldens/integration_inspector_v2_implementation_widgets_hidden.png and b/packages/devtools_app/test/test_infra/goldens/integration_inspector_v2_implementation_widgets_hidden.png differ diff --git a/packages/devtools_app/test/test_infra/goldens/integration_inspector_v2_initial_load.png b/packages/devtools_app/test/test_infra/goldens/integration_inspector_v2_initial_load.png index a2aa7fa28b9..26d0044cf97 100644 Binary files a/packages/devtools_app/test/test_infra/goldens/integration_inspector_v2_initial_load.png and b/packages/devtools_app/test/test_infra/goldens/integration_inspector_v2_initial_load.png differ diff --git a/packages/devtools_app/test/test_infra/goldens/integration_inspector_v2_revert_to_legacy.png b/packages/devtools_app/test/test_infra/goldens/integration_inspector_v2_revert_to_legacy.png index 18394b8db9b..60a194d6b46 100644 Binary files a/packages/devtools_app/test/test_infra/goldens/integration_inspector_v2_revert_to_legacy.png and b/packages/devtools_app/test/test_infra/goldens/integration_inspector_v2_revert_to_legacy.png differ diff --git a/packages/devtools_app/test/test_infra/goldens/integration_inspector_v2_select_center.png b/packages/devtools_app/test/test_infra/goldens/integration_inspector_v2_select_center.png index f777daa9c85..d2d00d92589 100644 Binary files a/packages/devtools_app/test/test_infra/goldens/integration_inspector_v2_select_center.png and b/packages/devtools_app/test/test_infra/goldens/integration_inspector_v2_select_center.png differ