diff --git a/dev/benchmarks/microbenchmarks/lib/stocks/layout_bench.dart b/dev/benchmarks/microbenchmarks/lib/stocks/layout_bench.dart index e42211d594c..e4bc85ce523 100644 --- a/dev/benchmarks/microbenchmarks/lib/stocks/layout_bench.dart +++ b/dev/benchmarks/microbenchmarks/lib/stocks/layout_bench.dart @@ -31,13 +31,13 @@ Future main() async { await tester.pump(); // Start drawer animation await tester.pump(const Duration(seconds: 1)); // Complete drawer animation - final TestViewConfiguration big = TestViewConfiguration.fromView( + final TestViewConfiguration big = TestViewConfiguration( size: const Size(360.0, 640.0), - view: tester.view, + window: RendererBinding.instance.window, ); - final TestViewConfiguration small = TestViewConfiguration.fromView( + final TestViewConfiguration small = TestViewConfiguration( size: const Size(355.0, 635.0), - view: tester.view, + window: RendererBinding.instance.window, ); final RenderView renderView = WidgetsBinding.instance.renderView; binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.benchmark; diff --git a/dev/benchmarks/test_apps/stocks/test/icon_color_test.dart b/dev/benchmarks/test_apps/stocks/test/icon_color_test.dart index 6d52faeeca7..3a8b8f71ab5 100644 --- a/dev/benchmarks/test_apps/stocks/test/icon_color_test.dart +++ b/dev/benchmarks/test_apps/stocks/test/icon_color_test.dart @@ -58,8 +58,8 @@ void main() { expect(find.text('Account Balance'), findsNothing); // drag the drawer out - final Offset left = Offset(0.0, (tester.view.physicalSize / tester.view.devicePixelRatio).height / 2.0); - final Offset right = Offset((tester.view.physicalSize / tester.view.devicePixelRatio).width, left.dy); + final Offset left = Offset(0.0, (WidgetsBinding.instance.window.physicalSize / WidgetsBinding.instance.window.devicePixelRatio).height / 2.0); + final Offset right = Offset((WidgetsBinding.instance.window.physicalSize / WidgetsBinding.instance.window.devicePixelRatio).width, left.dy); final TestGesture gesture = await tester.startGesture(left); await tester.pump(); await gesture.moveTo(right); diff --git a/packages/flutter/lib/src/widgets/binding.dart b/packages/flutter/lib/src/widgets/binding.dart index 53f595ce7ed..98124fbbe3a 100644 --- a/packages/flutter/lib/src/widgets/binding.dart +++ b/packages/flutter/lib/src/widgets/binding.dart @@ -901,13 +901,15 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB /// Used by [runApp] to wrap the provided `rootWidget` in the default [View]. /// /// The [View] determines into what [FlutterView] the app is rendered into. - /// This is currently [PlatformDispatcher.implicitView] from [platformDispatcher]. + /// For backwards-compatibility reasons, this method currently chooses + /// [window] (which is a [FlutterView]) as the rendering target. This will + /// change in a future version of Flutter. /// /// The `rootWidget` widget provided to this method must not already be /// wrapped in a [View]. Widget wrapWithDefaultView(Widget rootWidget) { return View( - view: platformDispatcher.implicitView!, + view: window, child: rootWidget, ); } diff --git a/packages/flutter/test/cupertino/route_test.dart b/packages/flutter/test/cupertino/route_test.dart index 0c2dc3108e2..01e997c7fae 100644 --- a/packages/flutter/test/cupertino/route_test.dart +++ b/packages/flutter/test/cupertino/route_test.dart @@ -1702,7 +1702,6 @@ void main() { ]; await tester.pumpWidget( buildNavigator( - view: tester.view, pages: myPages, onPopPage: (Route route, dynamic result) { assert(false); // The test shouldn't call this. @@ -1729,7 +1728,6 @@ void main() { await tester.pumpWidget( buildNavigator( - view: tester.view, pages: myPages, onPopPage: (Route route, dynamic result) { assert(false); // The test shouldn't call this. @@ -1758,7 +1756,6 @@ void main() { ]; await tester.pumpWidget( buildNavigator( - view: tester.view, pages: myPages, onPopPage: (Route route, dynamic result) { assert(false); // The test shouldn't call this. @@ -1780,7 +1777,6 @@ void main() { await tester.pumpWidget( buildNavigator( - view: tester.view, pages: myPages, onPopPage: (Route route, dynamic result) { assert(false); // The test shouldn't call this. @@ -2217,13 +2213,12 @@ class TransitionDetector extends DefaultTransitionDelegate { Widget buildNavigator({ required List> pages, - required FlutterView view, PopPageCallback? onPopPage, GlobalKey? key, TransitionDelegate? transitionDelegate, }) { return MediaQuery( - data: MediaQueryData.fromView(view), + data: MediaQueryData.fromView(WidgetsBinding.instance.window), child: Localizations( locale: const Locale('en', 'US'), delegates: const >[ diff --git a/packages/flutter/test/cupertino/scrollbar_test.dart b/packages/flutter/test/cupertino/scrollbar_test.dart index 71dd6c355d4..e0b8fad3018 100644 --- a/packages/flutter/test/cupertino/scrollbar_test.dart +++ b/packages/flutter/test/cupertino/scrollbar_test.dart @@ -251,7 +251,7 @@ void main() { const double inset = 3; const double scaleFactor = 2; - final Size screenSize = tester.view.physicalSize / tester.view.devicePixelRatio; + final Size screenSize = tester.binding.window.physicalSize / tester.binding.window.devicePixelRatio; final ScrollController scrollController = ScrollController(); await tester.pumpWidget( diff --git a/packages/flutter/test/cupertino/text_field_test.dart b/packages/flutter/test/cupertino/text_field_test.dart index 80e8f730f90..da1a8663729 100644 --- a/packages/flutter/test/cupertino/text_field_test.dart +++ b/packages/flutter/test/cupertino/text_field_test.dart @@ -2,10 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// no-shuffle: +// //TODO(gspencergoog): Remove this tag once this test's state leaks/test +// dependencies have been fixed. +// https://github.com/flutter/flutter/issues/85160 +// Fails with "flutter test --test-randomize-ordering-seed=456" // reduced-test-set: // This file is run as part of a reduced test set in CI on Mac and Windows // machines. -@Tags(['reduced-test-set']) +@Tags(['reduced-test-set', 'no-shuffle']) library; import 'dart:ui' as ui show BoxHeightStyle, BoxWidthStyle, Color; @@ -4998,11 +5003,9 @@ void main() { group('Text selection toolbar', () { testWidgets('Collapsed selection works', (WidgetTester tester) async { - tester.view.physicalSize = const Size(400, 400); - tester.view.devicePixelRatio = 1; - addTearDown(tester.view.reset); - EditableText.debugDeterministicCursor = true; + tester.binding.window.physicalSizeTestValue = const Size(400, 400); + tester.binding.window.devicePixelRatioTestValue = 1; TextEditingController controller; EditableTextState state; Offset bottomLeftSelectionPosition; @@ -5180,14 +5183,15 @@ void main() { ), ), ); + + tester.binding.window.clearPhysicalSizeTestValue(); + tester.binding.window.clearDevicePixelRatioTestValue(); }); testWidgets('selecting multiple words works', (WidgetTester tester) async { - tester.view.physicalSize = const Size(400, 400); - tester.view.devicePixelRatio = 1; - addTearDown(tester.view.reset); - EditableText.debugDeterministicCursor = true; + tester.binding.window.physicalSizeTestValue = const Size(400, 400); + tester.binding.window.devicePixelRatioTestValue = 1; final TextEditingController controller; final EditableTextState state; @@ -5249,14 +5253,15 @@ void main() { ), ), ); + + tester.binding.window.clearPhysicalSizeTestValue(); + tester.binding.window.clearDevicePixelRatioTestValue(); }); testWidgets('selecting multiline works', (WidgetTester tester) async { - tester.view.physicalSize = const Size(400, 400); - tester.view.devicePixelRatio = 1; - addTearDown(tester.view.reset); - EditableText.debugDeterministicCursor = true; + tester.binding.window.physicalSizeTestValue = const Size(400, 400); + tester.binding.window.devicePixelRatioTestValue = 1; final TextEditingController controller; final EditableTextState state; @@ -5322,6 +5327,9 @@ void main() { ), ), ); + + tester.binding.window.clearPhysicalSizeTestValue(); + tester.binding.window.clearDevicePixelRatioTestValue(); }); // This is a regression test for diff --git a/packages/flutter/test/cupertino/text_selection_test.dart b/packages/flutter/test/cupertino/text_selection_test.dart index b5283ab9140..2a63b04b40a 100644 --- a/packages/flutter/test/cupertino/text_selection_test.dart +++ b/packages/flutter/test/cupertino/text_selection_test.dart @@ -246,8 +246,8 @@ void main() { testWidgets("When a menu item doesn't fit, a second page is used.", (WidgetTester tester) async { // Set the screen size to more narrow, so that Paste can't fit. - tester.view.physicalSize = const Size(800, 800); - addTearDown(tester.view.reset); + tester.binding.window.physicalSizeTestValue = const Size(800, 800); + addTearDown(tester.binding.window.clearPhysicalSizeTestValue); final TextEditingController controller = TextEditingController(text: 'abc def ghi'); await tester.pumpWidget(CupertinoApp( @@ -318,8 +318,8 @@ void main() { testWidgets('A smaller menu puts each button on its own page.', (WidgetTester tester) async { // Set the screen size to more narrow, so that two buttons can't fit on // the same page. - tester.view.physicalSize = const Size(640, 800); - addTearDown(tester.view.reset); + tester.binding.window.physicalSizeTestValue = const Size(640, 800); + addTearDown(tester.binding.window.clearPhysicalSizeTestValue); final TextEditingController controller = TextEditingController(text: 'abc def ghi'); await tester.pumpWidget(CupertinoApp( diff --git a/packages/flutter/test/cupertino/text_selection_toolbar_test.dart b/packages/flutter/test/cupertino/text_selection_toolbar_test.dart index 3912bc116bc..83b6d4b5327 100644 --- a/packages/flutter/test/cupertino/text_selection_toolbar_test.dart +++ b/packages/flutter/test/cupertino/text_selection_toolbar_test.dart @@ -188,8 +188,8 @@ void main() { testWidgets('does not paginate if children fit with zero margin', (WidgetTester tester) async { final List children = List.generate(7, (int i) => const TestBox()); - final double spacerWidth = 1.0 / tester.view.devicePixelRatio; - final double dividerWidth = 1.0 / tester.view.devicePixelRatio; + final double spacerWidth = 1.0 / tester.binding.window.devicePixelRatio; + final double dividerWidth = 1.0 / tester.binding.window.devicePixelRatio; const double borderRadius = 8.0; // Should match _kToolbarBorderRadius final double width = 7 * TestBox.itemWidth + 6 * (dividerWidth + 2 * spacerWidth) + 2 * borderRadius; await tester.pumpWidget( diff --git a/packages/flutter/test/gestures/gesture_binding_resample_event_on_widget_test.dart b/packages/flutter/test/gestures/gesture_binding_resample_event_on_widget_test.dart index c31c59f9c29..8c007f2eaa5 100644 --- a/packages/flutter/test/gestures/gesture_binding_resample_event_on_widget_test.dart +++ b/packages/flutter/test/gestures/gesture_binding_resample_event_on_widget_test.dart @@ -101,7 +101,7 @@ void main() { expect(events.length, 1); expect(events[0], isA()); expect(events[0].timeStamp, currentTestFrameTime() + kSamplingOffset); - expect(events[0].position, Offset(7.5 / tester.view.devicePixelRatio, 0.0)); + expect(events[0].position, Offset(7.5 / GestureBinding.instance.window.devicePixelRatio, 0.0)); // Now the system time is epoch + 20ms requestFrame(); @@ -109,8 +109,8 @@ void main() { expect(events.length, 2); expect(events[1].timeStamp, currentTestFrameTime() + kSamplingOffset); expect(events[1], isA()); - expect(events[1].position, Offset(22.5 / tester.view.devicePixelRatio, 0.0)); - expect(events[1].delta, Offset(15.0 / tester.view.devicePixelRatio, 0.0)); + expect(events[1].position, Offset(22.5 / GestureBinding.instance.window.devicePixelRatio, 0.0)); + expect(events[1].delta, Offset(15.0 / GestureBinding.instance.window.devicePixelRatio, 0.0)); // Now the system time is epoch + 30ms requestFrame(); @@ -118,8 +118,8 @@ void main() { expect(events.length, 4); expect(events[2].timeStamp, currentTestFrameTime() + kSamplingOffset); expect(events[2], isA()); - expect(events[2].position, Offset(37.5 / tester.view.devicePixelRatio, 0.0)); - expect(events[2].delta, Offset(15.0 / tester.view.devicePixelRatio, 0.0)); + expect(events[2].position, Offset(37.5 / GestureBinding.instance.window.devicePixelRatio, 0.0)); + expect(events[2].delta, Offset(15.0 / GestureBinding.instance.window.devicePixelRatio, 0.0)); expect(events[3].timeStamp, currentTestFrameTime() + kSamplingOffset); expect(events[3], isA()); }); diff --git a/packages/flutter/test/gestures/gesture_binding_test.dart b/packages/flutter/test/gestures/gesture_binding_test.dart index 76e3b1d7f69..328dd4bbd73 100644 --- a/packages/flutter/test/gestures/gesture_binding_test.dart +++ b/packages/flutter/test/gestures/gesture_binding_test.dart @@ -162,8 +162,6 @@ void main() { expect(events[1], isA()); }); - const double devicePixelRatio = 2.5; - test('Can expand add and hover pointers', () { const ui.PointerDataPacket packet = ui.PointerDataPacket( data: [ @@ -175,7 +173,7 @@ void main() { ], ); - final List events = PointerEventConverter.expand(packet.data, devicePixelRatio).toList(); + final List events = PointerEventConverter.expand(packet.data, GestureBinding.instance.window.devicePixelRatio).toList(); expect(events.length, 5); expect(events[0], isA()); @@ -191,7 +189,7 @@ void main() { ui.PointerData(change: ui.PointerChange.add, device: 24), ], ); - List events = PointerEventConverter.expand(packet.data, devicePixelRatio).toList(); + List events = PointerEventConverter.expand(packet.data, GestureBinding.instance.window.devicePixelRatio).toList(); expect(events.length, 1); expect(events[0], isA()); @@ -207,7 +205,7 @@ void main() { ui.PointerData(signalKind: ui.PointerSignalKind.scroll, device: 24, scrollDeltaY: double.negativeInfinity, scrollDeltaX: 10), ], ); - events = PointerEventConverter.expand(packet.data, devicePixelRatio).toList(); + events = PointerEventConverter.expand(packet.data, GestureBinding.instance.window.devicePixelRatio).toList(); expect(events.length, 0); // Send packet with a valid scroll event. @@ -217,7 +215,7 @@ void main() { ], ); // Make sure PointerEventConverter can expand when device pixel ratio is valid. - events = PointerEventConverter.expand(packet.data, devicePixelRatio).toList(); + events = PointerEventConverter.expand(packet.data, GestureBinding.instance.window.devicePixelRatio).toList(); expect(events.length, 1); expect(events[0], isA()); @@ -234,7 +232,7 @@ void main() { ], ); - final List events = PointerEventConverter.expand(packet.data, devicePixelRatio).toList(); + final List events = PointerEventConverter.expand(packet.data, GestureBinding.instance.window.devicePixelRatio).toList(); expect(events.length, 2); expect(events[0], isA()); @@ -242,7 +240,7 @@ void main() { }); test('Should synthesize kPrimaryButton for touch when no button is set', () { - final Offset location = const Offset(10.0, 10.0) * devicePixelRatio; + final Offset location = const Offset(10.0, 10.0) * GestureBinding.instance.window.devicePixelRatio; final ui.PointerDataPacket packet = ui.PointerDataPacket( data: [ ui.PointerData(change: ui.PointerChange.add, physicalX: location.dx, physicalY: location.dy), @@ -253,7 +251,7 @@ void main() { ], ); - final List events = PointerEventConverter.expand(packet.data, devicePixelRatio).toList(); + final List events = PointerEventConverter.expand(packet.data, GestureBinding.instance.window.devicePixelRatio).toList(); expect(events.length, 5); expect(events[0], isA()); @@ -269,7 +267,7 @@ void main() { }); test('Should not synthesize kPrimaryButton for touch when a button is set', () { - final Offset location = const Offset(10.0, 10.0) * devicePixelRatio; + final Offset location = const Offset(10.0, 10.0) * GestureBinding.instance.window.devicePixelRatio; final ui.PointerDataPacket packet = ui.PointerDataPacket( data: [ ui.PointerData(change: ui.PointerChange.add, physicalX: location.dx, physicalY: location.dy), @@ -280,7 +278,7 @@ void main() { ], ); - final List events = PointerEventConverter.expand(packet.data, devicePixelRatio).toList(); + final List events = PointerEventConverter.expand(packet.data, GestureBinding.instance.window.devicePixelRatio).toList(); expect(events.length, 5); expect(events[0], isA()); @@ -296,7 +294,7 @@ void main() { }); test('Should synthesize kPrimaryButton for stylus when no button is set', () { - final Offset location = const Offset(10.0, 10.0) * devicePixelRatio; + final Offset location = const Offset(10.0, 10.0) * GestureBinding.instance.window.devicePixelRatio; for (final PointerDeviceKind kind in [ PointerDeviceKind.stylus, PointerDeviceKind.invertedStylus, @@ -312,7 +310,7 @@ void main() { ], ); - final List events = PointerEventConverter.expand(packet.data, devicePixelRatio).toList(); + final List events = PointerEventConverter.expand(packet.data, GestureBinding.instance.window.devicePixelRatio).toList(); expect(events.length, 5); expect(events[0], isA()); @@ -329,7 +327,7 @@ void main() { }); test('Should synthesize kPrimaryButton for unknown devices when no button is set', () { - final Offset location = const Offset(10.0, 10.0) * devicePixelRatio; + final Offset location = const Offset(10.0, 10.0) * GestureBinding.instance.window.devicePixelRatio; const PointerDeviceKind kind = PointerDeviceKind.unknown; final ui.PointerDataPacket packet = ui.PointerDataPacket( data: [ @@ -341,7 +339,7 @@ void main() { ], ); - final List events = PointerEventConverter.expand(packet.data, devicePixelRatio).toList(); + final List events = PointerEventConverter.expand(packet.data, GestureBinding.instance.window.devicePixelRatio).toList(); expect(events.length, 5); expect(events[0], isA()); @@ -357,7 +355,7 @@ void main() { }); test('Should not synthesize kPrimaryButton for mouse', () { - final Offset location = const Offset(10.0, 10.0) * devicePixelRatio; + final Offset location = const Offset(10.0, 10.0) * GestureBinding.instance.window.devicePixelRatio; for (final PointerDeviceKind kind in [ PointerDeviceKind.mouse, ]) { @@ -371,7 +369,7 @@ void main() { ], ); - final List events = PointerEventConverter.expand(packet.data, devicePixelRatio).toList(); + final List events = PointerEventConverter.expand(packet.data, GestureBinding.instance.window.devicePixelRatio).toList(); expect(events.length, 5); expect(events[0], isA()); diff --git a/packages/flutter/test/gestures/gesture_config_regression_test.dart b/packages/flutter/test/gestures/gesture_config_regression_test.dart index cf2b9aac4fd..6a9fb8b7d01 100644 --- a/packages/flutter/test/gestures/gesture_config_regression_test.dart +++ b/packages/flutter/test/gestures/gesture_config_regression_test.dart @@ -90,9 +90,7 @@ class NestedDraggableCase extends StatelessWidget { void main() { testWidgets('Scroll Views get the same ScrollConfiguration as GestureDetectors', (WidgetTester tester) async { - tester.view.gestureSettings = const ui.GestureSettings(physicalTouchSlop: 4); - addTearDown(tester.view.reset); - + tester.binding.window.gestureSettingsTestValue = const ui.GestureSettings(physicalTouchSlop: 4); final TestResult result = TestResult(); await tester.pumpWidget(MaterialApp( @@ -110,11 +108,11 @@ void main() { expect(result.dragStarted, true); expect(result.dragUpdate, true); + tester.binding.window.clearGestureSettingsTestValue(); }); testWidgets('Scroll Views get the same ScrollConfiguration as Draggables', (WidgetTester tester) async { - tester.view.gestureSettings = const ui.GestureSettings(physicalTouchSlop: 4); - addTearDown(tester.view.reset); + tester.binding.window.gestureSettingsTestValue = const ui.GestureSettings(physicalTouchSlop: 4); final TestResult result = TestResult(); @@ -133,5 +131,6 @@ void main() { expect(result.dragStarted, true); expect(result.dragUpdate, true); + tester.binding.window.clearGestureSettingsTestValue(); }); } diff --git a/packages/flutter/test/material/debug_test.dart b/packages/flutter/test/material/debug_test.dart index 00882c49015..919b3ded16f 100644 --- a/packages/flutter/test/material/debug_test.dart +++ b/packages/flutter/test/material/debug_test.dart @@ -235,7 +235,7 @@ void main() { ' MediaQuery\n' ' _MediaQueryFromView\n' ' _ViewScope\n' - ' View-[GlobalObjectKey TestFlutterView#00000]\n' + ' View-[GlobalObjectKey TestWindow#00000]\n' ' [root]\n' ' Typically, the Scaffold widget is introduced by the MaterialApp\n' ' or WidgetsApp widget at the top of your application widget tree.\n' @@ -376,7 +376,7 @@ void main() { ' MediaQuery\n' ' _MediaQueryFromView\n' ' _ViewScope\n' - ' View-[GlobalObjectKey TestFlutterView#00000]\n' + ' View-[GlobalObjectKey TestWindow#00000]\n' ' [root]\n' ' Typically, the ScaffoldMessenger widget is introduced by the\n' ' MaterialApp at the top of your application widget tree.\n' diff --git a/packages/flutter/test/material/page_test.dart b/packages/flutter/test/material/page_test.dart index f55e07b7ff5..16d002108ea 100644 --- a/packages/flutter/test/material/page_test.dart +++ b/packages/flutter/test/material/page_test.dart @@ -1042,7 +1042,6 @@ void main() { ]; await tester.pumpWidget( buildNavigator( - view: tester.view, pages: myPages, onPopPage: (Route route, dynamic result) { assert(false); // The test should never execute this. @@ -1061,7 +1060,6 @@ void main() { await tester.pumpWidget( buildNavigator( - view: tester.view, pages: myPages, onPopPage: (Route route, dynamic result) { assert(false); // The test should never execute this. @@ -1087,7 +1085,6 @@ void main() { ]; await tester.pumpWidget( buildNavigator( - view: tester.view, pages: myPages, onPopPage: (Route route, dynamic result) { assert(false); // The test should never execute this. @@ -1109,7 +1106,6 @@ void main() { await tester.pumpWidget( buildNavigator( - view: tester.view, pages: myPages, onPopPage: (Route route, dynamic result) { assert(false); // The test should never execute this. @@ -1218,12 +1214,11 @@ class TransitionDetector extends DefaultTransitionDelegate { Widget buildNavigator({ required List> pages, required PopPageCallback onPopPage, - required ui.FlutterView view, GlobalKey? key, TransitionDelegate? transitionDelegate, }) { return MediaQuery( - data: MediaQueryData.fromView(view), + data: MediaQueryData.fromView(WidgetsBinding.instance.window), child: Localizations( locale: const Locale('en', 'US'), delegates: const >[ diff --git a/packages/flutter/test/material/scaffold_test.dart b/packages/flutter/test/material/scaffold_test.dart index 3f040b1f658..a8167bbab97 100644 --- a/packages/flutter/test/material/scaffold_test.dart +++ b/packages/flutter/test/material/scaffold_test.dart @@ -2454,7 +2454,7 @@ void main() { ' MediaQuery\n' ' _MediaQueryFromView\n' ' _ViewScope\n' - ' View-[GlobalObjectKey TestFlutterView#e6136]\n' + ' View-[GlobalObjectKey TestWindow#e6136]\n' ' [root]\n' ' Typically, the ScaffoldMessenger widget is introduced by the\n' ' MaterialApp at the top of your application widget tree.\n', diff --git a/packages/flutter/test/painting/paint_image_test.dart b/packages/flutter/test/painting/paint_image_test.dart index bc83e465c42..f4787d8eb61 100644 --- a/packages/flutter/test/painting/paint_image_test.dart +++ b/packages/flutter/test/painting/paint_image_test.dart @@ -52,7 +52,7 @@ void main() { test('debugInvertOversizedImages', () async { debugInvertOversizedImages = true; - expect(PaintingBinding.instance.platformDispatcher.views.any((ui. FlutterView view) => view.devicePixelRatio > 1.0), isTrue); + expect(PaintingBinding.instance.window.devicePixelRatio != 1.0, true); final FlutterExceptionHandler? oldFlutterError = FlutterError.onError; final List messages = []; @@ -180,7 +180,7 @@ void main() { expect(imageSizeInfo, isNotNull); expect(imageSizeInfo.source, 'test.png'); expect(imageSizeInfo.imageSize, const Size(300, 300)); - expect(imageSizeInfo.displaySize, const Size(200, 100) * tester.view.devicePixelRatio); + expect(imageSizeInfo.displaySize, const Size(200, 100) * PaintingBinding.instance.window.devicePixelRatio); // Make sure that we don't report an identical image size info if we // redraw in the next frame. @@ -219,7 +219,7 @@ void main() { expect(imageSizeInfo, isNotNull); expect(imageSizeInfo.source, 'test.png'); expect(imageSizeInfo.imageSize, const Size(300, 300)); - expect(imageSizeInfo.displaySize, const Size(200, 100) * tester.view.devicePixelRatio); + expect(imageSizeInfo.displaySize, const Size(200, 100) * PaintingBinding.instance.window.devicePixelRatio); // Make sure that we don't report an identical image size info if we // redraw in the next frame. @@ -237,7 +237,7 @@ void main() { expect(imageSizeInfo, isNotNull); expect(imageSizeInfo.source, 'test.png'); expect(imageSizeInfo.imageSize, const Size(300, 300)); - expect(imageSizeInfo.displaySize, const Size(200, 150) * tester.view.devicePixelRatio); + expect(imageSizeInfo.displaySize, const Size(200, 150) * PaintingBinding.instance.window.devicePixelRatio); debugOnPaintImage = null; }); @@ -261,7 +261,7 @@ void main() { expect(imageSizeInfo, isNotNull); expect(imageSizeInfo.source, ''); expect(imageSizeInfo.imageSize, const Size(300, 200)); - expect(imageSizeInfo.displaySize, const Size(200, 100) * tester.view.devicePixelRatio); + expect(imageSizeInfo.displaySize, const Size(200, 100) * PaintingBinding.instance.window.devicePixelRatio); debugOnPaintImage = null; }); diff --git a/packages/flutter/test/rendering/independent_layout_test.dart b/packages/flutter/test/rendering/independent_layout_test.dart index 64cb9465b5d..a9ec271ec46 100644 --- a/packages/flutter/test/rendering/independent_layout_test.dart +++ b/packages/flutter/test/rendering/independent_layout_test.dart @@ -44,7 +44,7 @@ void main() { expect(offscreen.child.hasSize, isFalse); expect(offscreen.painted, isFalse); // Attach the offscreen to a custom render view and owner - final RenderView renderView = RenderView(configuration: testConfiguration, window: RendererBinding.instance.platformDispatcher.views.single); + final RenderView renderView = RenderView(configuration: testConfiguration, window: RendererBinding.instance.window); final PipelineOwner pipelineOwner = PipelineOwner(); renderView.attach(pipelineOwner); renderView.child = offscreen.root; @@ -66,7 +66,6 @@ void main() { pipelineOwner.flushPaint(); expect(offscreen.painted, isTrue); }); - test('offscreen layout does not affect onscreen', () { final TestLayout onscreen = TestLayout(); final TestLayout offscreen = TestLayout(); @@ -75,7 +74,7 @@ void main() { expect(offscreen.child.hasSize, isFalse); expect(offscreen.painted, isFalse); // Attach the offscreen to a custom render view and owner - final RenderView renderView = RenderView(configuration: testConfiguration, window: RendererBinding.instance.platformDispatcher.views.single); + final RenderView renderView = RenderView(configuration: testConfiguration, window: RendererBinding.instance.window); final PipelineOwner pipelineOwner = PipelineOwner(); renderView.attach(pipelineOwner); renderView.child = offscreen.root; diff --git a/packages/flutter/test/rendering/layers_test.dart b/packages/flutter/test/rendering/layers_test.dart index ef89f0e0e4d..f8c4bf58e15 100644 --- a/packages/flutter/test/rendering/layers_test.dart +++ b/packages/flutter/test/rendering/layers_test.dart @@ -169,7 +169,7 @@ void main() { test('switching layer link of an attached leader layer should not crash', () { final LayerLink link = LayerLink(); final LeaderLayer leaderLayer = LeaderLayer(link: link); - final RenderView view = RenderView(configuration: const ViewConfiguration(), window: RendererBinding.instance.platformDispatcher.views.single); + final RenderView view = RenderView(configuration: const ViewConfiguration(), window: RendererBinding.instance.window); leaderLayer.attach(view); final LayerLink link2 = LayerLink(); leaderLayer.link = link2; @@ -182,7 +182,7 @@ void main() { final LayerLink link = LayerLink(); final LeaderLayer leaderLayer1 = LeaderLayer(link: link); final LeaderLayer leaderLayer2 = LeaderLayer(link: link); - final RenderView view = RenderView(configuration: const ViewConfiguration(), window: RendererBinding.instance.platformDispatcher.views.single); + final RenderView view = RenderView(configuration: const ViewConfiguration(), window: RendererBinding.instance.window); leaderLayer1.attach(view); leaderLayer2.attach(view); leaderLayer2.detach(); diff --git a/packages/flutter/test/rendering/view_chrome_style_test.dart b/packages/flutter/test/rendering/view_chrome_style_test.dart index 0d56c3ad8a6..91be41ae37a 100644 --- a/packages/flutter/test/rendering/view_chrome_style_test.dart +++ b/packages/flutter/test/rendering/view_chrome_style_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:ui'; + import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -14,18 +16,18 @@ void main() { const double deviceWidth = 480.0; const double devicePixelRatio = 2.0; - void setupTestDevice(WidgetTester tester) { + void setupTestDevice() { + final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized(); const FakeViewPadding padding = FakeViewPadding( top: statusBarHeight * devicePixelRatio, bottom: navigationBarHeight * devicePixelRatio, ); - addTearDown(tester.view.reset); - tester.view - ..viewPadding = padding - ..padding = padding - ..devicePixelRatio = devicePixelRatio - ..physicalSize = const Size( + binding.window + ..viewPaddingTestValue = padding + ..paddingTestValue = padding + ..devicePixelRatioTestValue = devicePixelRatio + ..physicalSizeTestValue = const Size( deviceWidth * devicePixelRatio, deviceHeight * devicePixelRatio, ); @@ -50,7 +52,7 @@ void main() { testWidgets( 'statusBarColor is set for annotated view', (WidgetTester tester) async { - setupTestDevice(tester); + setupTestDevice(); await tester.pumpWidget(const AnnotatedRegion( value: SystemUiOverlayStyle( statusBarColor: Colors.blue, @@ -70,7 +72,7 @@ void main() { testWidgets( "statusBarColor isn't set when view covers less than half of the system status bar", (WidgetTester tester) async { - setupTestDevice(tester); + setupTestDevice(); const double lessThanHalfOfTheStatusBarHeight = statusBarHeight / 2.0 - 1; await tester.pumpWidget(const Align( @@ -95,7 +97,7 @@ void main() { testWidgets( 'statusBarColor is set when view covers more than half of tye system status bar', (WidgetTester tester) async { - setupTestDevice(tester); + setupTestDevice(); const double moreThanHalfOfTheStatusBarHeight = statusBarHeight / 2.0 + 1; await tester.pumpWidget(const Align( @@ -125,7 +127,7 @@ void main() { testWidgets( "systemNavigationBarColor isn't set for non Android device", (WidgetTester tester) async { - setupTestDevice(tester); + setupTestDevice(); await tester.pumpWidget(const AnnotatedRegion( value: SystemUiOverlayStyle( systemNavigationBarColor: Colors.blue, @@ -156,7 +158,7 @@ void main() { testWidgets( 'systemNavigationBarColor is set for annotated view', (WidgetTester tester) async { - setupTestDevice(tester); + setupTestDevice(); await tester.pumpWidget(const AnnotatedRegion( value: SystemUiOverlayStyle( systemNavigationBarColor: Colors.blue, @@ -176,7 +178,7 @@ void main() { testWidgets( "systemNavigationBarColor isn't set when view covers less than half of navigation bar", (WidgetTester tester) async { - setupTestDevice(tester); + setupTestDevice(); const double lessThanHalfOfTheNavigationBarHeight = navigationBarHeight / 2.0 - 1; await tester.pumpWidget(const Align( @@ -201,7 +203,7 @@ void main() { testWidgets( 'systemNavigationBarColor is set when view covers more than half of navigation bar', (WidgetTester tester) async { - setupTestDevice(tester); + setupTestDevice(); const double moreThanHalfOfTheNavigationBarHeight = navigationBarHeight / 2.0 + 1; await tester.pumpWidget(const Align( @@ -228,7 +230,7 @@ void main() { }); testWidgets('Top AnnotatedRegion provides status bar overlay style and bottom AnnotatedRegion provides navigation bar overlay style', (WidgetTester tester) async { - setupTestDevice(tester); + setupTestDevice(); await tester.pumpWidget( const Column(children: [ Expanded(child: AnnotatedRegion( @@ -254,7 +256,7 @@ void main() { }, variant: TargetPlatformVariant.only(TargetPlatform.android)); testWidgets('Top only AnnotatedRegion provides status bar and navigation bar style properties', (WidgetTester tester) async { - setupTestDevice(tester); + setupTestDevice(); await tester.pumpWidget( const Column(children: [ Expanded(child: AnnotatedRegion( @@ -274,7 +276,7 @@ void main() { }, variant: TargetPlatformVariant.only(TargetPlatform.android)); testWidgets('Bottom only AnnotatedRegion provides status bar and navigation bar style properties', (WidgetTester tester) async { - setupTestDevice(tester); + setupTestDevice(); await tester.pumpWidget( const Column(children: [ Expanded(child: SizedBox.expand()), @@ -294,3 +296,21 @@ void main() { }, variant: TargetPlatformVariant.only(TargetPlatform.android)); }); } + +class FakeViewPadding implements ViewPadding { + const FakeViewPadding({ + this.left = 0.0, + this.top = 0.0, + this.right = 0.0, + this.bottom = 0.0, + }); + + @override + final double left; + @override + final double top; + @override + final double right; + @override + final double bottom; +} diff --git a/packages/flutter/test/rendering/view_test.dart b/packages/flutter/test/rendering/view_test.dart index 94097ae690c..52e3de57f51 100644 --- a/packages/flutter/test/rendering/view_test.dart +++ b/packages/flutter/test/rendering/view_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:ui' as ui; + import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -30,9 +32,10 @@ void main() { }); test('does not replace the root layer unnecessarily', () { + final ui.FlutterView window = TestWindow(window: RendererBinding.instance.window); final RenderView view = RenderView( configuration: createViewConfiguration(), - window: RendererBinding.instance.platformDispatcher.views.single, + window: window, ); final PipelineOwner owner = PipelineOwner(); view.attach(owner); @@ -45,10 +48,11 @@ void main() { expect(identical(view.debugLayer, firstLayer), false); }); - test('does not replace the root layer unnecessarily when view resizes', () { + test('does not replace the root layer unnecessarily when window resize', () { + final ui.FlutterView window = TestWindow(window: RendererBinding.instance.window); final RenderView view = RenderView( configuration: createViewConfiguration(size: const Size(100.0, 100.0)), - window: RendererBinding.instance.platformDispatcher.views.single, + window: window, ); final PipelineOwner owner = PipelineOwner(); view.attach(owner); diff --git a/packages/flutter/test/rendering/viewport_test.dart b/packages/flutter/test/rendering/viewport_test.dart index e69057ace86..ea33ccc5f51 100644 --- a/packages/flutter/test/rendering/viewport_test.dart +++ b/packages/flutter/test/rendering/viewport_test.dart @@ -10,6 +10,8 @@ @Tags(['reduced-test-set']) library; +import 'dart:ui' as ui; + import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; @@ -780,14 +782,19 @@ void main() { } testWidgets('Reverse List showOnScreen', (WidgetTester tester) async { - addTearDown(tester.view.reset); + final ui.Size originalScreenSize = tester.binding.window.physicalSize; + final double originalDevicePixelRatio = tester.binding.window.devicePixelRatio; + addTearDown(() { + tester.binding.window.devicePixelRatioTestValue = originalDevicePixelRatio; + tester.binding.window.physicalSizeTestValue = originalScreenSize; + }); const double screenHeight = 400.0; const double screenWidth = 400.0; const double itemHeight = screenHeight / 10.0; const ValueKey centerKey = ValueKey('center'); - tester.view.devicePixelRatio = 1.0; - tester.view.physicalSize = const Size(screenWidth, screenHeight); + tester.binding.window.devicePixelRatioTestValue = 1.0; + tester.binding.window.physicalSizeTestValue = const Size(screenWidth, screenHeight); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/annotated_region_test.dart b/packages/flutter/test/widgets/annotated_region_test.dart index ec159c90a11..e91a39dd503 100644 --- a/packages/flutter/test/widgets/annotated_region_test.dart +++ b/packages/flutter/test/widgets/annotated_region_test.dart @@ -29,13 +29,13 @@ void main() { ), ); int? result = RendererBinding.instance.renderView.debugLayer!.find(Offset( - 10.0 * tester.view.devicePixelRatio, - 10.0 * tester.view.devicePixelRatio, + 10.0 * RendererBinding.instance.window.devicePixelRatio, + 10.0 * RendererBinding.instance.window.devicePixelRatio, )); expect(result, null); result = RendererBinding.instance.renderView.debugLayer!.find(Offset( - 50.0 * tester.view.devicePixelRatio, - 50.0 * tester.view.devicePixelRatio, + 50.0 * RendererBinding.instance.window.devicePixelRatio, + 50.0 * RendererBinding.instance.window.devicePixelRatio, )); expect(result, 1); }); diff --git a/packages/flutter/test/widgets/container_test.dart b/packages/flutter/test/widgets/container_test.dart index 7c327bc9754..28c3ef6419a 100644 --- a/packages/flutter/test/widgets/container_test.dart +++ b/packages/flutter/test/widgets/container_test.dart @@ -13,7 +13,7 @@ import 'package:flutter_test/flutter_test.dart'; import '../rendering/mock_canvas.dart'; void main() { - group('Container control tests:', () { + testWidgets('Container control test', (WidgetTester tester) async { final Container container = Container( alignment: Alignment.bottomRight, padding: const EdgeInsets.all(7.0), @@ -39,522 +39,457 @@ void main() { ), ); - testWidgets('paints as expected', (WidgetTester tester) async { - await tester.pumpWidget(Align( - alignment: Alignment.topLeft, - child: container, - )); + expect(container, hasOneLineDescription); - final RenderBox box = tester.renderObject(find.byType(Container)); - expect(box, isNotNull); + await tester.pumpWidget(Align( + alignment: Alignment.topLeft, + child: container, + )); - expect(box, paints - ..rect(rect: const Rect.fromLTWH(5.0, 5.0, 53.0, 78.0), color: const Color(0xFF00FF00)) - ..rect(rect: const Rect.fromLTWH(26.0, 43.0, 25.0, 33.0), color: const Color(0xFFFFFF00)) - ..rect(rect: const Rect.fromLTWH(5.0, 5.0, 53.0, 78.0), color: const Color(0x7F0000FF)), - ); - }); + final RenderBox box = tester.renderObject(find.byType(Container)); + expect(box, isNotNull); - group('diagnostics', () { - testWidgets('has reasonable default diagnostics', (WidgetTester tester) async { - await tester.pumpWidget(Align( - alignment: Alignment.topLeft, - child: container, - )); + expect(box, paints + ..rect(rect: const Rect.fromLTWH(5.0, 5.0, 53.0, 78.0), color: const Color(0xFF00FF00)) + ..rect(rect: const Rect.fromLTWH(26.0, 43.0, 25.0, 33.0), color: const Color(0xFFFFFF00)) + ..rect(rect: const Rect.fromLTWH(5.0, 5.0, 53.0, 78.0), color: const Color(0x7F0000FF)), + ); - final RenderBox box = tester.renderObject(find.byType(Container)); + expect(box, hasAGoodToStringDeep); + expect( + box.toStringDeep(minLevel: DiagnosticLevel.info), + equalsIgnoringHashCodes( + 'RenderPadding#00000 relayoutBoundary=up1\n' + ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n' + ' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n' + ' │ size: Size(63.0, 88.0)\n' + ' │ padding: EdgeInsets.all(5.0)\n' + ' │\n' + ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up2\n' + ' │ parentData: offset=Offset(5.0, 5.0) (can use size)\n' + ' │ constraints: BoxConstraints(0.0<=w<=790.0, 0.0<=h<=590.0)\n' + ' │ size: Size(53.0, 78.0)\n' + ' │ additionalConstraints: BoxConstraints(w=53.0, h=78.0)\n' + ' │\n' + ' └─child: RenderDecoratedBox#00000\n' + ' │ parentData: (can use size)\n' + ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' + ' │ size: Size(53.0, 78.0)\n' + ' │ decoration: BoxDecoration:\n' + ' │ color: Color(0x7f0000ff)\n' + ' │ configuration: ImageConfiguration(bundle:\n' + ' │ PlatformAssetBundle#00000(), devicePixelRatio: 3.0, platform:\n' + ' │ android)\n' + ' │\n' + ' └─child: _RenderColoredBox#00000\n' + ' │ parentData: (can use size)\n' + ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' + ' │ size: Size(53.0, 78.0)\n' + ' │ behavior: opaque\n' + ' │\n' + ' └─child: RenderPadding#00000\n' + ' │ parentData: (can use size)\n' + ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' + ' │ size: Size(53.0, 78.0)\n' + ' │ padding: EdgeInsets.all(7.0)\n' + ' │\n' + ' └─child: RenderPositionedBox#00000\n' + ' │ parentData: offset=Offset(7.0, 7.0) (can use size)\n' + ' │ constraints: BoxConstraints(w=39.0, h=64.0)\n' + ' │ size: Size(39.0, 64.0)\n' + ' │ alignment: Alignment.bottomRight\n' + ' │ widthFactor: expand\n' + ' │ heightFactor: expand\n' + ' │\n' + ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up1\n' + ' │ parentData: offset=Offset(14.0, 31.0) (can use size)\n' + ' │ constraints: BoxConstraints(0.0<=w<=39.0, 0.0<=h<=64.0)\n' + ' │ size: Size(25.0, 33.0)\n' + ' │ additionalConstraints: BoxConstraints(w=25.0, h=33.0)\n' + ' │\n' + ' └─child: RenderDecoratedBox#00000\n' + ' parentData: (can use size)\n' + ' constraints: BoxConstraints(w=25.0, h=33.0)\n' + ' size: Size(25.0, 33.0)\n' + ' decoration: BoxDecoration:\n' + ' color: Color(0xffffff00)\n' + ' configuration: ImageConfiguration(bundle:\n' + ' PlatformAssetBundle#00000(), devicePixelRatio: 3.0, platform:\n' + ' android)\n', + ), + ); - expect(container, hasOneLineDescription); - expect(box, hasAGoodToStringDeep); - }); + expect( + box.toStringDeep(), + equalsIgnoringHashCodes( + 'RenderPadding#00000 relayoutBoundary=up1\n' + ' │ creator: Padding ← Container ← Align ← MediaQuery ←\n' + ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' + ' │ TestWindow#00000] ← [root]\n' + ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n' + ' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n' + ' │ size: Size(63.0, 88.0)\n' + ' │ padding: EdgeInsets.all(5.0)\n' + ' │\n' + ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up2\n' + ' │ creator: ConstrainedBox ← Padding ← Container ← Align ←\n' + ' │ MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' + ' │ View-[GlobalObjectKey TestWindow#00000] ← [root]\n' + ' │ parentData: offset=Offset(5.0, 5.0) (can use size)\n' + ' │ constraints: BoxConstraints(0.0<=w<=790.0, 0.0<=h<=590.0)\n' + ' │ size: Size(53.0, 78.0)\n' + ' │ additionalConstraints: BoxConstraints(w=53.0, h=78.0)\n' + ' │\n' + ' └─child: RenderDecoratedBox#00000\n' + ' │ creator: DecoratedBox ← ConstrainedBox ← Padding ← Container ←\n' + ' │ Align ← MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' + ' │ View-[GlobalObjectKey TestWindow#00000] ← [root]\n' + ' │ parentData: (can use size)\n' + ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' + ' │ size: Size(53.0, 78.0)\n' + ' │ decoration: BoxDecoration:\n' + ' │ color: Color(0x7f0000ff)\n' + ' │ configuration: ImageConfiguration(bundle:\n' + ' │ PlatformAssetBundle#00000(), devicePixelRatio: 3.0, platform:\n' + ' │ android)\n' + ' │\n' + ' └─child: _RenderColoredBox#00000\n' + ' │ creator: ColoredBox ← DecoratedBox ← ConstrainedBox ← Padding ←\n' + ' │ Container ← Align ← MediaQuery ← _MediaQueryFromView ←\n' + ' │ _ViewScope ← View-[GlobalObjectKey TestWindow#00000] ← [root]\n' + ' │ parentData: (can use size)\n' + ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' + ' │ size: Size(53.0, 78.0)\n' + ' │ behavior: opaque\n' + ' │\n' + ' └─child: RenderPadding#00000\n' + ' │ creator: Padding ← ColoredBox ← DecoratedBox ← ConstrainedBox ←\n' + ' │ Padding ← Container ← Align ← MediaQuery ← _MediaQueryFromView\n' + ' │ ← _ViewScope ← View-[GlobalObjectKey TestWindow#00000] ← [root]\n' + ' │ parentData: (can use size)\n' + ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' + ' │ size: Size(53.0, 78.0)\n' + ' │ padding: EdgeInsets.all(7.0)\n' + ' │\n' + ' └─child: RenderPositionedBox#00000\n' + ' │ creator: Align ← Padding ← ColoredBox ← DecoratedBox ←\n' + ' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n' + ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' + ' │ TestWindow#00000] ← ⋯\n' + ' │ parentData: offset=Offset(7.0, 7.0) (can use size)\n' + ' │ constraints: BoxConstraints(w=39.0, h=64.0)\n' + ' │ size: Size(39.0, 64.0)\n' + ' │ alignment: Alignment.bottomRight\n' + ' │ widthFactor: expand\n' + ' │ heightFactor: expand\n' + ' │\n' + ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up1\n' + ' │ creator: SizedBox ← Align ← Padding ← ColoredBox ← DecoratedBox ←\n' + ' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n' + ' │ _MediaQueryFromView ← _ViewScope ← ⋯\n' + ' │ parentData: offset=Offset(14.0, 31.0) (can use size)\n' + ' │ constraints: BoxConstraints(0.0<=w<=39.0, 0.0<=h<=64.0)\n' + ' │ size: Size(25.0, 33.0)\n' + ' │ additionalConstraints: BoxConstraints(w=25.0, h=33.0)\n' + ' │\n' + ' └─child: RenderDecoratedBox#00000\n' + ' creator: DecoratedBox ← SizedBox ← Align ← Padding ← ColoredBox ←\n' + ' DecoratedBox ← ConstrainedBox ← Padding ← Container ← Align ←\n' + ' MediaQuery ← _MediaQueryFromView ← ⋯\n' + ' parentData: (can use size)\n' + ' constraints: BoxConstraints(w=25.0, h=33.0)\n' + ' size: Size(25.0, 33.0)\n' + ' decoration: BoxDecoration:\n' + ' color: Color(0xffffff00)\n' + ' configuration: ImageConfiguration(bundle:\n' + ' PlatformAssetBundle#00000(), devicePixelRatio: 3.0, platform:\n' + ' android)\n', + ), + ); - testWidgets('has expected info diagnostics', (WidgetTester tester) async { - await tester.pumpWidget(Align( - alignment: Alignment.topLeft, - child: container, - )); + expect( + box.toStringDeep(minLevel: DiagnosticLevel.fine), + equalsIgnoringHashCodes( + 'RenderPadding#00000 relayoutBoundary=up1\n' + ' │ creator: Padding ← Container ← Align ← MediaQuery ←\n' + ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' + ' │ TestWindow#00000] ← [root]\n' + ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n' + ' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n' + ' │ layer: null\n' + ' │ semantics node: null\n' + ' │ size: Size(63.0, 88.0)\n' + ' │ padding: EdgeInsets.all(5.0)\n' + ' │ textDirection: null\n' + ' │\n' + ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up2\n' + ' │ creator: ConstrainedBox ← Padding ← Container ← Align ←\n' + ' │ MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' + ' │ View-[GlobalObjectKey TestWindow#00000] ← [root]\n' + ' │ parentData: offset=Offset(5.0, 5.0) (can use size)\n' + ' │ constraints: BoxConstraints(0.0<=w<=790.0, 0.0<=h<=590.0)\n' + ' │ layer: null\n' + ' │ semantics node: null\n' + ' │ size: Size(53.0, 78.0)\n' + ' │ additionalConstraints: BoxConstraints(w=53.0, h=78.0)\n' + ' │\n' + ' └─child: RenderDecoratedBox#00000\n' + ' │ creator: DecoratedBox ← ConstrainedBox ← Padding ← Container ←\n' + ' │ Align ← MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' + ' │ View-[GlobalObjectKey TestWindow#00000] ← [root]\n' + ' │ parentData: (can use size)\n' + ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' + ' │ layer: null\n' + ' │ semantics node: null\n' + ' │ size: Size(53.0, 78.0)\n' + ' │ decoration: BoxDecoration:\n' + ' │ color: Color(0x7f0000ff)\n' + ' │ image: null\n' + ' │ border: null\n' + ' │ borderRadius: null\n' + ' │ boxShadow: null\n' + ' │ gradient: null\n' + ' │ shape: rectangle\n' + ' │ configuration: ImageConfiguration(bundle:\n' + ' │ PlatformAssetBundle#00000(), devicePixelRatio: 3.0, platform:\n' + ' │ android)\n' + ' │\n' + ' └─child: _RenderColoredBox#00000\n' + ' │ creator: ColoredBox ← DecoratedBox ← ConstrainedBox ← Padding ←\n' + ' │ Container ← Align ← MediaQuery ← _MediaQueryFromView ←\n' + ' │ _ViewScope ← View-[GlobalObjectKey TestWindow#00000] ← [root]\n' + ' │ parentData: (can use size)\n' + ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' + ' │ layer: null\n' + ' │ semantics node: null\n' + ' │ size: Size(53.0, 78.0)\n' + ' │ behavior: opaque\n' + ' │\n' + ' └─child: RenderPadding#00000\n' + ' │ creator: Padding ← ColoredBox ← DecoratedBox ← ConstrainedBox ←\n' + ' │ Padding ← Container ← Align ← MediaQuery ← _MediaQueryFromView\n' + ' │ ← _ViewScope ← View-[GlobalObjectKey TestWindow#00000] ← [root]\n' + ' │ parentData: (can use size)\n' + ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' + ' │ layer: null\n' + ' │ semantics node: null\n' + ' │ size: Size(53.0, 78.0)\n' + ' │ padding: EdgeInsets.all(7.0)\n' + ' │ textDirection: null\n' + ' │\n' + ' └─child: RenderPositionedBox#00000\n' + ' │ creator: Align ← Padding ← ColoredBox ← DecoratedBox ←\n' + ' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n' + ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' + ' │ TestWindow#00000] ← ⋯\n' + ' │ parentData: offset=Offset(7.0, 7.0) (can use size)\n' + ' │ constraints: BoxConstraints(w=39.0, h=64.0)\n' + ' │ layer: null\n' + ' │ semantics node: null\n' + ' │ size: Size(39.0, 64.0)\n' + ' │ alignment: Alignment.bottomRight\n' + ' │ textDirection: null\n' + ' │ widthFactor: expand\n' + ' │ heightFactor: expand\n' + ' │\n' + ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up1\n' + ' │ creator: SizedBox ← Align ← Padding ← ColoredBox ← DecoratedBox ←\n' + ' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n' + ' │ _MediaQueryFromView ← _ViewScope ← ⋯\n' + ' │ parentData: offset=Offset(14.0, 31.0) (can use size)\n' + ' │ constraints: BoxConstraints(0.0<=w<=39.0, 0.0<=h<=64.0)\n' + ' │ layer: null\n' + ' │ semantics node: null\n' + ' │ size: Size(25.0, 33.0)\n' + ' │ additionalConstraints: BoxConstraints(w=25.0, h=33.0)\n' + ' │\n' + ' └─child: RenderDecoratedBox#00000\n' + ' creator: DecoratedBox ← SizedBox ← Align ← Padding ← ColoredBox ←\n' + ' DecoratedBox ← ConstrainedBox ← Padding ← Container ← Align ←\n' + ' MediaQuery ← _MediaQueryFromView ← ⋯\n' + ' parentData: (can use size)\n' + ' constraints: BoxConstraints(w=25.0, h=33.0)\n' + ' layer: null\n' + ' semantics node: null\n' + ' size: Size(25.0, 33.0)\n' + ' decoration: BoxDecoration:\n' + ' color: Color(0xffffff00)\n' + ' image: null\n' + ' border: null\n' + ' borderRadius: null\n' + ' boxShadow: null\n' + ' gradient: null\n' + ' shape: rectangle\n' + ' configuration: ImageConfiguration(bundle:\n' + ' PlatformAssetBundle#00000(), devicePixelRatio: 3.0, platform:\n' + ' android)\n', + ), + ); - final RenderBox box = tester.renderObject(find.byType(Container)); + expect( + box.toStringDeep(minLevel: DiagnosticLevel.hidden), + equalsIgnoringHashCodes( + 'RenderPadding#00000 relayoutBoundary=up1\n' + ' │ needsCompositing: false\n' + ' │ creator: Padding ← Container ← Align ← MediaQuery ←\n' + ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' + ' │ TestWindow#00000] ← [root]\n' + ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n' + ' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n' + ' │ layer: null\n' + ' │ semantics node: null\n' + ' │ isBlockingSemanticsOfPreviouslyPaintedNodes: false\n' + ' │ isSemanticBoundary: false\n' + ' │ size: Size(63.0, 88.0)\n' + ' │ padding: EdgeInsets.all(5.0)\n' + ' │ textDirection: null\n' + ' │\n' + ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up2\n' + ' │ needsCompositing: false\n' + ' │ creator: ConstrainedBox ← Padding ← Container ← Align ←\n' + ' │ MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' + ' │ View-[GlobalObjectKey TestWindow#00000] ← [root]\n' + ' │ parentData: offset=Offset(5.0, 5.0) (can use size)\n' + ' │ constraints: BoxConstraints(0.0<=w<=790.0, 0.0<=h<=590.0)\n' + ' │ layer: null\n' + ' │ semantics node: null\n' + ' │ isBlockingSemanticsOfPreviouslyPaintedNodes: false\n' + ' │ isSemanticBoundary: false\n' + ' │ size: Size(53.0, 78.0)\n' + ' │ additionalConstraints: BoxConstraints(w=53.0, h=78.0)\n' + ' │\n' + ' └─child: RenderDecoratedBox#00000\n' + ' │ needsCompositing: false\n' + ' │ creator: DecoratedBox ← ConstrainedBox ← Padding ← Container ←\n' + ' │ Align ← MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' + ' │ View-[GlobalObjectKey TestWindow#00000] ← [root]\n' + ' │ parentData: (can use size)\n' + ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' + ' │ layer: null\n' + ' │ semantics node: null\n' + ' │ isBlockingSemanticsOfPreviouslyPaintedNodes: false\n' + ' │ isSemanticBoundary: false\n' + ' │ size: Size(53.0, 78.0)\n' + ' │ decoration: BoxDecoration:\n' + ' │ color: Color(0x7f0000ff)\n' + ' │ image: null\n' + ' │ border: null\n' + ' │ borderRadius: null\n' + ' │ boxShadow: null\n' + ' │ gradient: null\n' + ' │ shape: rectangle\n' + ' │ configuration: ImageConfiguration(bundle:\n' + ' │ PlatformAssetBundle#00000(), devicePixelRatio: 3.0, platform:\n' + ' │ android)\n' + ' │\n' + ' └─child: _RenderColoredBox#00000\n' + ' │ needsCompositing: false\n' + ' │ creator: ColoredBox ← DecoratedBox ← ConstrainedBox ← Padding ←\n' + ' │ Container ← Align ← MediaQuery ← _MediaQueryFromView ←\n' + ' │ _ViewScope ← View-[GlobalObjectKey TestWindow#00000] ← [root]\n' + ' │ parentData: (can use size)\n' + ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' + ' │ layer: null\n' + ' │ semantics node: null\n' + ' │ isBlockingSemanticsOfPreviouslyPaintedNodes: false\n' + ' │ isSemanticBoundary: false\n' + ' │ size: Size(53.0, 78.0)\n' + ' │ behavior: opaque\n' + ' │\n' + ' └─child: RenderPadding#00000\n' + ' │ needsCompositing: false\n' + ' │ creator: Padding ← ColoredBox ← DecoratedBox ← ConstrainedBox ←\n' + ' │ Padding ← Container ← Align ← MediaQuery ← _MediaQueryFromView\n' + ' │ ← _ViewScope ← View-[GlobalObjectKey TestWindow#00000] ← [root]\n' + ' │ parentData: (can use size)\n' + ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' + ' │ layer: null\n' + ' │ semantics node: null\n' + ' │ isBlockingSemanticsOfPreviouslyPaintedNodes: false\n' + ' │ isSemanticBoundary: false\n' + ' │ size: Size(53.0, 78.0)\n' + ' │ padding: EdgeInsets.all(7.0)\n' + ' │ textDirection: null\n' + ' │\n' + ' └─child: RenderPositionedBox#00000\n' + ' │ needsCompositing: false\n' + ' │ creator: Align ← Padding ← ColoredBox ← DecoratedBox ←\n' + ' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n' + ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' + ' │ TestWindow#00000] ← ⋯\n' + ' │ parentData: offset=Offset(7.0, 7.0) (can use size)\n' + ' │ constraints: BoxConstraints(w=39.0, h=64.0)\n' + ' │ layer: null\n' + ' │ semantics node: null\n' + ' │ isBlockingSemanticsOfPreviouslyPaintedNodes: false\n' + ' │ isSemanticBoundary: false\n' + ' │ size: Size(39.0, 64.0)\n' + ' │ alignment: Alignment.bottomRight\n' + ' │ textDirection: null\n' + ' │ widthFactor: expand\n' + ' │ heightFactor: expand\n' + ' │\n' + ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up1\n' + ' │ needsCompositing: false\n' + ' │ creator: SizedBox ← Align ← Padding ← ColoredBox ← DecoratedBox ←\n' + ' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n' + ' │ _MediaQueryFromView ← _ViewScope ← ⋯\n' + ' │ parentData: offset=Offset(14.0, 31.0) (can use size)\n' + ' │ constraints: BoxConstraints(0.0<=w<=39.0, 0.0<=h<=64.0)\n' + ' │ layer: null\n' + ' │ semantics node: null\n' + ' │ isBlockingSemanticsOfPreviouslyPaintedNodes: false\n' + ' │ isSemanticBoundary: false\n' + ' │ size: Size(25.0, 33.0)\n' + ' │ additionalConstraints: BoxConstraints(w=25.0, h=33.0)\n' + ' │\n' + ' └─child: RenderDecoratedBox#00000\n' + ' needsCompositing: false\n' + ' creator: DecoratedBox ← SizedBox ← Align ← Padding ← ColoredBox ←\n' + ' DecoratedBox ← ConstrainedBox ← Padding ← Container ← Align ←\n' + ' MediaQuery ← _MediaQueryFromView ← ⋯\n' + ' parentData: (can use size)\n' + ' constraints: BoxConstraints(w=25.0, h=33.0)\n' + ' layer: null\n' + ' semantics node: null\n' + ' isBlockingSemanticsOfPreviouslyPaintedNodes: false\n' + ' isSemanticBoundary: false\n' + ' size: Size(25.0, 33.0)\n' + ' decoration: BoxDecoration:\n' + ' color: Color(0xffffff00)\n' + ' image: null\n' + ' border: null\n' + ' borderRadius: null\n' + ' boxShadow: null\n' + ' gradient: null\n' + ' shape: rectangle\n' + ' configuration: ImageConfiguration(bundle:\n' + ' PlatformAssetBundle#00000(), devicePixelRatio: 3.0, platform:\n' + ' android)\n', + ), + ); - expect( - box.toStringDeep(minLevel: DiagnosticLevel.info), - equalsIgnoringHashCodes( - 'RenderPadding#00000 relayoutBoundary=up1\n' - ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n' - ' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n' - ' │ size: Size(63.0, 88.0)\n' - ' │ padding: EdgeInsets.all(5.0)\n' - ' │\n' - ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up2\n' - ' │ parentData: offset=Offset(5.0, 5.0) (can use size)\n' - ' │ constraints: BoxConstraints(0.0<=w<=790.0, 0.0<=h<=590.0)\n' - ' │ size: Size(53.0, 78.0)\n' - ' │ additionalConstraints: BoxConstraints(w=53.0, h=78.0)\n' - ' │\n' - ' └─child: RenderDecoratedBox#00000\n' - ' │ parentData: (can use size)\n' - ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' - ' │ size: Size(53.0, 78.0)\n' - ' │ decoration: BoxDecoration:\n' - ' │ color: Color(0x7f0000ff)\n' - ' │ configuration: ImageConfiguration(bundle:\n' - ' │ PlatformAssetBundle#00000(), devicePixelRatio: 3.0, platform:\n' - ' │ android)\n' - ' │\n' - ' └─child: _RenderColoredBox#00000\n' - ' │ parentData: (can use size)\n' - ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' - ' │ size: Size(53.0, 78.0)\n' - ' │ behavior: opaque\n' - ' │\n' - ' └─child: RenderPadding#00000\n' - ' │ parentData: (can use size)\n' - ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' - ' │ size: Size(53.0, 78.0)\n' - ' │ padding: EdgeInsets.all(7.0)\n' - ' │\n' - ' └─child: RenderPositionedBox#00000\n' - ' │ parentData: offset=Offset(7.0, 7.0) (can use size)\n' - ' │ constraints: BoxConstraints(w=39.0, h=64.0)\n' - ' │ size: Size(39.0, 64.0)\n' - ' │ alignment: Alignment.bottomRight\n' - ' │ widthFactor: expand\n' - ' │ heightFactor: expand\n' - ' │\n' - ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up1\n' - ' │ parentData: offset=Offset(14.0, 31.0) (can use size)\n' - ' │ constraints: BoxConstraints(0.0<=w<=39.0, 0.0<=h<=64.0)\n' - ' │ size: Size(25.0, 33.0)\n' - ' │ additionalConstraints: BoxConstraints(w=25.0, h=33.0)\n' - ' │\n' - ' └─child: RenderDecoratedBox#00000\n' - ' parentData: (can use size)\n' - ' constraints: BoxConstraints(w=25.0, h=33.0)\n' - ' size: Size(25.0, 33.0)\n' - ' decoration: BoxDecoration:\n' - ' color: Color(0xffffff00)\n' - ' configuration: ImageConfiguration(bundle:\n' - ' PlatformAssetBundle#00000(), devicePixelRatio: 3.0, platform:\n' - ' android)\n', - ), - ); - }); - - testWidgets('has expected debug diagnostics', (WidgetTester tester) async { - await tester.pumpWidget(Align( - alignment: Alignment.topLeft, - child: container, - )); - - final RenderBox box = tester.renderObject(find.byType(Container)); - - expect( - // Using the redundant value to ensure the test is explicitly for - // debug diagnostics, regardless of any changes to the default value. - // ignore: avoid_redundant_argument_values - box.toStringDeep(minLevel: DiagnosticLevel.debug), - equalsIgnoringHashCodes( - 'RenderPadding#00000 relayoutBoundary=up1\n' - ' │ creator: Padding ← Container ← Align ← MediaQuery ←\n' - ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' - ' │ TestFlutterView#00000] ← [root]\n' - ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n' - ' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n' - ' │ size: Size(63.0, 88.0)\n' - ' │ padding: EdgeInsets.all(5.0)\n' - ' │\n' - ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up2\n' - ' │ creator: ConstrainedBox ← Padding ← Container ← Align ←\n' - ' │ MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' - ' │ View-[GlobalObjectKey TestFlutterView#00000] ← [root]\n' - ' │ parentData: offset=Offset(5.0, 5.0) (can use size)\n' - ' │ constraints: BoxConstraints(0.0<=w<=790.0, 0.0<=h<=590.0)\n' - ' │ size: Size(53.0, 78.0)\n' - ' │ additionalConstraints: BoxConstraints(w=53.0, h=78.0)\n' - ' │\n' - ' └─child: RenderDecoratedBox#00000\n' - ' │ creator: DecoratedBox ← ConstrainedBox ← Padding ← Container ←\n' - ' │ Align ← MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' - ' │ View-[GlobalObjectKey TestFlutterView#00000] ← [root]\n' - ' │ parentData: (can use size)\n' - ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' - ' │ size: Size(53.0, 78.0)\n' - ' │ decoration: BoxDecoration:\n' - ' │ color: Color(0x7f0000ff)\n' - ' │ configuration: ImageConfiguration(bundle:\n' - ' │ PlatformAssetBundle#00000(), devicePixelRatio: 3.0, platform:\n' - ' │ android)\n' - ' │\n' - ' └─child: _RenderColoredBox#00000\n' - ' │ creator: ColoredBox ← DecoratedBox ← ConstrainedBox ← Padding ←\n' - ' │ Container ← Align ← MediaQuery ← _MediaQueryFromView ←\n' - ' │ _ViewScope ← View-[GlobalObjectKey TestFlutterView#00000] ←\n' - ' │ [root]\n' - ' │ parentData: (can use size)\n' - ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' - ' │ size: Size(53.0, 78.0)\n' - ' │ behavior: opaque\n' - ' │\n' - ' └─child: RenderPadding#00000\n' - ' │ creator: Padding ← ColoredBox ← DecoratedBox ← ConstrainedBox ←\n' - ' │ Padding ← Container ← Align ← MediaQuery ← _MediaQueryFromView\n' - ' │ ← _ViewScope ← View-[GlobalObjectKey TestFlutterView#00000] ←\n' - ' │ [root]\n' - ' │ parentData: (can use size)\n' - ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' - ' │ size: Size(53.0, 78.0)\n' - ' │ padding: EdgeInsets.all(7.0)\n' - ' │\n' - ' └─child: RenderPositionedBox#00000\n' - ' │ creator: Align ← Padding ← ColoredBox ← DecoratedBox ←\n' - ' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n' - ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' - ' │ TestFlutterView#00000] ← ⋯\n' - ' │ parentData: offset=Offset(7.0, 7.0) (can use size)\n' - ' │ constraints: BoxConstraints(w=39.0, h=64.0)\n' - ' │ size: Size(39.0, 64.0)\n' - ' │ alignment: Alignment.bottomRight\n' - ' │ widthFactor: expand\n' - ' │ heightFactor: expand\n' - ' │\n' - ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up1\n' - ' │ creator: SizedBox ← Align ← Padding ← ColoredBox ← DecoratedBox ←\n' - ' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n' - ' │ _MediaQueryFromView ← _ViewScope ← ⋯\n' - ' │ parentData: offset=Offset(14.0, 31.0) (can use size)\n' - ' │ constraints: BoxConstraints(0.0<=w<=39.0, 0.0<=h<=64.0)\n' - ' │ size: Size(25.0, 33.0)\n' - ' │ additionalConstraints: BoxConstraints(w=25.0, h=33.0)\n' - ' │\n' - ' └─child: RenderDecoratedBox#00000\n' - ' creator: DecoratedBox ← SizedBox ← Align ← Padding ← ColoredBox ←\n' - ' DecoratedBox ← ConstrainedBox ← Padding ← Container ← Align ←\n' - ' MediaQuery ← _MediaQueryFromView ← ⋯\n' - ' parentData: (can use size)\n' - ' constraints: BoxConstraints(w=25.0, h=33.0)\n' - ' size: Size(25.0, 33.0)\n' - ' decoration: BoxDecoration:\n' - ' color: Color(0xffffff00)\n' - ' configuration: ImageConfiguration(bundle:\n' - ' PlatformAssetBundle#00000(), devicePixelRatio: 3.0, platform:\n' - ' android)\n', - ), - ); - }); - - testWidgets('has expected fine diagnostics', (WidgetTester tester) async { - await tester.pumpWidget(Align( - alignment: Alignment.topLeft, - child: container, - )); - - final RenderBox box = tester.renderObject(find.byType(Container)); - - expect( - box.toStringDeep(minLevel: DiagnosticLevel.fine), - equalsIgnoringHashCodes( - 'RenderPadding#00000 relayoutBoundary=up1\n' - ' │ creator: Padding ← Container ← Align ← MediaQuery ←\n' - ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' - ' │ TestFlutterView#00000] ← [root]\n' - ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n' - ' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n' - ' │ layer: null\n' - ' │ semantics node: null\n' - ' │ size: Size(63.0, 88.0)\n' - ' │ padding: EdgeInsets.all(5.0)\n' - ' │ textDirection: null\n' - ' │\n' - ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up2\n' - ' │ creator: ConstrainedBox ← Padding ← Container ← Align ←\n' - ' │ MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' - ' │ View-[GlobalObjectKey TestFlutterView#00000] ← [root]\n' - ' │ parentData: offset=Offset(5.0, 5.0) (can use size)\n' - ' │ constraints: BoxConstraints(0.0<=w<=790.0, 0.0<=h<=590.0)\n' - ' │ layer: null\n' - ' │ semantics node: null\n' - ' │ size: Size(53.0, 78.0)\n' - ' │ additionalConstraints: BoxConstraints(w=53.0, h=78.0)\n' - ' │\n' - ' └─child: RenderDecoratedBox#00000\n' - ' │ creator: DecoratedBox ← ConstrainedBox ← Padding ← Container ←\n' - ' │ Align ← MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' - ' │ View-[GlobalObjectKey TestFlutterView#00000] ← [root]\n' - ' │ parentData: (can use size)\n' - ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' - ' │ layer: null\n' - ' │ semantics node: null\n' - ' │ size: Size(53.0, 78.0)\n' - ' │ decoration: BoxDecoration:\n' - ' │ color: Color(0x7f0000ff)\n' - ' │ image: null\n' - ' │ border: null\n' - ' │ borderRadius: null\n' - ' │ boxShadow: null\n' - ' │ gradient: null\n' - ' │ shape: rectangle\n' - ' │ configuration: ImageConfiguration(bundle:\n' - ' │ PlatformAssetBundle#00000(), devicePixelRatio: 3.0, platform:\n' - ' │ android)\n' - ' │\n' - ' └─child: _RenderColoredBox#00000\n' - ' │ creator: ColoredBox ← DecoratedBox ← ConstrainedBox ← Padding ←\n' - ' │ Container ← Align ← MediaQuery ← _MediaQueryFromView ←\n' - ' │ _ViewScope ← View-[GlobalObjectKey TestFlutterView#00000] ←\n' - ' │ [root]\n' - ' │ parentData: (can use size)\n' - ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' - ' │ layer: null\n' - ' │ semantics node: null\n' - ' │ size: Size(53.0, 78.0)\n' - ' │ behavior: opaque\n' - ' │\n' - ' └─child: RenderPadding#00000\n' - ' │ creator: Padding ← ColoredBox ← DecoratedBox ← ConstrainedBox ←\n' - ' │ Padding ← Container ← Align ← MediaQuery ← _MediaQueryFromView\n' - ' │ ← _ViewScope ← View-[GlobalObjectKey TestFlutterView#00000] ←\n' - ' │ [root]\n' - ' │ parentData: (can use size)\n' - ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' - ' │ layer: null\n' - ' │ semantics node: null\n' - ' │ size: Size(53.0, 78.0)\n' - ' │ padding: EdgeInsets.all(7.0)\n' - ' │ textDirection: null\n' - ' │\n' - ' └─child: RenderPositionedBox#00000\n' - ' │ creator: Align ← Padding ← ColoredBox ← DecoratedBox ←\n' - ' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n' - ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' - ' │ TestFlutterView#00000] ← ⋯\n' - ' │ parentData: offset=Offset(7.0, 7.0) (can use size)\n' - ' │ constraints: BoxConstraints(w=39.0, h=64.0)\n' - ' │ layer: null\n' - ' │ semantics node: null\n' - ' │ size: Size(39.0, 64.0)\n' - ' │ alignment: Alignment.bottomRight\n' - ' │ textDirection: null\n' - ' │ widthFactor: expand\n' - ' │ heightFactor: expand\n' - ' │\n' - ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up1\n' - ' │ creator: SizedBox ← Align ← Padding ← ColoredBox ← DecoratedBox ←\n' - ' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n' - ' │ _MediaQueryFromView ← _ViewScope ← ⋯\n' - ' │ parentData: offset=Offset(14.0, 31.0) (can use size)\n' - ' │ constraints: BoxConstraints(0.0<=w<=39.0, 0.0<=h<=64.0)\n' - ' │ layer: null\n' - ' │ semantics node: null\n' - ' │ size: Size(25.0, 33.0)\n' - ' │ additionalConstraints: BoxConstraints(w=25.0, h=33.0)\n' - ' │\n' - ' └─child: RenderDecoratedBox#00000\n' - ' creator: DecoratedBox ← SizedBox ← Align ← Padding ← ColoredBox ←\n' - ' DecoratedBox ← ConstrainedBox ← Padding ← Container ← Align ←\n' - ' MediaQuery ← _MediaQueryFromView ← ⋯\n' - ' parentData: (can use size)\n' - ' constraints: BoxConstraints(w=25.0, h=33.0)\n' - ' layer: null\n' - ' semantics node: null\n' - ' size: Size(25.0, 33.0)\n' - ' decoration: BoxDecoration:\n' - ' color: Color(0xffffff00)\n' - ' image: null\n' - ' border: null\n' - ' borderRadius: null\n' - ' boxShadow: null\n' - ' gradient: null\n' - ' shape: rectangle\n' - ' configuration: ImageConfiguration(bundle:\n' - ' PlatformAssetBundle#00000(), devicePixelRatio: 3.0, platform:\n' - ' android)\n', - ), - ); - }); - - testWidgets('has expected hidden diagnostics', (WidgetTester tester) async { - await tester.pumpWidget(Align( - alignment: Alignment.topLeft, - child: container, - )); - - final RenderBox box = tester.renderObject(find.byType(Container)); - - expect( - box.toStringDeep(minLevel: DiagnosticLevel.hidden), - equalsIgnoringHashCodes( - 'RenderPadding#00000 relayoutBoundary=up1\n' - ' │ needsCompositing: false\n' - ' │ creator: Padding ← Container ← Align ← MediaQuery ←\n' - ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' - ' │ TestFlutterView#00000] ← [root]\n' - ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n' - ' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n' - ' │ layer: null\n' - ' │ semantics node: null\n' - ' │ isBlockingSemanticsOfPreviouslyPaintedNodes: false\n' - ' │ isSemanticBoundary: false\n' - ' │ size: Size(63.0, 88.0)\n' - ' │ padding: EdgeInsets.all(5.0)\n' - ' │ textDirection: null\n' - ' │\n' - ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up2\n' - ' │ needsCompositing: false\n' - ' │ creator: ConstrainedBox ← Padding ← Container ← Align ←\n' - ' │ MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' - ' │ View-[GlobalObjectKey TestFlutterView#00000] ← [root]\n' - ' │ parentData: offset=Offset(5.0, 5.0) (can use size)\n' - ' │ constraints: BoxConstraints(0.0<=w<=790.0, 0.0<=h<=590.0)\n' - ' │ layer: null\n' - ' │ semantics node: null\n' - ' │ isBlockingSemanticsOfPreviouslyPaintedNodes: false\n' - ' │ isSemanticBoundary: false\n' - ' │ size: Size(53.0, 78.0)\n' - ' │ additionalConstraints: BoxConstraints(w=53.0, h=78.0)\n' - ' │\n' - ' └─child: RenderDecoratedBox#00000\n' - ' │ needsCompositing: false\n' - ' │ creator: DecoratedBox ← ConstrainedBox ← Padding ← Container ←\n' - ' │ Align ← MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' - ' │ View-[GlobalObjectKey TestFlutterView#00000] ← [root]\n' - ' │ parentData: (can use size)\n' - ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' - ' │ layer: null\n' - ' │ semantics node: null\n' - ' │ isBlockingSemanticsOfPreviouslyPaintedNodes: false\n' - ' │ isSemanticBoundary: false\n' - ' │ size: Size(53.0, 78.0)\n' - ' │ decoration: BoxDecoration:\n' - ' │ color: Color(0x7f0000ff)\n' - ' │ image: null\n' - ' │ border: null\n' - ' │ borderRadius: null\n' - ' │ boxShadow: null\n' - ' │ gradient: null\n' - ' │ shape: rectangle\n' - ' │ configuration: ImageConfiguration(bundle:\n' - ' │ PlatformAssetBundle#00000(), devicePixelRatio: 3.0, platform:\n' - ' │ android)\n' - ' │\n' - ' └─child: _RenderColoredBox#00000\n' - ' │ needsCompositing: false\n' - ' │ creator: ColoredBox ← DecoratedBox ← ConstrainedBox ← Padding ←\n' - ' │ Container ← Align ← MediaQuery ← _MediaQueryFromView ←\n' - ' │ _ViewScope ← View-[GlobalObjectKey TestFlutterView#00000] ←\n' - ' │ [root]\n' - ' │ parentData: (can use size)\n' - ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' - ' │ layer: null\n' - ' │ semantics node: null\n' - ' │ isBlockingSemanticsOfPreviouslyPaintedNodes: false\n' - ' │ isSemanticBoundary: false\n' - ' │ size: Size(53.0, 78.0)\n' - ' │ behavior: opaque\n' - ' │\n' - ' └─child: RenderPadding#00000\n' - ' │ needsCompositing: false\n' - ' │ creator: Padding ← ColoredBox ← DecoratedBox ← ConstrainedBox ←\n' - ' │ Padding ← Container ← Align ← MediaQuery ← _MediaQueryFromView\n' - ' │ ← _ViewScope ← View-[GlobalObjectKey TestFlutterView#00000] ←\n' - ' │ [root]\n' - ' │ parentData: (can use size)\n' - ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' - ' │ layer: null\n' - ' │ semantics node: null\n' - ' │ isBlockingSemanticsOfPreviouslyPaintedNodes: false\n' - ' │ isSemanticBoundary: false\n' - ' │ size: Size(53.0, 78.0)\n' - ' │ padding: EdgeInsets.all(7.0)\n' - ' │ textDirection: null\n' - ' │\n' - ' └─child: RenderPositionedBox#00000\n' - ' │ needsCompositing: false\n' - ' │ creator: Align ← Padding ← ColoredBox ← DecoratedBox ←\n' - ' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n' - ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' - ' │ TestFlutterView#00000] ← ⋯\n' - ' │ parentData: offset=Offset(7.0, 7.0) (can use size)\n' - ' │ constraints: BoxConstraints(w=39.0, h=64.0)\n' - ' │ layer: null\n' - ' │ semantics node: null\n' - ' │ isBlockingSemanticsOfPreviouslyPaintedNodes: false\n' - ' │ isSemanticBoundary: false\n' - ' │ size: Size(39.0, 64.0)\n' - ' │ alignment: Alignment.bottomRight\n' - ' │ textDirection: null\n' - ' │ widthFactor: expand\n' - ' │ heightFactor: expand\n' - ' │\n' - ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up1\n' - ' │ needsCompositing: false\n' - ' │ creator: SizedBox ← Align ← Padding ← ColoredBox ← DecoratedBox ←\n' - ' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n' - ' │ _MediaQueryFromView ← _ViewScope ← ⋯\n' - ' │ parentData: offset=Offset(14.0, 31.0) (can use size)\n' - ' │ constraints: BoxConstraints(0.0<=w<=39.0, 0.0<=h<=64.0)\n' - ' │ layer: null\n' - ' │ semantics node: null\n' - ' │ isBlockingSemanticsOfPreviouslyPaintedNodes: false\n' - ' │ isSemanticBoundary: false\n' - ' │ size: Size(25.0, 33.0)\n' - ' │ additionalConstraints: BoxConstraints(w=25.0, h=33.0)\n' - ' │\n' - ' └─child: RenderDecoratedBox#00000\n' - ' needsCompositing: false\n' - ' creator: DecoratedBox ← SizedBox ← Align ← Padding ← ColoredBox ←\n' - ' DecoratedBox ← ConstrainedBox ← Padding ← Container ← Align ←\n' - ' MediaQuery ← _MediaQueryFromView ← ⋯\n' - ' parentData: (can use size)\n' - ' constraints: BoxConstraints(w=25.0, h=33.0)\n' - ' layer: null\n' - ' semantics node: null\n' - ' isBlockingSemanticsOfPreviouslyPaintedNodes: false\n' - ' isSemanticBoundary: false\n' - ' size: Size(25.0, 33.0)\n' - ' decoration: BoxDecoration:\n' - ' color: Color(0xffffff00)\n' - ' image: null\n' - ' border: null\n' - ' borderRadius: null\n' - ' boxShadow: null\n' - ' gradient: null\n' - ' shape: rectangle\n' - ' configuration: ImageConfiguration(bundle:\n' - ' PlatformAssetBundle#00000(), devicePixelRatio: 3.0, platform:\n' - ' android)\n', - ), - ); - }); - - testWidgets('painting error has expected diagnostics', (WidgetTester tester) async { - await tester.pumpWidget(Align( - alignment: Alignment.topLeft, - child: container, - )); - - final RenderBox decoratedBox = tester.renderObject(find.byType(DecoratedBox).last); - final PaintingContext context = _MockPaintingContext(); - late FlutterError error; - try { - decoratedBox.paint(context, Offset.zero); - } on FlutterError catch (e) { - error = e; - } - expect(error, isNotNull); - expect( - error.toStringDeep(), - 'FlutterError\n' - ' BoxDecoration painter had mismatching save and restore calls.\n' - ' Before painting the decoration, the canvas save count was 0.\n' - ' After painting it, the canvas save count was 2. Every call to\n' - ' save() or saveLayer() must be matched by a call to restore().\n' - ' The decoration was:\n' - ' BoxDecoration(color: Color(0xffffff00))\n' - ' The painter was:\n' - ' BoxPainter for BoxDecoration(color: Color(0xffffff00))\n', - ); - }); - }); + final RenderBox decoratedBox = tester.renderObject(find.byType(DecoratedBox).last); + final PaintingContext context = _MockPaintingContext(); + late FlutterError error; + try { + decoratedBox.paint(context, Offset.zero); + } on FlutterError catch (e) { + error = e; + } + expect(error, isNotNull); + expect( + error.toStringDeep(), + 'FlutterError\n' + ' BoxDecoration painter had mismatching save and restore calls.\n' + ' Before painting the decoration, the canvas save count was 0.\n' + ' After painting it, the canvas save count was 2. Every call to\n' + ' save() or saveLayer() must be matched by a call to restore().\n' + ' The decoration was:\n' + ' BoxDecoration(color: Color(0xffffff00))\n' + ' The painter was:\n' + ' BoxPainter for BoxDecoration(color: Color(0xffffff00))\n', + ); }); testWidgets('Can be placed in an infinite box', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/custom_multi_child_layout_test.dart b/packages/flutter/test/widgets/custom_multi_child_layout_test.dart index 0a6db8b1c85..732ae02ea92 100644 --- a/packages/flutter/test/widgets/custom_multi_child_layout_test.dart +++ b/packages/flutter/test/widgets/custom_multi_child_layout_test.dart @@ -374,7 +374,7 @@ void main() { ' creator: ConstrainedBox ← Container ← LayoutWithMissingId ←\n' ' CustomMultiChildLayout ← Center ← MediaQuery ←\n' ' _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' - ' TestFlutterView#00000] ← [root]\n' + ' TestWindow#00000] ← [root]\n' ' parentData: offset=Offset(0.0, 0.0); id=null\n' ' constraints: MISSING\n' ' size: MISSING\n' diff --git a/packages/flutter/test/widgets/display_feature_sub_screen_test.dart b/packages/flutter/test/widgets/display_feature_sub_screen_test.dart index 926a459a81d..f7045132a9f 100644 --- a/packages/flutter/test/widgets/display_feature_sub_screen_test.dart +++ b/packages/flutter/test/widgets/display_feature_sub_screen_test.dart @@ -11,7 +11,7 @@ void main() { group('DisplayFeatureSubScreen', () { testWidgets('without Directionality or anchor', (WidgetTester tester) async { const Key childKey = Key('childKey'); - final MediaQueryData mediaQuery = MediaQueryData.fromView(tester.view).copyWith( + final MediaQueryData mediaQuery = MediaQueryData.fromView(WidgetsBinding.instance.window).copyWith( displayFeatures: [ const DisplayFeature( bounds: Rect.fromLTRB(390, 0, 410, 600), @@ -39,7 +39,7 @@ void main() { testWidgets('with anchorPoint', (WidgetTester tester) async { const Key childKey = Key('childKey'); - final MediaQueryData mediaQuery = MediaQueryData.fromView(tester.view).copyWith( + final MediaQueryData mediaQuery = MediaQueryData.fromView(WidgetsBinding.instance.window).copyWith( displayFeatures: [ const DisplayFeature( bounds: Rect.fromLTRB(390, 0, 410, 600), @@ -70,7 +70,7 @@ void main() { testWidgets('with infinity anchorpoint', (WidgetTester tester) async { const Key childKey = Key('childKey'); - final MediaQueryData mediaQuery = MediaQueryData.fromView(tester.view).copyWith( + final MediaQueryData mediaQuery = MediaQueryData.fromView(WidgetsBinding.instance.window).copyWith( displayFeatures: [ const DisplayFeature( bounds: Rect.fromLTRB(390, 0, 410, 600), @@ -101,7 +101,7 @@ void main() { testWidgets('with horizontal hinge and anchorPoint', (WidgetTester tester) async { const Key childKey = Key('childKey'); - final MediaQueryData mediaQuery = MediaQueryData.fromView(tester.view).copyWith( + final MediaQueryData mediaQuery = MediaQueryData.fromView(WidgetsBinding.instance.window).copyWith( displayFeatures: [ const DisplayFeature( bounds: Rect.fromLTRB(0, 290, 800, 310), @@ -131,7 +131,7 @@ void main() { testWidgets('with multiple display features and anchorPoint', (WidgetTester tester) async { const Key childKey = Key('childKey'); - final MediaQueryData mediaQuery = MediaQueryData.fromView(tester.view).copyWith( + final MediaQueryData mediaQuery = MediaQueryData.fromView(WidgetsBinding.instance.window).copyWith( displayFeatures: [ const DisplayFeature( bounds: Rect.fromLTRB(0, 290, 800, 310), @@ -166,7 +166,7 @@ void main() { testWidgets('with non-splitting display features and anchorPoint', (WidgetTester tester) async { const Key childKey = Key('childKey'); - final MediaQueryData mediaQuery = MediaQueryData.fromView(tester.view).copyWith( + final MediaQueryData mediaQuery = MediaQueryData.fromView(WidgetsBinding.instance.window).copyWith( displayFeatures: [ // Top notch const DisplayFeature( @@ -211,7 +211,7 @@ void main() { testWidgets('with size 0 display feature in half-opened posture and anchorPoint', (WidgetTester tester) async { const Key childKey = Key('childKey'); - final MediaQueryData mediaQuery = MediaQueryData.fromView(tester.view).copyWith( + final MediaQueryData mediaQuery = MediaQueryData.fromView(WidgetsBinding.instance.window).copyWith( displayFeatures: [ const DisplayFeature( bounds: Rect.fromLTRB(0, 300, 800, 300), diff --git a/packages/flutter/test/widgets/focus_manager_test.dart b/packages/flutter/test/widgets/focus_manager_test.dart index e6ce67d56b1..21c8b0dd837 100644 --- a/packages/flutter/test/widgets/focus_manager_test.dart +++ b/packages/flutter/test/widgets/focus_manager_test.dart @@ -1230,7 +1230,7 @@ void main() { ' │ primaryFocus: FocusNode#00000(Child 4 [PRIMARY FOCUS])\n' ' │ primaryFocusCreator: Container-[GlobalKey#00000] ← MediaQuery ←\n' ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' - ' │ TestFlutterView#00000] ← [root]\n' + ' │ TestWindow#00000] ← [root]\n' ' │\n' ' └─rootScope: FocusScopeNode#00000(Root Focus Scope [IN FOCUS PATH])\n' ' │ IN FOCUS PATH\n' diff --git a/packages/flutter/test/widgets/independent_widget_layout_test.dart b/packages/flutter/test/widgets/independent_widget_layout_test.dart index 558e7fd4813..90d8881b486 100644 --- a/packages/flutter/test/widgets/independent_widget_layout_test.dart +++ b/packages/flutter/test/widgets/independent_widget_layout_test.dart @@ -2,16 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' show FlutterView; - import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; const Size _kTestViewSize = Size(800.0, 600.0); -class ScheduledFrameTrackingPlatformDispatcher extends TestPlatformDispatcher { - ScheduledFrameTrackingPlatformDispatcher({ required super.platformDispatcher }); +class ScheduledFrameTrackingWindow extends TestWindow { + ScheduledFrameTrackingWindow({ required super.window }); int _scheduledFrameCount = 0; int get scheduledFrameCount => _scheduledFrameCount; @@ -28,16 +26,16 @@ class ScheduledFrameTrackingPlatformDispatcher extends TestPlatformDispatcher { } class ScheduledFrameTrackingBindings extends AutomatedTestWidgetsFlutterBinding { - late final ScheduledFrameTrackingPlatformDispatcher _platformDispatcher = ScheduledFrameTrackingPlatformDispatcher(platformDispatcher: super.platformDispatcher); + late final ScheduledFrameTrackingWindow _window = ScheduledFrameTrackingWindow(window: super.window); @override - ScheduledFrameTrackingPlatformDispatcher get platformDispatcher => _platformDispatcher; + ScheduledFrameTrackingWindow get window => _window; } class OffscreenRenderView extends RenderView { - OffscreenRenderView({required FlutterView view}) : super( + OffscreenRenderView() : super( configuration: const ViewConfiguration(size: _kTestViewSize), - window: view, + window: WidgetsBinding.instance.window, ); @override @@ -47,14 +45,13 @@ class OffscreenRenderView extends RenderView { } class OffscreenWidgetTree { - OffscreenWidgetTree(this.view) { + OffscreenWidgetTree() { renderView.attach(pipelineOwner); renderView.prepareInitialFrame(); pipelineOwner.requestVisualUpdate(); } - final FlutterView view; - late final RenderView renderView = OffscreenRenderView(view: view); + final RenderView renderView = OffscreenRenderView(); final BuildOwner buildOwner = BuildOwner(focusManager: FocusManager()); final PipelineOwner pipelineOwner = PipelineOwner(); RenderObjectToWidgetElement? root; @@ -171,12 +168,12 @@ void main() { testWidgets('RenderObjectToWidgetAdapter.attachToRenderTree does not schedule frame', (WidgetTester tester) async { expect(WidgetsBinding.instance, isA()); - final ScheduledFrameTrackingPlatformDispatcher platformDispatcher = tester.platformDispatcher as ScheduledFrameTrackingPlatformDispatcher; - platformDispatcher.resetScheduledFrameCount(); - expect(platformDispatcher.scheduledFrameCount, isZero); - final OffscreenWidgetTree tree = OffscreenWidgetTree(tester.view); + final ScheduledFrameTrackingWindow window = WidgetsBinding.instance.window as ScheduledFrameTrackingWindow; + window.resetScheduledFrameCount(); + expect(window.scheduledFrameCount, isZero); + final OffscreenWidgetTree tree = OffscreenWidgetTree(); tree.pumpWidget(const SizedBox.shrink()); - expect(platformDispatcher.scheduledFrameCount, isZero); + expect(window.scheduledFrameCount, isZero); }); testWidgets('no crosstalk between widget build owners', (WidgetTester tester) async { @@ -184,7 +181,7 @@ void main() { final Counter counter1 = Counter(); final Trigger trigger2 = Trigger(); final Counter counter2 = Counter(); - final OffscreenWidgetTree tree = OffscreenWidgetTree(tester.view); + final OffscreenWidgetTree tree = OffscreenWidgetTree(); // Both counts should start at zero expect(counter1.count, equals(0)); expect(counter2.count, equals(0)); @@ -230,7 +227,7 @@ void main() { }); testWidgets('no crosstalk between focus nodes', (WidgetTester tester) async { - final OffscreenWidgetTree tree = OffscreenWidgetTree(tester.view); + final OffscreenWidgetTree tree = OffscreenWidgetTree(); final FocusNode onscreenFocus = FocusNode(); final FocusNode offscreenFocus = FocusNode(); await tester.pumpWidget( @@ -253,7 +250,7 @@ void main() { }); testWidgets('able to tear down offscreen tree', (WidgetTester tester) async { - final OffscreenWidgetTree tree = OffscreenWidgetTree(tester.view); + final OffscreenWidgetTree tree = OffscreenWidgetTree(); final List states = []; tree.pumpWidget(SizedBox(child: TestStates(states: states))); expect(states, [WidgetState.initialized]); diff --git a/packages/flutter/test/widgets/media_query_test.dart b/packages/flutter/test/widgets/media_query_test.dart index 3b27e84ccb0..73e0e1da898 100644 --- a/packages/flutter/test/widgets/media_query_test.dart +++ b/packages/flutter/test/widgets/media_query_test.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' show Brightness, DisplayFeature, DisplayFeatureState, DisplayFeatureType, GestureSettings; +import 'dart:ui' show Brightness, DisplayFeature, DisplayFeatureState, DisplayFeatureType, GestureSettings, PlatformDispatcher, ViewPadding; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; @@ -146,10 +146,10 @@ void main() { }); testWidgets('MediaQueryData.fromView is sane', (WidgetTester tester) async { - final MediaQueryData data = MediaQueryData.fromView(tester.view); + final MediaQueryData data = MediaQueryData.fromView(tester.binding.window); expect(data, hasOneLineDescription); expect(data.hashCode, equals(data.copyWith().hashCode)); - expect(data.size, equals(tester.view.physicalSize / tester.view.devicePixelRatio)); + expect(data.size, equals(tester.binding.window.physicalSize / tester.binding.window.devicePixelRatio)); expect(data.accessibleNavigation, false); expect(data.invertColors, false); expect(data.disableAnimations, false); @@ -173,17 +173,26 @@ void main() { navigationMode: NavigationMode.directional, ); - final MediaQueryData data = MediaQueryData.fromView(tester.view, platformData: platformData); + final TestView view = TestView( + physicalSize: const Size(300, 600), + devicePixelRatio: 3.0, + padding: const TestViewPadding(15), + viewPadding: const TestViewPadding(75), + viewInsets: const TestViewPadding(45), + systemGestureInsets: const TestViewPadding(9), + ); + + final MediaQueryData data = MediaQueryData.fromView(view, platformData: platformData); expect(data, hasOneLineDescription); expect(data.hashCode, data.copyWith().hashCode); - expect(data.size, tester.view.physicalSize / tester.view.devicePixelRatio); - expect(data.devicePixelRatio, tester.view.devicePixelRatio); + expect(data.size, view.physicalSize / view.devicePixelRatio); + expect(data.devicePixelRatio, view.devicePixelRatio); expect(data.textScaleFactor, platformData.textScaleFactor); expect(data.platformBrightness, platformData.platformBrightness); - expect(data.padding, EdgeInsets.fromViewPadding(tester.view.padding, tester.view.devicePixelRatio)); - expect(data.viewPadding, EdgeInsets.fromViewPadding(tester.view.viewPadding, tester.view.devicePixelRatio)); - expect(data.viewInsets, EdgeInsets.fromViewPadding(tester.view.viewInsets, tester.view.devicePixelRatio)); - expect(data.systemGestureInsets, EdgeInsets.fromViewPadding(tester.view.systemGestureInsets, tester.view.devicePixelRatio)); + expect(data.padding, EdgeInsets.fromViewPadding(view.padding, view.devicePixelRatio)); + expect(data.viewPadding, EdgeInsets.fromViewPadding(view.viewPadding, view.devicePixelRatio)); + expect(data.viewInsets, EdgeInsets.fromViewPadding(view.viewInsets, view.devicePixelRatio)); + expect(data.systemGestureInsets, EdgeInsets.fromViewPadding(view.systemGestureInsets, view.devicePixelRatio)); expect(data.accessibleNavigation, platformData.accessibleNavigation); expect(data.invertColors, platformData.invertColors); expect(data.disableAnimations, platformData.disableAnimations); @@ -191,37 +200,48 @@ void main() { expect(data.highContrast, platformData.highContrast); expect(data.alwaysUse24HourFormat, platformData.alwaysUse24HourFormat); expect(data.navigationMode, platformData.navigationMode); - expect(data.gestureSettings, DeviceGestureSettings.fromView(tester.view)); - expect(data.displayFeatures, tester.view.displayFeatures); + expect(data.gestureSettings, DeviceGestureSettings.fromView(view)); + expect(data.displayFeatures, view.displayFeatures); }); testWidgets('MediaQueryData.fromView uses data from platformDispatcher if no platformData is provided', (WidgetTester tester) async { - tester.platformDispatcher + final TestPlatformDispatcher platformDispatcher = TestPlatformDispatcher(platformDispatcher: tester.binding.platformDispatcher); + platformDispatcher ..textScaleFactorTestValue = 123 ..platformBrightnessTestValue = Brightness.dark ..accessibilityFeaturesTestValue = FakeAccessibilityFeatures.allOn; - addTearDown(() => tester.platformDispatcher.clearAllTestValues()); + addTearDown(() => platformDispatcher.clearAllTestValues()); - final MediaQueryData data = MediaQueryData.fromView(tester.view); + final TestView view = TestView( + platformDispatcher: platformDispatcher, + physicalSize: const Size(300, 600), + devicePixelRatio: 3.0, + padding: const TestViewPadding(15), + viewPadding: const TestViewPadding(75), + viewInsets: const TestViewPadding(45), + systemGestureInsets: const TestViewPadding(9), + ); + + final MediaQueryData data = MediaQueryData.fromView(view); expect(data, hasOneLineDescription); expect(data.hashCode, data.copyWith().hashCode); - expect(data.size, tester.view.physicalSize / tester.view.devicePixelRatio); - expect(data.devicePixelRatio, tester.view.devicePixelRatio); - expect(data.textScaleFactor, tester.platformDispatcher.textScaleFactor); - expect(data.platformBrightness, tester.platformDispatcher.platformBrightness); - expect(data.padding, EdgeInsets.fromViewPadding(tester.view.padding, tester.view.devicePixelRatio)); - expect(data.viewPadding, EdgeInsets.fromViewPadding(tester.view.viewPadding, tester.view.devicePixelRatio)); - expect(data.viewInsets, EdgeInsets.fromViewPadding(tester.view.viewInsets, tester.view.devicePixelRatio)); - expect(data.systemGestureInsets, EdgeInsets.fromViewPadding(tester.view.systemGestureInsets, tester.view.devicePixelRatio)); - expect(data.accessibleNavigation, tester.platformDispatcher.accessibilityFeatures.accessibleNavigation); - expect(data.invertColors, tester.platformDispatcher.accessibilityFeatures.invertColors); - expect(data.disableAnimations, tester.platformDispatcher.accessibilityFeatures.disableAnimations); - expect(data.boldText, tester.platformDispatcher.accessibilityFeatures.boldText); - expect(data.highContrast, tester.platformDispatcher.accessibilityFeatures.highContrast); - expect(data.alwaysUse24HourFormat, tester.platformDispatcher.alwaysUse24HourFormat); + expect(data.size, view.physicalSize / view.devicePixelRatio); + expect(data.devicePixelRatio, view.devicePixelRatio); + expect(data.textScaleFactor, platformDispatcher.textScaleFactor); + expect(data.platformBrightness, platformDispatcher.platformBrightness); + expect(data.padding, EdgeInsets.fromViewPadding(view.padding, view.devicePixelRatio)); + expect(data.viewPadding, EdgeInsets.fromViewPadding(view.viewPadding, view.devicePixelRatio)); + expect(data.viewInsets, EdgeInsets.fromViewPadding(view.viewInsets, view.devicePixelRatio)); + expect(data.systemGestureInsets, EdgeInsets.fromViewPadding(view.systemGestureInsets, view.devicePixelRatio)); + expect(data.accessibleNavigation, platformDispatcher.accessibilityFeatures.accessibleNavigation); + expect(data.invertColors, platformDispatcher.accessibilityFeatures.invertColors); + expect(data.disableAnimations, platformDispatcher.accessibilityFeatures.disableAnimations); + expect(data.boldText, platformDispatcher.accessibilityFeatures.boldText); + expect(data.highContrast, platformDispatcher.accessibilityFeatures.highContrast); + expect(data.alwaysUse24HourFormat, platformDispatcher.alwaysUse24HourFormat); expect(data.navigationMode, NavigationMode.traditional); - expect(data.gestureSettings, DeviceGestureSettings.fromView(tester.view)); - expect(data.displayFeatures, tester.view.displayFeatures); + expect(data.gestureSettings, DeviceGestureSettings.fromView(view)); + expect(data.displayFeatures, view.displayFeatures); }); testWidgets('MediaQuery.fromView injects a new MediaQuery with data from view, preserving platform-specific data', (WidgetTester tester) async { @@ -237,11 +257,20 @@ void main() { navigationMode: NavigationMode.directional, ); + final TestView view = TestView( + physicalSize: const Size(300, 600), + devicePixelRatio: 3.0, + padding: const TestViewPadding(15), + viewPadding: const TestViewPadding(75), + viewInsets: const TestViewPadding(45), + systemGestureInsets: const TestViewPadding(9), + ); + late MediaQueryData data; await tester.pumpWidget(MediaQuery( data: platformData, child: MediaQuery.fromView( - view: tester.view, + view: view, child: Builder( builder: (BuildContext context) { data = MediaQuery.of(context); @@ -252,14 +281,14 @@ void main() { )); expect(data, isNot(platformData)); - expect(data.size, tester.view.physicalSize / tester.view.devicePixelRatio); - expect(data.devicePixelRatio, tester.view.devicePixelRatio); + expect(data.size, view.physicalSize / view.devicePixelRatio); + expect(data.devicePixelRatio, view.devicePixelRatio); expect(data.textScaleFactor, platformData.textScaleFactor); expect(data.platformBrightness, platformData.platformBrightness); - expect(data.padding, EdgeInsets.fromViewPadding(tester.view.padding, tester.view.devicePixelRatio)); - expect(data.viewPadding, EdgeInsets.fromViewPadding(tester.view.viewPadding, tester.view.devicePixelRatio)); - expect(data.viewInsets, EdgeInsets.fromViewPadding(tester.view.viewInsets, tester.view.devicePixelRatio)); - expect(data.systemGestureInsets, EdgeInsets.fromViewPadding(tester.view.systemGestureInsets, tester.view.devicePixelRatio)); + expect(data.padding, EdgeInsets.fromViewPadding(view.padding, view.devicePixelRatio)); + expect(data.viewPadding, EdgeInsets.fromViewPadding(view.viewPadding, view.devicePixelRatio)); + expect(data.viewInsets, EdgeInsets.fromViewPadding(view.viewInsets, view.devicePixelRatio)); + expect(data.systemGestureInsets, EdgeInsets.fromViewPadding(view.systemGestureInsets, view.devicePixelRatio)); expect(data.accessibleNavigation, platformData.accessibleNavigation); expect(data.invertColors, platformData.invertColors); expect(data.disableAnimations, platformData.disableAnimations); @@ -267,16 +296,27 @@ void main() { expect(data.highContrast, platformData.highContrast); expect(data.alwaysUse24HourFormat, platformData.alwaysUse24HourFormat); expect(data.navigationMode, platformData.navigationMode); - expect(data.gestureSettings, DeviceGestureSettings.fromView(tester.view)); - expect(data.displayFeatures, tester.view.displayFeatures); + expect(data.gestureSettings, DeviceGestureSettings.fromView(view)); + expect(data.displayFeatures, view.displayFeatures); }); testWidgets('MediaQuery.fromView injects a new MediaQuery with data from view when no surrounding MediaQuery exists', (WidgetTester tester) async { - tester.platformDispatcher + final TestPlatformDispatcher platformDispatcher = TestPlatformDispatcher(platformDispatcher: tester.binding.platformDispatcher); + platformDispatcher ..textScaleFactorTestValue = 123 ..platformBrightnessTestValue = Brightness.dark ..accessibilityFeaturesTestValue = FakeAccessibilityFeatures.allOn; - addTearDown(() => tester.platformDispatcher.clearAllTestValues()); + addTearDown(() => platformDispatcher.clearAllTestValues()); + + final TestView view = TestView( + platformDispatcher: platformDispatcher, + physicalSize: const Size(300, 600), + devicePixelRatio: 3.0, + padding: const TestViewPadding(15), + viewPadding: const TestViewPadding(75), + viewInsets: const TestViewPadding(45), + systemGestureInsets: const TestViewPadding(9), + ); late MediaQueryData data; MediaQueryData? outerData; @@ -286,7 +326,7 @@ void main() { builder: (BuildContext context) { outerData = MediaQuery.maybeOf(context); return MediaQuery.fromView( - view: tester.view, + view: view, child: Builder( builder: (BuildContext context) { data = MediaQuery.of(context); @@ -299,34 +339,33 @@ void main() { ); expect(outerData, isNull); - expect(data.size, tester.view.physicalSize / tester.view.devicePixelRatio); - expect(data.devicePixelRatio, tester.view.devicePixelRatio); - expect(data.textScaleFactor, tester.platformDispatcher.textScaleFactor); - expect(data.platformBrightness, tester.platformDispatcher.platformBrightness); - expect(data.padding, EdgeInsets.fromViewPadding(tester.view.padding, tester.view.devicePixelRatio)); - expect(data.viewPadding, EdgeInsets.fromViewPadding(tester.view.viewPadding, tester.view.devicePixelRatio)); - expect(data.viewInsets, EdgeInsets.fromViewPadding(tester.view.viewInsets, tester.view.devicePixelRatio)); - expect(data.systemGestureInsets, EdgeInsets.fromViewPadding(tester.view.systemGestureInsets, tester.view.devicePixelRatio)); - expect(data.accessibleNavigation, tester.platformDispatcher.accessibilityFeatures.accessibleNavigation); - expect(data.invertColors, tester.platformDispatcher.accessibilityFeatures.invertColors); - expect(data.disableAnimations, tester.platformDispatcher.accessibilityFeatures.disableAnimations); - expect(data.boldText, tester.platformDispatcher.accessibilityFeatures.boldText); - expect(data.highContrast, tester.platformDispatcher.accessibilityFeatures.highContrast); - expect(data.alwaysUse24HourFormat, tester.platformDispatcher.alwaysUse24HourFormat); + expect(data.size, view.physicalSize / view.devicePixelRatio); + expect(data.devicePixelRatio, view.devicePixelRatio); + expect(data.textScaleFactor, platformDispatcher.textScaleFactor); + expect(data.platformBrightness, platformDispatcher.platformBrightness); + expect(data.padding, EdgeInsets.fromViewPadding(view.padding, view.devicePixelRatio)); + expect(data.viewPadding, EdgeInsets.fromViewPadding(view.viewPadding, view.devicePixelRatio)); + expect(data.viewInsets, EdgeInsets.fromViewPadding(view.viewInsets, view.devicePixelRatio)); + expect(data.systemGestureInsets, EdgeInsets.fromViewPadding(view.systemGestureInsets, view.devicePixelRatio)); + expect(data.accessibleNavigation, platformDispatcher.accessibilityFeatures.accessibleNavigation); + expect(data.invertColors, platformDispatcher.accessibilityFeatures.invertColors); + expect(data.disableAnimations, platformDispatcher.accessibilityFeatures.disableAnimations); + expect(data.boldText, platformDispatcher.accessibilityFeatures.boldText); + expect(data.highContrast, platformDispatcher.accessibilityFeatures.highContrast); + expect(data.alwaysUse24HourFormat, platformDispatcher.alwaysUse24HourFormat); expect(data.navigationMode, NavigationMode.traditional); - expect(data.gestureSettings, DeviceGestureSettings.fromView(tester.view)); - expect(data.displayFeatures, tester.view.displayFeatures); + expect(data.gestureSettings, DeviceGestureSettings.fromView(view)); + expect(data.displayFeatures, view.displayFeatures); }); testWidgets('MediaQuery.fromView updates on notifications (no parent data)', (WidgetTester tester) async { - addTearDown(() => tester.platformDispatcher.clearAllTestValues()); - addTearDown(() => tester.view.reset()); - - tester.platformDispatcher + tester.binding.platformDispatcher ..textScaleFactorTestValue = 123 ..platformBrightnessTestValue = Brightness.dark ..accessibilityFeaturesTestValue = FakeAccessibilityFeatures.allOn; - tester.view.devicePixelRatio = 44; + addTearDown(() => tester.binding.platformDispatcher.clearAllTestValues()); + tester.binding.window.devicePixelRatioTestValue = 44; + addTearDown(() => tester.binding.window.clearAllTestValues()); late MediaQueryData data; MediaQueryData? outerData; @@ -337,7 +376,7 @@ void main() { builder: (BuildContext context) { outerData = MediaQuery.maybeOf(context); return MediaQuery.fromView( - view: tester.view, + view: tester.binding.window, child: Builder( builder: (BuildContext context) { rebuildCount++; @@ -354,39 +393,38 @@ void main() { expect(rebuildCount, 1); expect(data.textScaleFactor, 123); - tester.platformDispatcher.textScaleFactorTestValue = 456; + tester.binding.platformDispatcher.textScaleFactorTestValue = 456; await tester.pump(); expect(data.textScaleFactor, 456); expect(rebuildCount, 2); expect(data.platformBrightness, Brightness.dark); - tester.platformDispatcher.platformBrightnessTestValue = Brightness.light; + tester.binding.platformDispatcher.platformBrightnessTestValue = Brightness.light; await tester.pump(); expect(data.platformBrightness, Brightness.light); expect(rebuildCount, 3); expect(data.accessibleNavigation, true); - tester.platformDispatcher.accessibilityFeaturesTestValue = const FakeAccessibilityFeatures(); + tester.binding.platformDispatcher.accessibilityFeaturesTestValue = const FakeAccessibilityFeatures(); await tester.pump(); expect(data.accessibleNavigation, false); expect(rebuildCount, 4); expect(data.devicePixelRatio, 44); - tester.view.devicePixelRatio = 55; + tester.binding.window.devicePixelRatioTestValue = 55; await tester.pump(); expect(data.devicePixelRatio, 55); expect(rebuildCount, 5); }); testWidgets('MediaQuery.fromView updates on notifications (with parent data)', (WidgetTester tester) async { - addTearDown(() => tester.platformDispatcher.clearAllTestValues()); - addTearDown(() => tester.view.reset()); - - tester.platformDispatcher + tester.binding.platformDispatcher ..textScaleFactorTestValue = 123 ..platformBrightnessTestValue = Brightness.dark ..accessibilityFeaturesTestValue = FakeAccessibilityFeatures.allOn; - tester.view.devicePixelRatio = 44; + addTearDown(() => tester.binding.platformDispatcher.clearAllTestValues()); + tester.binding.window.devicePixelRatioTestValue = 44; + addTearDown(() => tester.binding.window.clearAllTestValues()); late MediaQueryData data; int rebuildCount = 0; @@ -398,7 +436,7 @@ void main() { accessibleNavigation: true, ), child: MediaQuery.fromView( - view: tester.view, + view: tester.binding.window, child: Builder( builder: (BuildContext context) { rebuildCount++; @@ -413,25 +451,25 @@ void main() { expect(rebuildCount, 1); expect(data.textScaleFactor, 44); - tester.platformDispatcher.textScaleFactorTestValue = 456; + tester.binding.platformDispatcher.textScaleFactorTestValue = 456; await tester.pump(); expect(data.textScaleFactor, 44); expect(rebuildCount, 1); expect(data.platformBrightness, Brightness.dark); - tester.platformDispatcher.platformBrightnessTestValue = Brightness.light; + tester.binding.platformDispatcher.platformBrightnessTestValue = Brightness.light; await tester.pump(); expect(data.platformBrightness, Brightness.dark); expect(rebuildCount, 1); expect(data.accessibleNavigation, true); - tester.platformDispatcher.accessibilityFeaturesTestValue = const FakeAccessibilityFeatures(); + tester.binding.platformDispatcher.accessibilityFeaturesTestValue = const FakeAccessibilityFeatures(); await tester.pump(); expect(data.accessibleNavigation, true); expect(rebuildCount, 1); expect(data.devicePixelRatio, 44); - tester.view.devicePixelRatio = 55; + tester.binding.window.devicePixelRatioTestValue = 55; await tester.pump(); expect(data.devicePixelRatio, 55); expect(rebuildCount, 2); @@ -449,7 +487,7 @@ void main() { return MediaQuery( data: MediaQueryData(textScaleFactor: textScaleFactor), child: MediaQuery.fromView( - view: tester.view, + view: tester.binding.window, child: Builder( builder: (BuildContext context) { rebuildCount++; @@ -475,7 +513,7 @@ void main() { }); testWidgets('MediaQueryData.copyWith defaults to source', (WidgetTester tester) async { - final MediaQueryData data = MediaQueryData.fromView(tester.view); + final MediaQueryData data = MediaQueryData.fromView(tester.binding.window); final MediaQueryData copied = data.copyWith(); expect(copied.size, data.size); expect(copied.devicePixelRatio, data.devicePixelRatio); @@ -514,7 +552,7 @@ void main() { ), ]; - final MediaQueryData data = MediaQueryData.fromView(tester.view); + final MediaQueryData data = MediaQueryData.fromView(tester.binding.window); final MediaQueryData copied = data.copyWith( size: customSize, devicePixelRatio: customDevicePixelRatio, @@ -1287,11 +1325,11 @@ void main() { expect(subScreenMediaQuery.displayFeatures, [cutoutDisplayFeature]); }); - testWidgets('MediaQueryData.gestureSettings is set from view.gestureSettings', (WidgetTester tester) async { - tester.view.gestureSettings = const GestureSettings(physicalDoubleTapSlop: 100, physicalTouchSlop: 100); - addTearDown(() => tester.view.resetGestureSettings()); + testWidgets('MediaQueryData.gestureSettings is set from window.viewConfiguration', (WidgetTester tester) async { + tester.binding.window.gestureSettingsTestValue = const GestureSettings(physicalDoubleTapSlop: 100, physicalTouchSlop: 100); - expect(MediaQueryData.fromView(tester.view).gestureSettings.touchSlop, closeTo(33.33, 0.1)); // Repeating, of course + expect(MediaQueryData.fromView(tester.binding.window).gestureSettings.touchSlop, closeTo(33.33, 0.1)); // Repeating, of course + tester.binding.window.clearGestureSettingsTestValue(); }); testWidgets('MediaQuery can be partially depended-on', (WidgetTester tester) async { @@ -1473,3 +1511,52 @@ Future pumpWidgetWithoutViewWrapper({required WidgetTester tester, require tester.binding.scheduleFrame(); return tester.binding.pump(); } + +class TestView implements FlutterView { + TestView({ + PlatformDispatcher? platformDispatcher, + required this.physicalSize, + required this.devicePixelRatio, + required this.padding, + required this.viewPadding, + required this.viewInsets, + required this.systemGestureInsets, + }) : _platformDispatcher = platformDispatcher; + + @override + PlatformDispatcher get platformDispatcher => _platformDispatcher!; + final PlatformDispatcher? _platformDispatcher; + @override + final Size physicalSize; + @override + final double devicePixelRatio; + @override + final ViewPadding padding; + @override + final ViewPadding viewPadding; + @override + final ViewPadding viewInsets; + @override + final ViewPadding systemGestureInsets; + @override + final List displayFeatures = []; + @override + final GestureSettings gestureSettings = const GestureSettings(); + + @override + dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); +} + +class TestViewPadding implements ViewPadding { + const TestViewPadding(this.value); + final double value; + + @override + double get bottom => value; + @override + double get left => value; + @override + double get right => value; + @override + double get top => value; +} diff --git a/packages/flutter/test/widgets/navigator_test.dart b/packages/flutter/test/widgets/navigator_test.dart index 857a549efd2..f982d605812 100644 --- a/packages/flutter/test/widgets/navigator_test.dart +++ b/packages/flutter/test/widgets/navigator_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' show FlutterView; - import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; @@ -2679,7 +2677,6 @@ void main() { group('Page api', () { Widget buildNavigator({ - required FlutterView view, required List> pages, required PopPageCallback onPopPage, GlobalKey? key, @@ -2687,7 +2684,7 @@ void main() { List observers = const [], }) { return MediaQuery( - data: MediaQueryData.fromView(view), + data: MediaQueryData.fromView(WidgetsBinding.instance.window), child: Localizations( locale: const Locale('en', 'US'), delegates: const >[ @@ -2721,12 +2718,7 @@ void main() { } await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); expect(find.text('third'), findsOneWidget); expect(find.text('second'), findsNothing); @@ -2758,42 +2750,22 @@ void main() { bool onPopPage(Route route, dynamic result) => false; await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages1, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages1, onPopPage: onPopPage, key: navigator), ); await tester.pump(); expect(find.text('initial'), findsOneWidget); // Update multiple times without waiting for pop to finish to leave // multiple popping route entries in route stack with the same page key. await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages2, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages2, onPopPage: onPopPage, key: navigator), ); await tester.pump(); await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages1, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages1, onPopPage: onPopPage, key: navigator), ); await tester.pump(); await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages2, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages2, onPopPage: onPopPage, key: navigator), ); await tester.pumpAndSettle(); @@ -2897,12 +2869,7 @@ void main() { } await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); expect(find.text('initial'), findsOneWidget); @@ -2937,12 +2904,7 @@ void main() { ]; await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); // The third page is transitioning, and the secondary animation of first // page should chain with the third page. The animation of second page @@ -2997,12 +2959,7 @@ void main() { ]; await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); await tester.pump(const Duration(milliseconds: 30)); expect(secondaryAnimationOfRouteOne.value, primaryAnimationOfRouteTwo.value); @@ -3062,12 +3019,7 @@ void main() { return route.didPop(result); } await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); expect(find.text('third'), findsOneWidget); expect(find.text('second'), findsNothing); @@ -3081,12 +3033,7 @@ void main() { myPages = myPages.reversed.toList(); await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); // Reversed routes are still chained up correctly. expect(secondaryAnimationOfRouteThree.value, primaryAnimationOfRouteTwo.value); @@ -3169,12 +3116,7 @@ void main() { } await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); expect(find.text('second'), findsOneWidget); expect(find.text('initial'), findsNothing); @@ -3203,12 +3145,7 @@ void main() { const TestPage(key: ValueKey('3'), name:'third'), ]; await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); await tester.pumpAndSettle(); expect(find.text('initial'), findsNothing); @@ -3239,12 +3176,7 @@ void main() { const TestPage(key: ValueKey('2'), name:'second'), ]; await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); // Swaps the order without any adding or removing should not trigger any // transition. The routes should update without a pumpAndSettle @@ -3316,12 +3248,7 @@ void main() { // Add initial page route with one pageless route. await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); bool initialPageless1Completed = false; navigator.currentState!.push( @@ -3337,12 +3264,7 @@ void main() { const TestPage(key: ValueKey('2'), name: 'second'), ]; await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); await tester.pumpAndSettle(); bool secondPageless1Completed = false; @@ -3367,12 +3289,7 @@ void main() { const TestPage(key: ValueKey('3'), name: 'third'), ]; await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); await tester.pumpAndSettle(); bool thirdPageless1Completed = false; @@ -3395,12 +3312,7 @@ void main() { const TestPage(key: ValueKey('2'), name: 'second'), ]; await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); // The pageless route of initial page route should be completed. expect(initialPageless1Completed, true); @@ -3412,12 +3324,7 @@ void main() { const TestPage(key: ValueKey('3'), name: 'third'), ]; await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); await tester.pumpAndSettle(); expect(secondPageless1Completed, true); @@ -3428,12 +3335,7 @@ void main() { const TestPage(key: ValueKey('4'), name: 'forth'), ]; await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); expect(thirdPageless1Completed, true); await tester.pumpAndSettle(); @@ -3454,12 +3356,7 @@ void main() { } await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); expect(find.text('second'), findsOneWidget); expect(find.text('initial'), findsNothing); @@ -3481,12 +3378,7 @@ void main() { const TestPage(key: ValueKey('2'), name:'second'), ]; await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); await tester.pumpAndSettle(); @@ -3519,7 +3411,6 @@ void main() { // Add initial page route with one pageless route. await tester.pumpWidget( buildNavigator( - view: tester.view, pages: myPages, onPopPage: onPopPage, key: navigator, @@ -3541,7 +3432,6 @@ void main() { ]; await tester.pumpWidget( buildNavigator( - view: tester.view, pages: myPages, onPopPage: onPopPage, key: navigator, @@ -3571,7 +3461,6 @@ void main() { ]; await tester.pumpWidget( buildNavigator( - view: tester.view, pages: myPages, onPopPage: onPopPage, key: navigator, @@ -3599,7 +3488,6 @@ void main() { ]; await tester.pumpWidget( buildNavigator( - view: tester.view, pages: myPages, onPopPage: onPopPage, key: navigator, @@ -3617,7 +3505,6 @@ void main() { ]; await tester.pumpWidget( buildNavigator( - view: tester.view, pages: myPages, onPopPage: onPopPage, key: navigator, @@ -3635,7 +3522,6 @@ void main() { ]; await tester.pumpWidget( buildNavigator( - view: tester.view, pages: myPages, onPopPage: onPopPage, key: navigator, @@ -3661,12 +3547,7 @@ void main() { return route.didPop(result); } await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); // Pops the second page route. @@ -3674,12 +3555,7 @@ void main() { const TestPage(key: ValueKey('1'), name: 'initial'), ]; await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); // Re-push the second page again before it finishes popping. @@ -3688,12 +3564,7 @@ void main() { const TestPage(key: ValueKey('2'), name: 'second'), ]; await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); // It should not crash the app. @@ -3713,12 +3584,7 @@ void main() { return route.didPop(result); } await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); // Pops the second page route. @@ -3726,12 +3592,7 @@ void main() { const TestPage(key: ValueKey('1'), name: 'initial'), ]; await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); // Updates the pages again before second page finishes popping. @@ -3739,12 +3600,7 @@ void main() { const TestPage(key: ValueKey('1'), name: 'initial'), ]; await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); // It should not crash the app. @@ -3765,12 +3621,7 @@ void main() { return route.didPop(result); } await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); // Pushes a pageless route. showDialog( @@ -3787,12 +3638,7 @@ void main() { const TestPage(key: ValueKey('1'), name: 'initial'), ]; await tester.pumpWidget( - buildNavigator( - view: tester.view, - pages: myPages, - onPopPage: onPopPage, - key: navigator, - ), + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), ); // It should not crash the app. expect(tester.takeException(), isNull); @@ -3831,7 +3677,6 @@ void main() { await tester.pumpWidget( buildNavigator( - view: tester.view, pages: myPages, onPopPage: onPopPage, key: navigator, @@ -3845,7 +3690,6 @@ void main() { await tester.pumpWidget( buildNavigator( - view: tester.view, pages: myPages, onPopPage: onPopPage, key: navigator, diff --git a/packages/flutter/test/widgets/slotted_render_object_widget_test.dart b/packages/flutter/test/widgets/slotted_render_object_widget_test.dart index e5ba7a55fbc..b8816d7bfba 100644 --- a/packages/flutter/test/widgets/slotted_render_object_widget_test.dart +++ b/packages/flutter/test/widgets/slotted_render_object_widget_test.dart @@ -223,7 +223,7 @@ void main() { '_RenderDiagonal#00000 relayoutBoundary=up1\n' ' │ creator: _Diagonal ← Align ← Directionality ← MediaQuery ←\n' ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' - ' │ TestFlutterView#00000] ← [root]\n' + ' │ TestWindow#00000] ← [root]\n' ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n' ' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n' ' │ size: Size(190.0, 220.0)\n' @@ -231,7 +231,7 @@ void main() { ' ├─topLeft: RenderConstrainedBox#00000 relayoutBoundary=up2\n' ' │ creator: SizedBox ← _Diagonal ← Align ← Directionality ←\n' ' │ MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' - ' │ View-[GlobalObjectKey TestFlutterView#00000] ← [root]\n' + ' │ View-[GlobalObjectKey TestWindow#00000] ← [root]\n' ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n' ' │ constraints: BoxConstraints(unconstrained)\n' ' │ size: Size(80.0, 100.0)\n' @@ -240,7 +240,7 @@ void main() { ' └─bottomRight: RenderConstrainedBox#00000 relayoutBoundary=up2\n' ' creator: SizedBox ← _Diagonal ← Align ← Directionality ←\n' ' MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' - ' View-[GlobalObjectKey TestFlutterView#00000] ← [root]\n' + ' View-[GlobalObjectKey TestWindow#00000] ← [root]\n' ' parentData: offset=Offset(80.0, 100.0) (can use size)\n' ' constraints: BoxConstraints(unconstrained)\n' ' size: Size(110.0, 120.0)\n' diff --git a/packages/flutter_localizations/test/material/date_picker_test.dart b/packages/flutter_localizations/test/material/date_picker_test.dart index 388bff225ae..8487026c0c7 100644 --- a/packages/flutter_localizations/test/material/date_picker_test.dart +++ b/packages/flutter_localizations/test/material/date_picker_test.dart @@ -227,9 +227,10 @@ void main() { const Size kCommonScreenSizeLandscape = Size(1770, 1070); Future showPicker(WidgetTester tester, Locale locale, Size size) async { - tester.view.physicalSize = size; - tester.view.devicePixelRatio = 1.0; - addTearDown(tester.view.reset); + tester.binding.window.physicalSizeTestValue = size; + addTearDown(tester.binding.window.clearPhysicalSizeTestValue); + tester.binding.window.devicePixelRatioTestValue = 1.0; + addTearDown(tester.binding.window.clearDevicePixelRatioTestValue); await tester.pumpWidget( MaterialApp( home: Builder( diff --git a/packages/flutter_localizations/test/material/time_picker_test.dart b/packages/flutter_localizations/test/material/time_picker_test.dart index 3a07db3fbd8..5f850379c9e 100644 --- a/packages/flutter_localizations/test/material/time_picker_test.dart +++ b/packages/flutter_localizations/test/material/time_picker_test.dart @@ -9,9 +9,8 @@ import 'package:flutter_test/flutter_test.dart'; void main() { testWidgets('can localize the header in all known formats - portrait', (WidgetTester tester) async { // Ensure picker is displayed in portrait mode. - tester.view.physicalSize = const Size(400, 800); - tester.view.devicePixelRatio = 1; - addTearDown(tester.view.reset); + tester.binding.window.physicalSizeTestValue = const Size(400, 800); + tester.binding.window.devicePixelRatioTestValue = 1; final Finder stringFragmentTextFinder = find.descendant( of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_StringFragment'), @@ -75,13 +74,15 @@ void main() { await tester.tapAt(Offset(center.dx, center.dy - 50.0)); await finishPicker(tester); } + + tester.binding.window.clearPhysicalSizeTestValue(); + tester.binding.window.clearDevicePixelRatioTestValue(); }); testWidgets('can localize the header in all known formats - landscape', (WidgetTester tester) async { // Ensure picker is displayed in landscape mode. - tester.view.physicalSize = const Size(800, 400); - tester.view.devicePixelRatio = 1; - addTearDown(tester.view.reset); + tester.binding.window.physicalSizeTestValue = const Size(800, 400); + tester.binding.window.devicePixelRatioTestValue = 1; final Finder stringFragmentTextFinder = find.descendant( of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_StringFragment'), @@ -150,6 +151,9 @@ void main() { await tester.tapAt(Offset(center.dx, center.dy - 50.0)); await finishPicker(tester); } + + tester.binding.window.clearPhysicalSizeTestValue(); + tester.binding.window.clearDevicePixelRatioTestValue(); }); testWidgets('can localize input mode in all known formats', (WidgetTester tester) async { diff --git a/packages/flutter_test/lib/src/binding.dart b/packages/flutter_test/lib/src/binding.dart index 05dd4b53ca8..712192241f8 100644 --- a/packages/flutter_test/lib/src/binding.dart +++ b/packages/flutter_test/lib/src/binding.dart @@ -182,18 +182,17 @@ abstract class TestWidgetsFlutterBinding extends BindingBase /// /// This constructor overrides the [debugPrint] global hook to point to /// [debugPrintOverride], which can be overridden by subclasses. - TestWidgetsFlutterBinding() : platformDispatcher = TestPlatformDispatcher( - platformDispatcher: PlatformDispatcher.instance, - ) { + TestWidgetsFlutterBinding() : _window = TestWindow(window: ui.window) { debugPrint = debugPrintOverride; debugDisableShadows = disableShadows; } @override - late final TestWindow window; + TestWindow get window => _window; + final TestWindow _window; @override - final TestPlatformDispatcher platformDispatcher; + TestPlatformDispatcher get platformDispatcher => _window.platformDispatcher; @override TestRestorationManager get restorationManager { @@ -347,12 +346,6 @@ abstract class TestWidgetsFlutterBinding extends BindingBase @override void initInstances() { - // This is intialized here because it's needed for the `super.initInstances` - // call. It can't be handled as a ctor initializer because it's dependent - // on `platformDispatcher`. It can't be handled in the ctor itself because - // the base class ctor is called first and calls `initInstances`. - window = TestWindow.fromPlatformDispatcher(platformDispatcher: platformDispatcher); - super.initInstances(); _instance = this; timeDilation = 1.0; // just in case the developer has artificially changed it for development @@ -1919,9 +1912,9 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding { @override ViewConfiguration createViewConfiguration() { - return TestViewConfiguration.fromView( + return TestViewConfiguration( size: _surfaceSize ?? _kDefaultTestViewportSize, - view: window, + window: window, ); } @@ -1945,31 +1938,20 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding { /// size is in logical pixels. The resulting ViewConfiguration maps the given /// size onto the actual display using the [BoxFit.contain] algorithm. class TestViewConfiguration extends ViewConfiguration { - /// Deprecated. Will be removed in a future version of Flutter. + /// Creates a [TestViewConfiguration] with the given size. Defaults to 800x600. /// - /// This property has been deprecated to prepare for Flutter's upcoming - /// support for multiple views and multiple windows. - /// - /// Use [TestViewConfiguration.fromView] instead. - @Deprecated( - 'Use TestViewConfiguration.fromView instead. ' - 'Deprecated to prepare for the upcoming multi-window support. ' - 'This feature was deprecated after v3.7.0-32.0.pre.' - ) + /// If a [window] instance is not provided it defaults to [ui.window]. factory TestViewConfiguration({ Size size = _kDefaultTestViewportSize, ui.FlutterView? window, }) { - return TestViewConfiguration.fromView(size: size, view: window ?? ui.window); + return TestViewConfiguration._(size, window ?? ui.window); } - /// Creates a [TestViewConfiguration] with the given size and view. - /// - /// The [size] defaults to 800x600. - TestViewConfiguration.fromView({required ui.FlutterView view, super.size = _kDefaultTestViewportSize}) - : _paintMatrix = _getMatrix(size, view.devicePixelRatio, view), - _hitTestMatrix = _getMatrix(size, 1.0, view), - super(devicePixelRatio: view.devicePixelRatio); + TestViewConfiguration._(Size size, ui.FlutterView window) + : _paintMatrix = _getMatrix(size, window.devicePixelRatio, window), + _hitTestMatrix = _getMatrix(size, 1.0, window), + super(size: size, devicePixelRatio: window.devicePixelRatio); static Matrix4 _getMatrix(Size size, double devicePixelRatio, ui.FlutterView window) { final double inverseRatio = devicePixelRatio / window.devicePixelRatio; diff --git a/packages/flutter_test/lib/src/controller.dart b/packages/flutter_test/lib/src/controller.dart index 325893e60a1..2dbbfbb42bd 100644 --- a/packages/flutter_test/lib/src/controller.dart +++ b/packages/flutter_test/lib/src/controller.dart @@ -14,7 +14,6 @@ import 'event_simulation.dart'; import 'finders.dart'; import 'test_async_utils.dart'; import 'test_pointer.dart'; -import 'window.dart'; /// The default drag touch slop used to break up a large drag into multiple /// smaller moves. @@ -235,37 +234,6 @@ abstract class WidgetController { /// A reference to the current instance of the binding. final WidgetsBinding binding; - /// The [TestPlatformDispatcher] that is being used in this test. - /// - /// This will be injected into the framework such that calls to - /// [WidgetsBinding.platformDispatcher] will use this. This allows - /// users to change platform specific properties for testing. - /// - /// See also: - /// - /// * [TestFlutterView] which allows changing view specific properties - /// for testing - /// * [view] and [viewOf] which are used to find - /// [TestFlutterView]s from the widget tree - TestPlatformDispatcher get platformDispatcher => binding.platformDispatcher as TestPlatformDispatcher; - - /// The [TestFlutterView] provided by default when testing with - /// [WidgetTester.pumpWidget]. - /// - /// If the test requires multiple views, it will need to use [viewOf] instead - /// to ensure that the view related to the widget being evaluated is the one - /// that gets updated. - /// - /// See also: - /// - /// * [viewOf], which can find a [TestFlutterView] related to a given finder. - /// This is how to modify view properties for testing when dealing with - /// multiple views. - TestFlutterView get view { - assert(platformDispatcher.views.length == 1, 'When testing with multiple views, use `viewOf` instead.'); - return platformDispatcher.views.single; - } - /// Provides access to a [SemanticsController] for testing anything related to /// the [Semantics] tree. /// @@ -289,26 +257,6 @@ abstract class WidgetController { // TODO(ianh): verify that the return values are of type T and throw // a good message otherwise, in all the generic methods below - /// Finds the [TestFlutterView] that is the closest ancestor of the widget - /// found by [finder]. - /// - /// [TestFlutterView] can be used to modify view specific properties for testing. - /// - /// See also: - /// - /// * [view] which returns the [TestFlutterView] used when only a single - /// view is being used. - TestFlutterView viewOf(Finder finder) { - final View view = firstWidget( - find.ancestor( - of: finder, - matching: find.byType(View), - ) - ); - - return view.view as TestFlutterView; - } - /// Checks if `finder` exists in the tree. bool any(Finder finder) { TestAsyncUtils.guardSync(); diff --git a/packages/flutter_test/lib/src/window.dart b/packages/flutter_test/lib/src/window.dart index 20a9f0a6724..4a7a0c8ff4b 100644 --- a/packages/flutter_test/lib/src/window.dart +++ b/packages/flutter_test/lib/src/window.dart @@ -2,950 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' hide window; +import 'dart:ui' as ui hide window; import 'package:flutter/foundation.dart'; -/// Test version of [AccessibilityFeatures] in which specific features may -/// be set to arbitrary values. -/// -/// By default, all features are disabled. For an instance where all the -/// features are enabled, consider the [FakeAccessibilityFeatures.allOn] -/// constant. -@immutable -// ignore: avoid_implementing_value_types -class FakeAccessibilityFeatures implements AccessibilityFeatures { - /// Creates a test instance of [AccessibilityFeatures]. - /// - /// By default, all features are disabled. - const FakeAccessibilityFeatures({ - this.accessibleNavigation = false, - this.invertColors = false, - this.disableAnimations = false, - this.boldText = false, - this.reduceMotion = false, - this.highContrast = false, - this.onOffSwitchLabels = false, - }); - - /// An instance of [AccessibilityFeatures] where all the features are enabled. - static const FakeAccessibilityFeatures allOn = FakeAccessibilityFeatures( - accessibleNavigation: true, - invertColors: true, - disableAnimations: true, - boldText: true, - reduceMotion: true, - highContrast: true, - onOffSwitchLabels: true, - ); - - @override - final bool accessibleNavigation; - - @override - final bool invertColors; - - @override - final bool disableAnimations; - - @override - final bool boldText; - - @override - final bool reduceMotion; - - @override - final bool highContrast; - - @override - final bool onOffSwitchLabels; - - @override - bool operator ==(Object other) { - if (other.runtimeType != runtimeType) { - return false; - } - return other is FakeAccessibilityFeatures - && other.accessibleNavigation == accessibleNavigation - && other.invertColors == invertColors - && other.disableAnimations == disableAnimations - && other.boldText == boldText - && other.reduceMotion == reduceMotion - && other.highContrast == highContrast - && other.onOffSwitchLabels == onOffSwitchLabels; - } - - @override - int get hashCode { - return Object.hash( - accessibleNavigation, - invertColors, - disableAnimations, - boldText, - reduceMotion, - highContrast, - onOffSwitchLabels, - ); - } - - /// This gives us some grace time when the dart:ui side adds something to - /// [AccessibilityFeatures], and makes things easier when we do rolls to - /// give us time to catch up. - /// - /// If you would like to add to this class, changes must first be made in the - /// engine, followed by the framework. - @override - dynamic noSuchMethod(Invocation invocation) { - return null; - } -} - -/// Used to fake insets and padding for [TestFlutterView]s. -/// -/// See also: -/// -/// * [TestFlutterView.padding], [TestFlutterView.systemGestureInsets], -/// [TestFlutterView.viewInsets], and [TestFlutterView.viewPadding] for test -/// properties that make use of [FakeViewPadding]. -@immutable -class FakeViewPadding implements ViewPadding { - /// Instantiates a new [FakeViewPadding] object for faking insets and padding - /// during tests. - const FakeViewPadding({ - this.left = 0.0, - this.top = 0.0, - this.right = 0.0, - this.bottom = 0.0, - }); - - FakeViewPadding._wrap(ViewPadding base) : - left = base.left, - top = base.top, - right = base.right, - bottom = base.bottom; - - @override - final double left; - - @override - final double top; - - @override - final double right; - - @override - final double bottom; -} - -/// [PlatformDispatcher] that wraps another [PlatformDispatcher] and -/// allows faking of some properties for testing purposes. -/// -/// See also: -/// -/// * [TestFlutterView], which wraps a [FlutterView] for testing and -/// mocking purposes. -/// * [TestWindow], which wraps a [SingletonFlutterWindow] for -/// testing and mocking purposes. -class TestPlatformDispatcher implements PlatformDispatcher { - /// Constructs a [TestPlatformDispatcher] that defers all behavior to the given - /// [PlatformDispatcher] unless explicitly overridden for test purposes. - TestPlatformDispatcher({ - required PlatformDispatcher platformDispatcher, - }) : _platformDispatcher = platformDispatcher { - _updateViews(); - _platformDispatcher.onMetricsChanged = _handleMetricsChanged; - } - - /// The [PlatformDispatcher] that is wrapped by this [TestPlatformDispatcher]. - final PlatformDispatcher _platformDispatcher; - - @override - TestFlutterView? get implicitView { - return _platformDispatcher.implicitView != null - ? _testViews[_platformDispatcher.implicitView!.viewId]! - : null; - } - - final Map _testViews = {}; - - @override - VoidCallback? get onMetricsChanged => _platformDispatcher.onMetricsChanged; - VoidCallback? _onMetricsChanged; - @override - set onMetricsChanged(VoidCallback? callback) { - _onMetricsChanged = callback; - } - - void _handleMetricsChanged() { - _updateViews(); - _onMetricsChanged?.call(); - } - - @override - Locale get locale => _localeTestValue ?? _platformDispatcher.locale; - Locale? _localeTestValue; - /// Hides the real locale and reports the given [localeTestValue] instead. - set localeTestValue(Locale localeTestValue) { // ignore: avoid_setters_without_getters - _localeTestValue = localeTestValue; - onLocaleChanged?.call(); - } - - /// Deletes any existing test locale and returns to using the real locale. - void clearLocaleTestValue() { - _localeTestValue = null; - onLocaleChanged?.call(); - } - - @override - List get locales => _localesTestValue ?? _platformDispatcher.locales; - List? _localesTestValue; - /// Hides the real locales and reports the given [localesTestValue] instead. - set localesTestValue(List localesTestValue) { // ignore: avoid_setters_without_getters - _localesTestValue = localesTestValue; - onLocaleChanged?.call(); - } - - /// Deletes any existing test locales and returns to using the real locales. - void clearLocalesTestValue() { - _localesTestValue = null; - onLocaleChanged?.call(); - } - - @override - VoidCallback? get onLocaleChanged => _platformDispatcher.onLocaleChanged; - @override - set onLocaleChanged(VoidCallback? callback) { - _platformDispatcher.onLocaleChanged = callback; - } - - @override - String get initialLifecycleState => _initialLifecycleStateTestValue; - String _initialLifecycleStateTestValue = ''; - /// Sets a faked initialLifecycleState for testing. - set initialLifecycleStateTestValue(String state) { // ignore: avoid_setters_without_getters - _initialLifecycleStateTestValue = state; - } - - /// Resets [initialLifecycleState] to the default value for the platform. - void resetInitialLifecycleState() { - _initialLifecycleStateTestValue = ''; - } - - @override - double get textScaleFactor => _textScaleFactorTestValue ?? _platformDispatcher.textScaleFactor; - double? _textScaleFactorTestValue; - /// Hides the real text scale factor and reports the given - /// [textScaleFactorTestValue] instead. - set textScaleFactorTestValue(double textScaleFactorTestValue) { // ignore: avoid_setters_without_getters - _textScaleFactorTestValue = textScaleFactorTestValue; - onTextScaleFactorChanged?.call(); - } - - /// Deletes any existing test text scale factor and returns to using the real - /// text scale factor. - void clearTextScaleFactorTestValue() { - _textScaleFactorTestValue = null; - onTextScaleFactorChanged?.call(); - } - - @override - Brightness get platformBrightness => _platformBrightnessTestValue ?? _platformDispatcher.platformBrightness; - Brightness? _platformBrightnessTestValue; - @override - VoidCallback? get onPlatformBrightnessChanged => _platformDispatcher.onPlatformBrightnessChanged; - @override - set onPlatformBrightnessChanged(VoidCallback? callback) { - _platformDispatcher.onPlatformBrightnessChanged = callback; - } - /// Hides the real text scale factor and reports the given - /// [platformBrightnessTestValue] instead. - set platformBrightnessTestValue(Brightness platformBrightnessTestValue) { // ignore: avoid_setters_without_getters - _platformBrightnessTestValue = platformBrightnessTestValue; - onPlatformBrightnessChanged?.call(); - } - - /// Deletes any existing test platform brightness and returns to using the - /// real platform brightness. - void clearPlatformBrightnessTestValue() { - _platformBrightnessTestValue = null; - onPlatformBrightnessChanged?.call(); - } - - @override - bool get alwaysUse24HourFormat => _alwaysUse24HourFormatTestValue ?? _platformDispatcher.alwaysUse24HourFormat; - bool? _alwaysUse24HourFormatTestValue; - /// Hides the real clock format and reports the given - /// [alwaysUse24HourFormatTestValue] instead. - set alwaysUse24HourFormatTestValue(bool alwaysUse24HourFormatTestValue) { // ignore: avoid_setters_without_getters - _alwaysUse24HourFormatTestValue = alwaysUse24HourFormatTestValue; - } - - /// Deletes any existing test clock format and returns to using the real clock - /// format. - void clearAlwaysUse24HourTestValue() { - _alwaysUse24HourFormatTestValue = null; - } - - @override - VoidCallback? get onTextScaleFactorChanged => _platformDispatcher.onTextScaleFactorChanged; - @override - set onTextScaleFactorChanged(VoidCallback? callback) { - _platformDispatcher.onTextScaleFactorChanged = callback; - } - - @override - bool get nativeSpellCheckServiceDefined => _nativeSpellCheckServiceDefinedTestValue ?? _platformDispatcher.nativeSpellCheckServiceDefined; - bool? _nativeSpellCheckServiceDefinedTestValue; - set nativeSpellCheckServiceDefinedTestValue(bool nativeSpellCheckServiceDefinedTestValue) { // ignore: avoid_setters_without_getters - _nativeSpellCheckServiceDefinedTestValue = nativeSpellCheckServiceDefinedTestValue; - } - - /// Deletes existing value that determines whether or not a native spell check - /// service is defined and returns to the real value. - void clearNativeSpellCheckServiceDefined() { - _nativeSpellCheckServiceDefinedTestValue = null; - } - - @override - bool get brieflyShowPassword => _brieflyShowPasswordTestValue ?? _platformDispatcher.brieflyShowPassword; - bool? _brieflyShowPasswordTestValue; - /// Hides the real [brieflyShowPassword] and reports the given - /// `brieflyShowPasswordTestValue` instead. - set brieflyShowPasswordTestValue(bool brieflyShowPasswordTestValue) { // ignore: avoid_setters_without_getters - _brieflyShowPasswordTestValue = brieflyShowPasswordTestValue; - } - - /// Resets [brieflyShowPassword] to the default value for the platform. - void resetBrieflyShowPassword() { - _brieflyShowPasswordTestValue = null; - } - - @override - FrameCallback? get onBeginFrame => _platformDispatcher.onBeginFrame; - @override - set onBeginFrame(FrameCallback? callback) { - _platformDispatcher.onBeginFrame = callback; - } - - @override - VoidCallback? get onDrawFrame => _platformDispatcher.onDrawFrame; - @override - set onDrawFrame(VoidCallback? callback) { - _platformDispatcher.onDrawFrame = callback; - } - - @override - TimingsCallback? get onReportTimings => _platformDispatcher.onReportTimings; - @override - set onReportTimings(TimingsCallback? callback) { - _platformDispatcher.onReportTimings = callback; - } - - @override - PointerDataPacketCallback? get onPointerDataPacket => _platformDispatcher.onPointerDataPacket; - @override - set onPointerDataPacket(PointerDataPacketCallback? callback) { - _platformDispatcher.onPointerDataPacket = callback; - } - - @override - String get defaultRouteName => _defaultRouteNameTestValue ?? _platformDispatcher.defaultRouteName; - String? _defaultRouteNameTestValue; - /// Hides the real default route name and reports the given - /// [defaultRouteNameTestValue] instead. - set defaultRouteNameTestValue(String defaultRouteNameTestValue) { // ignore: avoid_setters_without_getters - _defaultRouteNameTestValue = defaultRouteNameTestValue; - } - - /// Deletes any existing test default route name and returns to using the real - /// default route name. - void clearDefaultRouteNameTestValue() { - _defaultRouteNameTestValue = null; - } - - @override - void scheduleFrame() { - _platformDispatcher.scheduleFrame(); - } - - @override - bool get semanticsEnabled => _semanticsEnabledTestValue ?? _platformDispatcher.semanticsEnabled; - bool? _semanticsEnabledTestValue; - /// Hides the real semantics enabled and reports the given - /// [semanticsEnabledTestValue] instead. - set semanticsEnabledTestValue(bool semanticsEnabledTestValue) { // ignore: avoid_setters_without_getters - _semanticsEnabledTestValue = semanticsEnabledTestValue; - onSemanticsEnabledChanged?.call(); - } - - /// Deletes any existing test semantics enabled and returns to using the real - /// semantics enabled. - void clearSemanticsEnabledTestValue() { - _semanticsEnabledTestValue = null; - onSemanticsEnabledChanged?.call(); - } - - @override - VoidCallback? get onSemanticsEnabledChanged => _platformDispatcher.onSemanticsEnabledChanged; - @override - set onSemanticsEnabledChanged(VoidCallback? callback) { - _platformDispatcher.onSemanticsEnabledChanged = callback; - } - - @override - SemanticsActionCallback? get onSemanticsAction => _platformDispatcher.onSemanticsAction; - @override - set onSemanticsAction(SemanticsActionCallback? callback) { - _platformDispatcher.onSemanticsAction = callback; - } - - @override - AccessibilityFeatures get accessibilityFeatures => _accessibilityFeaturesTestValue ?? _platformDispatcher.accessibilityFeatures; - AccessibilityFeatures? _accessibilityFeaturesTestValue; - /// Hides the real accessibility features and reports the given - /// [accessibilityFeaturesTestValue] instead. - /// - /// Consider using [FakeAccessibilityFeatures] to provide specific - /// values for the various accessibility features under test. - set accessibilityFeaturesTestValue(AccessibilityFeatures accessibilityFeaturesTestValue) { // ignore: avoid_setters_without_getters - _accessibilityFeaturesTestValue = accessibilityFeaturesTestValue; - onAccessibilityFeaturesChanged?.call(); - } - - /// Deletes any existing test accessibility features and returns to using the - /// real accessibility features. - void clearAccessibilityFeaturesTestValue() { - _accessibilityFeaturesTestValue = null; - onAccessibilityFeaturesChanged?.call(); - } - - @override - VoidCallback? get onAccessibilityFeaturesChanged => _platformDispatcher.onAccessibilityFeaturesChanged; - @override - set onAccessibilityFeaturesChanged(VoidCallback? callback) { - _platformDispatcher.onAccessibilityFeaturesChanged = callback; - } - - @override - void setIsolateDebugName(String name) { - _platformDispatcher.setIsolateDebugName(name); - } - - @override - void sendPlatformMessage( - String name, - ByteData? data, - PlatformMessageResponseCallback? callback, - ) { - _platformDispatcher.sendPlatformMessage(name, data, callback); - } - - @Deprecated( - 'Instead of calling this callback, use ServicesBinding.instance.channelBuffers.push. ' - 'This feature was deprecated after v2.1.0-10.0.pre.' - ) - @override - PlatformMessageCallback? get onPlatformMessage => _platformDispatcher.onPlatformMessage; - @Deprecated( - 'Instead of setting this callback, use ServicesBinding.instance.defaultBinaryMessenger.setMessageHandler. ' - 'This feature was deprecated after v2.1.0-10.0.pre.' - ) - @override - set onPlatformMessage(PlatformMessageCallback? callback) { - _platformDispatcher.onPlatformMessage = callback; - } - - /// Delete any test value properties that have been set on this [TestPlatformDispatcher] - /// and return to reporting the real [PlatformDispatcher] values for all - /// [PlatformDispatcher] properties. - /// - /// If desired, clearing of properties can be done on an individual basis, - /// e.g., [clearLocaleTestValue]. - void clearAllTestValues() { - clearAccessibilityFeaturesTestValue(); - clearAlwaysUse24HourTestValue(); - clearDefaultRouteNameTestValue(); - clearPlatformBrightnessTestValue(); - clearLocaleTestValue(); - clearLocalesTestValue(); - clearSemanticsEnabledTestValue(); - clearTextScaleFactorTestValue(); - clearNativeSpellCheckServiceDefined(); - resetBrieflyShowPassword(); - resetInitialLifecycleState(); - resetSystemFontFamily(); - } - - @override - VoidCallback? get onFrameDataChanged => _platformDispatcher.onFrameDataChanged; - @override - set onFrameDataChanged(VoidCallback? value) { - _platformDispatcher.onFrameDataChanged = value; - } - - @override - KeyDataCallback? get onKeyData => _platformDispatcher.onKeyData; - - @override - set onKeyData(KeyDataCallback? onKeyData) { - _platformDispatcher.onKeyData = onKeyData; - } - - @override - VoidCallback? get onPlatformConfigurationChanged => _platformDispatcher.onPlatformConfigurationChanged; - - @override - set onPlatformConfigurationChanged(VoidCallback? onPlatformConfigurationChanged) { - _platformDispatcher.onPlatformConfigurationChanged = onPlatformConfigurationChanged; - } - - @override - Locale? computePlatformResolvedLocale(List supportedLocales) => _platformDispatcher.computePlatformResolvedLocale(supportedLocales); - - @override - ByteData? getPersistentIsolateData() => _platformDispatcher.getPersistentIsolateData(); - - @override - Iterable get views => _testViews.values; - - void _updateViews() { - final List extraKeys = [..._testViews.keys]; - for (final FlutterView view in _platformDispatcher.views) { - extraKeys.remove(view.viewId); - if (!_testViews.containsKey(view.viewId)) { - _testViews[view.viewId] = TestFlutterView(view: view, platformDispatcher: this); - } - } - - extraKeys.forEach(_testViews.remove); - } - - @override - ErrorCallback? get onError => _platformDispatcher.onError; - @override - set onError(ErrorCallback? value) { - _platformDispatcher.onError; - } - - @override - VoidCallback? get onSystemFontFamilyChanged => _platformDispatcher.onSystemFontFamilyChanged; - @override - set onSystemFontFamilyChanged(VoidCallback? value) { - _platformDispatcher.onSystemFontFamilyChanged = value; - } - - @override - FrameData get frameData => _platformDispatcher.frameData; - - @override - void registerBackgroundIsolate(RootIsolateToken token) { - _platformDispatcher.registerBackgroundIsolate(token); - } - - @override - void requestDartPerformanceMode(DartPerformanceMode mode) { - _platformDispatcher.requestDartPerformanceMode(mode); - } - - /// The system font family to use for this test. - /// - /// Defaults to the value provided by [PlatformDispatcher.systemFontFamily]. - /// This can only be set in a test environment to emulate different platform - /// configurations. A standard [PlatformDispatcher] is not mutable from the - /// framework. - /// - /// Setting this value to `null` will force [systemFontFamily] to return - /// `null`. If you want to have the value default to the platform - /// [systemFontFamily], use [resetSystemFontFamily]. - /// - /// See also: - /// - /// * [PlatformDispatcher.systemFontFamily] for the standard implementation - /// * [resetSystemFontFamily] to reset this value specifically - /// * [clearAllTestValues] to reset all test values for this view - @override - String? get systemFontFamily { - return _forceSystemFontFamilyToBeNull - ? null - : _systemFontFamily ?? _platformDispatcher.systemFontFamily; - } - String? _systemFontFamily; - bool _forceSystemFontFamilyToBeNull = false; - set systemFontFamily(String? value) { - _systemFontFamily = value; - if (value == null) { - _forceSystemFontFamilyToBeNull = true; - } - onSystemFontFamilyChanged?.call(); - } - - /// Resets [systemFontFamily] to the default for the platform. - void resetSystemFontFamily() { - _systemFontFamily = null; - _forceSystemFontFamilyToBeNull = false; - onSystemFontFamilyChanged?.call(); - } - - @override - void updateSemantics(SemanticsUpdate update) { - // Using the deprecated method to maintain backwards compatibility during - // the multi-view transition window. - // ignore: deprecated_member_use - _platformDispatcher.updateSemantics(update); - } - - /// This gives us some grace time when the dart:ui side adds something to - /// [PlatformDispatcher], and makes things easier when we do rolls to give - /// us time to catch up. - @override - dynamic noSuchMethod(Invocation invocation) { - return null; - } -} - -/// A [FlutterView] that wraps another [FlutterView] and allows faking of -/// some properties for testing purposes. -/// -/// This class should not be instantiated manually, as -/// it requires a backing [FlutterView] that must be produced from -/// a [PlatformDispatcher]. -/// -/// See also: -/// -/// * [WidgetTester.view] which allows for accessing the [TestFlutterView] -/// for single view applications or widget testing. -/// * [WidgetTester.viewOf] which allows for accessing the appropriate -/// [TestFlutterView] in a given situation for multi-view applications. -/// * [TestPlatformDispatcher], which allows for faking of platform specific -/// functionality. -class TestFlutterView implements FlutterView { - /// Constructs a [TestFlutterView] that defers all behavior to the given - /// [FlutterView] unless explicitly overridden for testing. - TestFlutterView({ - required FlutterView view, - required TestPlatformDispatcher platformDispatcher, - }) : _view = view, _platformDispatcher = platformDispatcher; - - /// The [FlutterView] backing this [TestFlutterView]. - final FlutterView _view; - - @override - TestPlatformDispatcher get platformDispatcher => _platformDispatcher; - final TestPlatformDispatcher _platformDispatcher; - - @override - Object get viewId => _view.viewId; - - /// The device pixel ratio to use for this test. - /// - /// Defaults to the value provided by [FlutterView.devicePixelRatio]. This - /// can only be set in a test environment to emulate different view - /// configurations. A standard [FlutterView] is not mutable from the framework. - /// - /// See also: - /// - /// * [FlutterView.devicePixelRatio] for the standard implementation - /// * [resetDevicePixelRatio] to reset this value specifically - /// * [reset] to reset all test values for this view - @override - double get devicePixelRatio => _devicePixelRatio ?? _view.devicePixelRatio; - double? _devicePixelRatio; - set devicePixelRatio(double value) { - _devicePixelRatio = value; - platformDispatcher.onMetricsChanged?.call(); - } - - /// Resets [devicePixelRatio] for this test view to the default value for this view. - void resetDevicePixelRatio() { - _devicePixelRatio = null; - platformDispatcher.onMetricsChanged?.call(); - } - - /// The display features to use for this test. - /// - /// Defaults to the value provided by [FlutterView.displayFeatures]. This - /// can only be set in a test environment to emulate different view - /// configurations. A standard [FlutterView] is not mutable from the framework. - /// - /// See also: - /// - /// * [FlutterView.displayFeatures] for the standard implementation - /// * [resetDisplayFeatures] to reset this value specifically - /// * [reset] to reset all test values for this view - @override - List get displayFeatures => _displayFeatures ?? _view.displayFeatures; - List? _displayFeatures; - set displayFeatures(List value) { - _displayFeatures = value; - platformDispatcher.onMetricsChanged?.call(); - } - - /// Resets [displayFeatures] to the default values for this view. - void resetDisplayFeatures() { - _displayFeatures = null; - platformDispatcher.onMetricsChanged?.call(); - } - - /// The padding to use for this test. - /// - /// Defaults to the value provided by [FlutterView.padding]. This - /// can only be set in a test environment to emulate different view - /// configurations. A standard [FlutterView] is not mutable from the framework. - /// - /// See also: - /// - /// * [FakeViewPadding] which is used to set this value for testing - /// * [FlutterView.padding] for the standard implementation. - /// * [resetPadding] to reset this value specifically. - /// * [reset] to reset all test values for this view. - @override - FakeViewPadding get padding => _padding ?? FakeViewPadding._wrap(_view.padding); - FakeViewPadding? _padding; - set padding(FakeViewPadding value) { - _padding = value; - platformDispatcher.onMetricsChanged?.call(); - } - - /// Resets [padding] to the default value for this view. - void resetPadding() { - _padding = null; - platformDispatcher.onMetricsChanged?.call(); - } - - /// The physical geometry to use for this test. - /// - /// Defaults to the value provided by [FlutterView.physicalGeometry]. This - /// can only be set in a test environment to emulate different view - /// configurations. A standard [FlutterView] is not mutable from the framework. - /// - /// This property and [physicalSize] are dependent on one another. If both - /// properties are set through their test setters, the final result will be - /// that [physicalGeometry] determines the location and [physicalSize] - /// determines the size of the [physicalGeometry] [Rect]. If only - /// [physicalSize] is set, the final result is that the default value of - /// [physicalGeometry] determines the location and [physicalSize] determines - /// the size of the [physicalGeometry] [Rect]. If only [physicalGeometry] - /// is set, it will determine both the location and size of the - /// [physicalGeometry] [Rect]. - /// - /// See also: - /// - /// * [FlutterView.physicalGeometry] for the standard implementation - /// * [resetPhysicalGeometry] to reset this value specifically - /// * [reset] to reset all test values for this view - @override - Rect get physicalGeometry { - Rect value = _physicalGeometry ?? _view.physicalGeometry; - if (_physicalSize != null) { - value = value.topLeft & _physicalSize!; - } - return value; - } - Rect? _physicalGeometry; - set physicalGeometry(Rect value) { - _physicalGeometry = value; - platformDispatcher.onMetricsChanged?.call(); - } - - /// Resets [physicalGeometry] to the default value for this view. - /// - /// This will also reset [physicalSize] as the values are dependent - /// on one another. - void resetPhysicalGeometry() { - _physicalGeometry = null; - _physicalSize = null; - platformDispatcher.onMetricsChanged?.call(); - } - - /// The physical size to use for this test. - /// - /// Defaults to the value provided by [FlutterView.physicalSize]. This - /// can only be set in a test environment to emulate different view - /// configurations. A standard [FlutterView] is not mutable from the framework. - /// - /// This property and [physicalGeometry] are dependent on one another. If both - /// properties are set through their test setters, the final result will be - /// that [physicalGeometry] determines the location and [physicalSize] - /// determines the size of the [physicalGeometry] [Rect]. If only - /// [physicalSize] is set, the final result is that the default value of - /// [physicalGeometry] determines the location and [physicalSize] determines - /// the size of the [physicalGeometry] [Rect]. If only [physicalGeometry] - /// is set, it will determine both the location and size of the - /// [physicalGeometry] [Rect]. - /// - /// See also: - /// - /// * [FlutterView.physicalSize] for the standard implementation - /// * [resetPhysicalSize] to reset this value specifically - /// * [reset] to reset all test values for this view - @override - Size get physicalSize { - // This has to be able to default to `_view.physicalSize` as web_ui handles - // `physicalSize` and `physicalGeometry` differently than dart:ui, where - // the values are both based off of `physicalGeometry`. - return _physicalSize ?? _physicalGeometry?.size ?? _view.physicalSize; - } - Size? _physicalSize; - set physicalSize(Size value) { - _physicalSize = value; - platformDispatcher.onMetricsChanged?.call(); - } - - /// Resets [physicalSize] to the default value for this view. - /// - /// This will also reset [physicalGeometry] as the values are dependent - /// on one another. - void resetPhysicalSize() { - resetPhysicalGeometry(); - } - - /// The system gesture insets to use for this test. - /// - /// Defaults to the value provided by [FlutterView.systemGestureInsets]. - /// This can only be set in a test environment to emulate different view - /// configurations. A standard [FlutterView] is not mutable from the framework. - /// - /// See also: - /// - /// * [FakeViewPadding] which is used to set this value for testing - /// * [FlutterView.systemGestureInsets] for the standard implementation - /// * [resetSystemGestureInsets] to reset this value specifically - /// * [reset] to reset all test values for this view - @override - FakeViewPadding get systemGestureInsets => _systemGestureInsets ?? FakeViewPadding._wrap(_view.systemGestureInsets); - FakeViewPadding? _systemGestureInsets; - set systemGestureInsets(FakeViewPadding value) { - _systemGestureInsets = value; - platformDispatcher.onMetricsChanged?.call(); - } - - /// Resets [systemGestureInsets] to the default value for this view. - void resetSystemGestureInsets() { - _systemGestureInsets = null; - platformDispatcher.onMetricsChanged?.call(); - } - - /// The view insets to use for this test. - /// - /// Defaults to the value provided by [FlutterView.viewInsets]. This - /// can only be set in a test environment to emulate different view - /// configurations. A standard [FlutterView] is not mutable from the framework. - /// - /// See also: - /// - /// * [FakeViewPadding] which is used to set this value for testing - /// * [FlutterView.viewInsets] for the standard implementation - /// * [resetViewInsets] to reset this value specifically - /// * [reset] to reset all test values for this view - @override - FakeViewPadding get viewInsets => _viewInsets ?? FakeViewPadding._wrap(_view.viewInsets); - FakeViewPadding? _viewInsets; - set viewInsets(FakeViewPadding value) { - _viewInsets = value; - platformDispatcher.onMetricsChanged?.call(); - } - - /// Resets [viewInsets] to the default value for this view. - void resetViewInsets() { - _viewInsets = null; - platformDispatcher.onMetricsChanged?.call(); - } - - /// The view padding to use for this test. - /// - /// Defaults to the value provided by [FlutterView.viewPadding]. This - /// can only be set in a test environment to emulate different view - /// configurations. A standard [FlutterView] is not mutable from the framework. - /// - /// See also: - /// - /// * [FakeViewPadding] which is used to set this value for testing - /// * [FlutterView.viewPadding] for the standard implementation - /// * [resetViewPadding] to reset this value specifically - /// * [reset] to reset all test values for this view - @override - FakeViewPadding get viewPadding => _viewPadding ?? FakeViewPadding._wrap(_view.viewPadding); - FakeViewPadding? _viewPadding; - set viewPadding(FakeViewPadding value) { - _viewPadding = value; - platformDispatcher.onMetricsChanged?.call(); - } - - /// Resets [viewPadding] to the default value for this view. - void resetViewPadding() { - _viewPadding = null; - platformDispatcher.onMetricsChanged?.call(); - } - - /// The gesture settings to use for this test. - /// - /// Defaults to the value provided by [FlutterView.gestureSettings]. This - /// can only be set in a test environment to emulate different view - /// configurations. A standard [FlutterView] is not mutable from the framework. - /// - /// See also: - /// - /// * [FlutterView.gestureSettings] for the standard implementation - /// * [resetGestureSettings] to reset this value specifically - /// * [reset] to reset all test values for this view - @override - GestureSettings get gestureSettings => _gestureSettings ?? _view.gestureSettings; - GestureSettings? _gestureSettings; - set gestureSettings(GestureSettings value) { - _gestureSettings = value; - platformDispatcher.onMetricsChanged?.call(); - } - - /// Resets [gestureSettings] to the default value for this view. - void resetGestureSettings() { - _gestureSettings = null; - platformDispatcher.onMetricsChanged?.call(); - } - - @override - void render(Scene scene) { - _view.render(scene); - } - - @override - void updateSemantics(SemanticsUpdate update) { - _view.updateSemantics(update); - } - - /// Resets all test values to the defaults for this view. - /// - /// See also: - /// - /// * [resetDevicePixelRatio] to reset [devicePixelRatio] specifically - /// * [resetDisplayFeatures] to reset [displayFeatures] specifically - /// * [resetPadding] to reset [padding] specifically - /// * [resetPhysicalGeometry] to reset [physicalGeometry] specifically - /// * [resetPhysicalSize] to reset [physicalSize] specifically - /// * [resetSystemGestureInsets] to reset [systemGestureInsets] specifically - /// * [resetViewInsets] to reset [viewInsets] specifically - /// * [resetViewPadding] to reset [viewPadding] specifically - /// * [resetGestureSettings] to reset [gestureSettings] specifically - void reset() { - resetDevicePixelRatio(); - resetDisplayFeatures(); - resetPadding(); - resetPhysicalGeometry(); - // Skipping resetPhysicalSize because resetPhysicalGeometry resets both values. - resetSystemGestureInsets(); - resetViewInsets(); - resetViewPadding(); - resetGestureSettings(); - } - - /// This gives us some grace time when the dart:ui side adds something to - /// [FlutterView], and makes things easier when we do rolls to give - /// us time to catch up. - @override - dynamic noSuchMethod(Invocation invocation) { - return null; - } -} - /// [SingletonFlutterWindow] that wraps another [SingletonFlutterWindow] and /// allows faking of some properties for testing purposes. /// @@ -991,170 +51,155 @@ class TestFlutterView implements FlutterView { /// * [TestPlatformDispatcher], which wraps a [PlatformDispatcher] for /// testing purposes and is used by the [platformDispatcher] property of /// this class. -class TestWindow implements SingletonFlutterWindow { +class TestWindow implements ui.SingletonFlutterWindow { /// Constructs a [TestWindow] that defers all behavior to the given - /// [SingletonFlutterWindow] unless explicitly overridden for test purposes. + /// [dart:ui.SingletonFlutterWindow] unless explicitly overridden for test purposes. TestWindow({ - required SingletonFlutterWindow window, - }) : platformDispatcher = TestPlatformDispatcher(platformDispatcher: window.platformDispatcher); + required ui.SingletonFlutterWindow window, + }) : _window = window, + platformDispatcher = TestPlatformDispatcher(platformDispatcher: window.platformDispatcher); - /// Constructs a [TestWindow] that defers all behavior to the given - /// [TestPlatformDispatcher] and its [TestPlatformDispatcher.implicitView]. - /// - /// This class will not work when multiple views are present. If multiple view - /// support is needed use [WidgetTester.platformDispatcher] and - /// [WidgetTester.viewOf]. - /// - /// See also: - /// - /// * [TestPlatformDispatcher] which allows faking of platform-wide values for - /// testing purposes. - /// * [TestFlutterView] which allows faking of view-specific values for - /// testing purposes. - TestWindow.fromPlatformDispatcher({ - required this.platformDispatcher, - }); + /// The [dart:ui.SingletonFlutterWindow] that is wrapped by this [TestWindow]. + final ui.SingletonFlutterWindow _window; @override final TestPlatformDispatcher platformDispatcher; - TestFlutterView get _view => platformDispatcher.implicitView!; - @override - double get devicePixelRatio => _view.devicePixelRatio; + double get devicePixelRatio => _devicePixelRatio ?? _window.devicePixelRatio; + double? _devicePixelRatio; /// Hides the real device pixel ratio and reports the given [devicePixelRatio] /// instead. - // ignore: avoid_setters_without_getters - set devicePixelRatioTestValue(double devicePixelRatio) { - _view.devicePixelRatio = devicePixelRatio; + set devicePixelRatioTestValue(double devicePixelRatio) { // ignore: avoid_setters_without_getters + _devicePixelRatio = devicePixelRatio; + onMetricsChanged?.call(); } - /// Deletes any existing test device pixel ratio and returns to using the real /// device pixel ratio. void clearDevicePixelRatioTestValue() { - _view.resetDevicePixelRatio(); + _devicePixelRatio = null; + onMetricsChanged?.call(); } @override - Size get physicalSize => _view.physicalSize; + ui.Size get physicalSize => _physicalSizeTestValue ?? _window.physicalSize; + ui.Size? _physicalSizeTestValue; /// Hides the real physical size and reports the given [physicalSizeTestValue] /// instead. - // ignore: avoid_setters_without_getters - set physicalSizeTestValue (Size physicalSizeTestValue) { - _view.physicalSize = physicalSizeTestValue; + set physicalSizeTestValue (ui.Size physicalSizeTestValue) { // ignore: avoid_setters_without_getters + _physicalSizeTestValue = physicalSizeTestValue; + onMetricsChanged?.call(); } - /// Deletes any existing test physical size and returns to using the real /// physical size. void clearPhysicalSizeTestValue() { - _view.resetPhysicalSize(); + _physicalSizeTestValue = null; + onMetricsChanged?.call(); } @override - ViewPadding get viewInsets => _view.viewInsets; + ui.ViewPadding get viewInsets => _viewInsetsTestValue ?? _window.viewInsets; + ui.ViewPadding? _viewInsetsTestValue; /// Hides the real view insets and reports the given [viewInsetsTestValue] /// instead. - /// - /// Use [FakeViewPadding] to set this value for testing. - // ignore: avoid_setters_without_getters - set viewInsetsTestValue(ViewPadding value) { - _view.viewInsets = value is FakeViewPadding ? value : FakeViewPadding._wrap(value); + set viewInsetsTestValue(ui.ViewPadding viewInsetsTestValue) { // ignore: avoid_setters_without_getters + _viewInsetsTestValue = viewInsetsTestValue; + onMetricsChanged?.call(); } - /// Deletes any existing test view insets and returns to using the real view /// insets. void clearViewInsetsTestValue() { - _view.resetViewInsets(); + _viewInsetsTestValue = null; + onMetricsChanged?.call(); } @override - ViewPadding get viewPadding => _view.viewPadding; + ui.ViewPadding get viewPadding => _viewPaddingTestValue ?? _window.padding; + ui.ViewPadding? _viewPaddingTestValue; /// Hides the real view padding and reports the given [paddingTestValue] /// instead. - /// - /// Use [FakeViewPadding] to set this value for testing. - // ignore: avoid_setters_without_getters - set viewPaddingTestValue(ViewPadding value) { - _view.viewPadding = value is FakeViewPadding ? value : FakeViewPadding._wrap(value); + set viewPaddingTestValue(ui.ViewPadding viewPaddingTestValue) { // ignore: avoid_setters_without_getters + _viewPaddingTestValue = viewPaddingTestValue; + onMetricsChanged?.call(); } - /// Deletes any existing test view padding and returns to using the real /// viewPadding. void clearViewPaddingTestValue() { - _view.resetViewPadding(); + _viewPaddingTestValue = null; + onMetricsChanged?.call(); } @override - ViewPadding get padding => _view.padding; + ui.ViewPadding get padding => _paddingTestValue ?? _window.padding; + ui.ViewPadding? _paddingTestValue; /// Hides the real padding and reports the given [paddingTestValue] instead. - /// - /// Use [FakeViewPadding] to set this value for testing. - // ignore: avoid_setters_without_getters - set paddingTestValue(ViewPadding value) { - _view.padding = value is FakeViewPadding ? value : FakeViewPadding._wrap(value); + set paddingTestValue(ui.ViewPadding paddingTestValue) { // ignore: avoid_setters_without_getters + _paddingTestValue = paddingTestValue; + onMetricsChanged?.call(); } - /// Deletes any existing test padding and returns to using the real padding. void clearPaddingTestValue() { - _view.resetPadding(); + _paddingTestValue = null; + onMetricsChanged?.call(); } @override - GestureSettings get gestureSettings => _view.gestureSettings; + ui.GestureSettings get gestureSettings => _gestureSettings ?? _window.gestureSettings; + ui.GestureSettings? _gestureSettings; /// Hides the real gesture settings and reports the given [gestureSettingsTestValue] instead. - // ignore: avoid_setters_without_getters - set gestureSettingsTestValue(GestureSettings gestureSettingsTestValue) { - _view.gestureSettings = gestureSettingsTestValue; + set gestureSettingsTestValue(ui.GestureSettings gestureSettingsTestValue) { // ignore: avoid_setters_without_getters + _gestureSettings = gestureSettingsTestValue; + onMetricsChanged?.call(); } - /// Deletes any existing test gesture settings and returns to using the real gesture settings. void clearGestureSettingsTestValue() { - _view.resetGestureSettings(); + _gestureSettings = null; + onMetricsChanged?.call(); } @override - List get displayFeatures => _view.displayFeatures; + List get displayFeatures => _displayFeaturesTestValue ?? _window.displayFeatures; + List? _displayFeaturesTestValue; /// Hides the real displayFeatures and reports the given [displayFeaturesTestValue] instead. - // ignore: avoid_setters_without_getters - set displayFeaturesTestValue(List displayFeaturesTestValue) { - _view.displayFeatures = displayFeaturesTestValue; + set displayFeaturesTestValue(List displayFeaturesTestValue) { // ignore: avoid_setters_without_getters + _displayFeaturesTestValue = displayFeaturesTestValue; + onMetricsChanged?.call(); } - /// Deletes any existing test padding and returns to using the real padding. void clearDisplayFeaturesTestValue() { - _view.resetDisplayFeatures(); + _displayFeaturesTestValue = null; + onMetricsChanged?.call(); } @override - ViewPadding get systemGestureInsets => _view.systemGestureInsets; - /// Hides the real system gesture insets and reports the given - /// [systemGestureInsetsTestValue] instead. - /// - /// Use [FakeViewPadding] to set this value for testing. - set systemGestureInsetsTestValue(ViewPadding value) { // ignore: avoid_setters_without_getters - _view.systemGestureInsets = value is FakeViewPadding ? value : FakeViewPadding._wrap(value); + ui.ViewPadding get systemGestureInsets => _systemGestureInsetsTestValue ?? _window.systemGestureInsets; + ui.ViewPadding? _systemGestureInsetsTestValue; + /// Hides the real system gesture insets and reports the given [systemGestureInsetsTestValue] instead. + set systemGestureInsetsTestValue(ui.ViewPadding systemGestureInsetsTestValue) { // ignore: avoid_setters_without_getters + _systemGestureInsetsTestValue = systemGestureInsetsTestValue; + onMetricsChanged?.call(); } - /// Deletes any existing test system gesture insets and returns to using the real system gesture insets. void clearSystemGestureInsetsTestValue() { - _view.resetSystemGestureInsets(); + _systemGestureInsetsTestValue = null; + onMetricsChanged?.call(); } @override - VoidCallback? get onMetricsChanged => platformDispatcher.onMetricsChanged; + ui.VoidCallback? get onMetricsChanged => platformDispatcher.onMetricsChanged; @override - set onMetricsChanged(VoidCallback? callback) { + set onMetricsChanged(ui.VoidCallback? callback) { platformDispatcher.onMetricsChanged = callback; } @override - Locale get locale => platformDispatcher.locale; + ui.Locale get locale => platformDispatcher.locale; /// Hides the real locale and reports the given [localeTestValue] instead. @Deprecated( 'Use platformDispatcher.localeTestValue instead. ' 'This feature was deprecated after v2.11.0-0.0.pre.' ) - set localeTestValue(Locale localeTestValue) { // ignore: avoid_setters_without_getters + set localeTestValue(ui.Locale localeTestValue) { // ignore: avoid_setters_without_getters platformDispatcher.localeTestValue = localeTestValue; } @Deprecated( @@ -1167,13 +212,13 @@ class TestWindow implements SingletonFlutterWindow { } @override - List get locales => platformDispatcher.locales; + List get locales => platformDispatcher.locales; /// Hides the real locales and reports the given [localesTestValue] instead. @Deprecated( 'Use platformDispatcher.localesTestValue instead. ' 'This feature was deprecated after v2.11.0-0.0.pre.' ) - set localesTestValue(List localesTestValue) { // ignore: avoid_setters_without_getters + set localesTestValue(List localesTestValue) { // ignore: avoid_setters_without_getters platformDispatcher.localesTestValue = localesTestValue; } /// Deletes any existing test locales and returns to using the real locales. @@ -1186,9 +231,9 @@ class TestWindow implements SingletonFlutterWindow { } @override - VoidCallback? get onLocaleChanged => platformDispatcher.onLocaleChanged; + ui.VoidCallback? get onLocaleChanged => platformDispatcher.onLocaleChanged; @override - set onLocaleChanged(VoidCallback? callback) { + set onLocaleChanged(ui.VoidCallback? callback) { platformDispatcher.onLocaleChanged = callback; } @@ -1225,11 +270,11 @@ class TestWindow implements SingletonFlutterWindow { } @override - Brightness get platformBrightness => platformDispatcher.platformBrightness; + ui.Brightness get platformBrightness => platformDispatcher.platformBrightness; @override - VoidCallback? get onPlatformBrightnessChanged => platformDispatcher.onPlatformBrightnessChanged; + ui.VoidCallback? get onPlatformBrightnessChanged => platformDispatcher.onPlatformBrightnessChanged; @override - set onPlatformBrightnessChanged(VoidCallback? callback) { + set onPlatformBrightnessChanged(ui.VoidCallback? callback) { platformDispatcher.onPlatformBrightnessChanged = callback; } /// Hides the real text scale factor and reports the given @@ -1238,7 +283,7 @@ class TestWindow implements SingletonFlutterWindow { 'Use platformDispatcher.platformBrightnessTestValue instead. ' 'This feature was deprecated after v2.11.0-0.0.pre.' ) - set platformBrightnessTestValue(Brightness platformBrightnessTestValue) { // ignore: avoid_setters_without_getters + set platformBrightnessTestValue(ui.Brightness platformBrightnessTestValue) { // ignore: avoid_setters_without_getters platformDispatcher.platformBrightnessTestValue = platformBrightnessTestValue; } /// Deletes any existing test platform brightness and returns to using the @@ -1273,9 +318,9 @@ class TestWindow implements SingletonFlutterWindow { } @override - VoidCallback? get onTextScaleFactorChanged => platformDispatcher.onTextScaleFactorChanged; + ui.VoidCallback? get onTextScaleFactorChanged => platformDispatcher.onTextScaleFactorChanged; @override - set onTextScaleFactorChanged(VoidCallback? callback) { + set onTextScaleFactorChanged(ui.VoidCallback? callback) { platformDispatcher.onTextScaleFactorChanged = callback; } @@ -1298,30 +343,30 @@ class TestWindow implements SingletonFlutterWindow { } @override - FrameCallback? get onBeginFrame => platformDispatcher.onBeginFrame; + ui.FrameCallback? get onBeginFrame => platformDispatcher.onBeginFrame; @override - set onBeginFrame(FrameCallback? callback) { + set onBeginFrame(ui.FrameCallback? callback) { platformDispatcher.onBeginFrame = callback; } @override - VoidCallback? get onDrawFrame => platformDispatcher.onDrawFrame; + ui.VoidCallback? get onDrawFrame => platformDispatcher.onDrawFrame; @override - set onDrawFrame(VoidCallback? callback) { + set onDrawFrame(ui.VoidCallback? callback) { platformDispatcher.onDrawFrame = callback; } @override - TimingsCallback? get onReportTimings => platformDispatcher.onReportTimings; + ui.TimingsCallback? get onReportTimings => platformDispatcher.onReportTimings; @override - set onReportTimings(TimingsCallback? callback) { + set onReportTimings(ui.TimingsCallback? callback) { platformDispatcher.onReportTimings = callback; } @override - PointerDataPacketCallback? get onPointerDataPacket => platformDispatcher.onPointerDataPacket; + ui.PointerDataPacketCallback? get onPointerDataPacket => platformDispatcher.onPointerDataPacket; @override - set onPointerDataPacket(PointerDataPacketCallback? callback) { + set onPointerDataPacket(ui.PointerDataPacketCallback? callback) { platformDispatcher.onPointerDataPacket = callback; } @@ -1352,8 +397,8 @@ class TestWindow implements SingletonFlutterWindow { } @override - void render(Scene scene) { - _view.render(scene); + void render(ui.Scene scene) { + _window.render(scene); } @override @@ -1378,21 +423,21 @@ class TestWindow implements SingletonFlutterWindow { } @override - VoidCallback? get onSemanticsEnabledChanged => platformDispatcher.onSemanticsEnabledChanged; + ui.VoidCallback? get onSemanticsEnabledChanged => platformDispatcher.onSemanticsEnabledChanged; @override - set onSemanticsEnabledChanged(VoidCallback? callback) { + set onSemanticsEnabledChanged(ui.VoidCallback? callback) { platformDispatcher.onSemanticsEnabledChanged = callback; } @override - SemanticsActionCallback? get onSemanticsAction => platformDispatcher.onSemanticsAction; + ui.SemanticsActionCallback? get onSemanticsAction => platformDispatcher.onSemanticsAction; @override - set onSemanticsAction(SemanticsActionCallback? callback) { + set onSemanticsAction(ui.SemanticsActionCallback? callback) { platformDispatcher.onSemanticsAction = callback; } @override - AccessibilityFeatures get accessibilityFeatures => platformDispatcher.accessibilityFeatures; + ui.AccessibilityFeatures get accessibilityFeatures => platformDispatcher.accessibilityFeatures; /// Hides the real accessibility features and reports the given /// [accessibilityFeaturesTestValue] instead. /// @@ -1402,7 +447,7 @@ class TestWindow implements SingletonFlutterWindow { 'Use platformDispatcher.accessibilityFeaturesTestValue instead. ' 'This feature was deprecated after v2.11.0-0.0.pre.' ) - set accessibilityFeaturesTestValue(AccessibilityFeatures accessibilityFeaturesTestValue) { // ignore: avoid_setters_without_getters + set accessibilityFeaturesTestValue(ui.AccessibilityFeatures accessibilityFeaturesTestValue) { // ignore: avoid_setters_without_getters platformDispatcher.accessibilityFeaturesTestValue = accessibilityFeaturesTestValue; } /// Deletes any existing test accessibility features and returns to using the @@ -1416,15 +461,15 @@ class TestWindow implements SingletonFlutterWindow { } @override - VoidCallback? get onAccessibilityFeaturesChanged => platformDispatcher.onAccessibilityFeaturesChanged; + ui.VoidCallback? get onAccessibilityFeaturesChanged => platformDispatcher.onAccessibilityFeaturesChanged; @override - set onAccessibilityFeaturesChanged(VoidCallback? callback) { + set onAccessibilityFeaturesChanged(ui.VoidCallback? callback) { platformDispatcher.onAccessibilityFeaturesChanged = callback; } @override - void updateSemantics(SemanticsUpdate update) { - _view.updateSemantics(update); + void updateSemantics(ui.SemanticsUpdate update) { + _window.updateSemantics(update); } @override @@ -1436,7 +481,7 @@ class TestWindow implements SingletonFlutterWindow { void sendPlatformMessage( String name, ByteData? data, - PlatformMessageResponseCallback? callback, + ui.PlatformMessageResponseCallback? callback, ) { platformDispatcher.sendPlatformMessage(name, data, callback); } @@ -1446,13 +491,13 @@ class TestWindow implements SingletonFlutterWindow { 'This feature was deprecated after v2.1.0-10.0.pre.' ) @override - PlatformMessageCallback? get onPlatformMessage => platformDispatcher.onPlatformMessage; + ui.PlatformMessageCallback? get onPlatformMessage => platformDispatcher.onPlatformMessage; @Deprecated( 'Instead of setting this callback, use ServicesBinding.instance.defaultBinaryMessenger.setMessageHandler. ' 'This feature was deprecated after v2.1.0-10.0.pre.' ) @override - set onPlatformMessage(PlatformMessageCallback? callback) { + set onPlatformMessage(ui.PlatformMessageCallback? callback) { platformDispatcher.onPlatformMessage = callback; } @@ -1460,10 +505,10 @@ class TestWindow implements SingletonFlutterWindow { /// as well as its [platformDispatcher]. /// /// After calling this, the real [SingletonFlutterWindow] and - /// [PlatformDispatcher] values are reported again. + /// [ui.PlatformDispatcher] values are reported again. /// /// If desired, clearing of properties can be done on an individual basis, - /// e.g., [clearLocaleTestValue]. + /// e.g., [clearLocaleTestValue()]. void clearAllTestValues() { clearDevicePixelRatioTestValue(); clearPaddingTestValue(); @@ -1474,44 +519,6 @@ class TestWindow implements SingletonFlutterWindow { platformDispatcher.clearAllTestValues(); } - @override - VoidCallback? get onFrameDataChanged => platformDispatcher.onFrameDataChanged; - @override - set onFrameDataChanged(VoidCallback? value) { - platformDispatcher.onFrameDataChanged = value; - } - - @override - KeyDataCallback? get onKeyData => platformDispatcher.onKeyData; - @override - set onKeyData(KeyDataCallback? value) { - platformDispatcher.onKeyData = value; - } - - @override - VoidCallback? get onSystemFontFamilyChanged => platformDispatcher.onSystemFontFamilyChanged; - @override - set onSystemFontFamilyChanged(VoidCallback? value) { - platformDispatcher.onSystemFontFamilyChanged = value; - } - - @override - Locale? computePlatformResolvedLocale(List supportedLocales) { - return platformDispatcher.computePlatformResolvedLocale(supportedLocales); - } - - @override - FrameData get frameData => platformDispatcher.frameData; - - @override - Rect get physicalGeometry => _view.physicalGeometry; - - @override - String? get systemFontFamily => platformDispatcher.systemFontFamily; - - @override - Object get viewId => _view.viewId; - /// This gives us some grace time when the dart:ui side adds something to /// [SingletonFlutterWindow], and makes things easier when we do rolls to give /// us time to catch up. @@ -1520,3 +527,422 @@ class TestWindow implements SingletonFlutterWindow { return null; } } + +/// Test version of [AccessibilityFeatures] in which specific features may +/// be set to arbitrary values. +/// +/// By default, all features are disabled. For an instance where all the +/// features are enabled, consider the [FakeAccessibilityFeatures.allOn] +/// constant. +@immutable +// ignore: avoid_implementing_value_types +class FakeAccessibilityFeatures implements ui.AccessibilityFeatures { + /// Creates a test instance of [AccessibilityFeatures]. + /// + /// By default, all features are disabled. + const FakeAccessibilityFeatures({ + this.accessibleNavigation = false, + this.invertColors = false, + this.disableAnimations = false, + this.boldText = false, + this.reduceMotion = false, + this.highContrast = false, + }); + + /// An instance of [AccessibilityFeatures] where all the features are enabled. + static const FakeAccessibilityFeatures allOn = FakeAccessibilityFeatures( + accessibleNavigation: true, + invertColors: true, + disableAnimations: true, + boldText: true, + reduceMotion: true, + highContrast: true, + ); + + @override + final bool accessibleNavigation; + + @override + final bool invertColors; + + @override + final bool disableAnimations; + + @override + final bool boldText; + + @override + final bool reduceMotion; + + @override + final bool highContrast; + + @override + bool operator ==(Object other) { + if (other.runtimeType != runtimeType) { + return false; + } + return other is FakeAccessibilityFeatures + && other.accessibleNavigation == accessibleNavigation + && other.invertColors == invertColors + && other.disableAnimations == disableAnimations + && other.boldText == boldText + && other.reduceMotion == reduceMotion + && other.highContrast == highContrast; + } + + @override + int get hashCode => Object.hash(accessibleNavigation, invertColors, disableAnimations, boldText, reduceMotion, highContrast); + + /// This gives us some grace time when the dart:ui side adds something to + /// [AccessibilityFeatures], and makes things easier when we do rolls to + /// give us time to catch up. + /// + /// If you would like to add to this class, changes must first be made in the + /// engine, followed by the framework. + @override + dynamic noSuchMethod(Invocation invocation) { + return null; + } +} + +/// [PlatformDispatcher] that wraps another [PlatformDispatcher] and +/// allows faking of some properties for testing purposes. +/// +/// See also: +/// +/// * [TestWindow], which wraps a [SingletonFlutterWindow] for +/// testing and mocking purposes. +class TestPlatformDispatcher implements ui.PlatformDispatcher { + /// Constructs a [TestPlatformDispatcher] that defers all behavior to the given + /// [dart:ui.PlatformDispatcher] unless explicitly overridden for test purposes. + TestPlatformDispatcher({ + required ui.PlatformDispatcher platformDispatcher, + }) : _platformDispatcher = platformDispatcher; + + /// The [dart:ui.PlatformDispatcher] that is wrapped by this [TestPlatformDispatcher]. + final ui.PlatformDispatcher _platformDispatcher; + + @override + ui.VoidCallback? get onMetricsChanged => _platformDispatcher.onMetricsChanged; + @override + set onMetricsChanged(ui.VoidCallback? callback) { + _platformDispatcher.onMetricsChanged = callback; + } + + @override + ui.Locale get locale => _localeTestValue ?? _platformDispatcher.locale; + ui.Locale? _localeTestValue; + /// Hides the real locale and reports the given [localeTestValue] instead. + set localeTestValue(ui.Locale localeTestValue) { // ignore: avoid_setters_without_getters + _localeTestValue = localeTestValue; + onLocaleChanged?.call(); + } + /// Deletes any existing test locale and returns to using the real locale. + void clearLocaleTestValue() { + _localeTestValue = null; + onLocaleChanged?.call(); + } + + @override + List get locales => _localesTestValue ?? _platformDispatcher.locales; + List? _localesTestValue; + /// Hides the real locales and reports the given [localesTestValue] instead. + set localesTestValue(List localesTestValue) { // ignore: avoid_setters_without_getters + _localesTestValue = localesTestValue; + onLocaleChanged?.call(); + } + /// Deletes any existing test locales and returns to using the real locales. + void clearLocalesTestValue() { + _localesTestValue = null; + onLocaleChanged?.call(); + } + + @override + ui.VoidCallback? get onLocaleChanged => _platformDispatcher.onLocaleChanged; + @override + set onLocaleChanged(ui.VoidCallback? callback) { + _platformDispatcher.onLocaleChanged = callback; + } + + @override + String get initialLifecycleState => _initialLifecycleStateTestValue; + String _initialLifecycleStateTestValue = ''; + /// Sets a faked initialLifecycleState for testing. + set initialLifecycleStateTestValue(String state) { // ignore: avoid_setters_without_getters + _initialLifecycleStateTestValue = state; + } + + @override + double get textScaleFactor => _textScaleFactorTestValue ?? _platformDispatcher.textScaleFactor; + double? _textScaleFactorTestValue; + /// Hides the real text scale factor and reports the given + /// [textScaleFactorTestValue] instead. + set textScaleFactorTestValue(double textScaleFactorTestValue) { // ignore: avoid_setters_without_getters + _textScaleFactorTestValue = textScaleFactorTestValue; + onTextScaleFactorChanged?.call(); + } + /// Deletes any existing test text scale factor and returns to using the real + /// text scale factor. + void clearTextScaleFactorTestValue() { + _textScaleFactorTestValue = null; + onTextScaleFactorChanged?.call(); + } + + @override + ui.Brightness get platformBrightness => _platformBrightnessTestValue ?? _platformDispatcher.platformBrightness; + ui.Brightness? _platformBrightnessTestValue; + @override + ui.VoidCallback? get onPlatformBrightnessChanged => _platformDispatcher.onPlatformBrightnessChanged; + @override + set onPlatformBrightnessChanged(ui.VoidCallback? callback) { + _platformDispatcher.onPlatformBrightnessChanged = callback; + } + /// Hides the real text scale factor and reports the given + /// [platformBrightnessTestValue] instead. + set platformBrightnessTestValue(ui.Brightness platformBrightnessTestValue) { // ignore: avoid_setters_without_getters + _platformBrightnessTestValue = platformBrightnessTestValue; + onPlatformBrightnessChanged?.call(); + } + /// Deletes any existing test platform brightness and returns to using the + /// real platform brightness. + void clearPlatformBrightnessTestValue() { + _platformBrightnessTestValue = null; + onPlatformBrightnessChanged?.call(); + } + + @override + bool get alwaysUse24HourFormat => _alwaysUse24HourFormatTestValue ?? _platformDispatcher.alwaysUse24HourFormat; + bool? _alwaysUse24HourFormatTestValue; + /// Hides the real clock format and reports the given + /// [alwaysUse24HourFormatTestValue] instead. + set alwaysUse24HourFormatTestValue(bool alwaysUse24HourFormatTestValue) { // ignore: avoid_setters_without_getters + _alwaysUse24HourFormatTestValue = alwaysUse24HourFormatTestValue; + } + /// Deletes any existing test clock format and returns to using the real clock + /// format. + void clearAlwaysUse24HourTestValue() { + _alwaysUse24HourFormatTestValue = null; + } + + @override + ui.VoidCallback? get onTextScaleFactorChanged => _platformDispatcher.onTextScaleFactorChanged; + @override + set onTextScaleFactorChanged(ui.VoidCallback? callback) { + _platformDispatcher.onTextScaleFactorChanged = callback; + } + + @override + bool get nativeSpellCheckServiceDefined => _nativeSpellCheckServiceDefinedTestValue ?? _platformDispatcher.nativeSpellCheckServiceDefined; + bool? _nativeSpellCheckServiceDefinedTestValue; + set nativeSpellCheckServiceDefinedTestValue(bool nativeSpellCheckServiceDefinedTestValue) { // ignore: avoid_setters_without_getters + _nativeSpellCheckServiceDefinedTestValue = nativeSpellCheckServiceDefinedTestValue; + } + /// Deletes existing value that determines whether or not a native spell check + /// service is defined and returns to the real value. + void clearNativeSpellCheckServiceDefined() { + _nativeSpellCheckServiceDefinedTestValue = null; + } + + @override + bool get brieflyShowPassword => _brieflyShowPasswordTestValue ?? _platformDispatcher.brieflyShowPassword; + bool? _brieflyShowPasswordTestValue; + /// Hides the real [brieflyShowPassword] and reports the given + /// `brieflyShowPasswordTestValue` instead. + set brieflyShowPasswordTestValue(bool brieflyShowPasswordTestValue) { // ignore: avoid_setters_without_getters + _brieflyShowPasswordTestValue = brieflyShowPasswordTestValue; + } + + @override + ui.FrameCallback? get onBeginFrame => _platformDispatcher.onBeginFrame; + @override + set onBeginFrame(ui.FrameCallback? callback) { + _platformDispatcher.onBeginFrame = callback; + } + + @override + ui.VoidCallback? get onDrawFrame => _platformDispatcher.onDrawFrame; + @override + set onDrawFrame(ui.VoidCallback? callback) { + _platformDispatcher.onDrawFrame = callback; + } + + @override + ui.TimingsCallback? get onReportTimings => _platformDispatcher.onReportTimings; + @override + set onReportTimings(ui.TimingsCallback? callback) { + _platformDispatcher.onReportTimings = callback; + } + + @override + ui.PointerDataPacketCallback? get onPointerDataPacket => _platformDispatcher.onPointerDataPacket; + @override + set onPointerDataPacket(ui.PointerDataPacketCallback? callback) { + _platformDispatcher.onPointerDataPacket = callback; + } + + @override + String get defaultRouteName => _defaultRouteNameTestValue ?? _platformDispatcher.defaultRouteName; + String? _defaultRouteNameTestValue; + /// Hides the real default route name and reports the given + /// [defaultRouteNameTestValue] instead. + set defaultRouteNameTestValue(String defaultRouteNameTestValue) { // ignore: avoid_setters_without_getters + _defaultRouteNameTestValue = defaultRouteNameTestValue; + } + /// Deletes any existing test default route name and returns to using the real + /// default route name. + void clearDefaultRouteNameTestValue() { + _defaultRouteNameTestValue = null; + } + + @override + void scheduleFrame() { + _platformDispatcher.scheduleFrame(); + } + + @override + bool get semanticsEnabled => _semanticsEnabledTestValue ?? _platformDispatcher.semanticsEnabled; + bool? _semanticsEnabledTestValue; + /// Hides the real semantics enabled and reports the given + /// [semanticsEnabledTestValue] instead. + set semanticsEnabledTestValue(bool semanticsEnabledTestValue) { // ignore: avoid_setters_without_getters + _semanticsEnabledTestValue = semanticsEnabledTestValue; + onSemanticsEnabledChanged?.call(); + } + /// Deletes any existing test semantics enabled and returns to using the real + /// semantics enabled. + void clearSemanticsEnabledTestValue() { + _semanticsEnabledTestValue = null; + onSemanticsEnabledChanged?.call(); + } + + @override + ui.VoidCallback? get onSemanticsEnabledChanged => _platformDispatcher.onSemanticsEnabledChanged; + @override + set onSemanticsEnabledChanged(ui.VoidCallback? callback) { + _platformDispatcher.onSemanticsEnabledChanged = callback; + } + + @override + ui.SemanticsActionCallback? get onSemanticsAction => _platformDispatcher.onSemanticsAction; + @override + set onSemanticsAction(ui.SemanticsActionCallback? callback) { + _platformDispatcher.onSemanticsAction = callback; + } + + @override + ui.AccessibilityFeatures get accessibilityFeatures => _accessibilityFeaturesTestValue ?? _platformDispatcher.accessibilityFeatures; + ui.AccessibilityFeatures? _accessibilityFeaturesTestValue; + /// Hides the real accessibility features and reports the given + /// [accessibilityFeaturesTestValue] instead. + /// + /// Consider using [FakeAccessibilityFeatures] to provide specific + /// values for the various accessibility features under test. + set accessibilityFeaturesTestValue(ui.AccessibilityFeatures accessibilityFeaturesTestValue) { // ignore: avoid_setters_without_getters + _accessibilityFeaturesTestValue = accessibilityFeaturesTestValue; + onAccessibilityFeaturesChanged?.call(); + } + /// Deletes any existing test accessibility features and returns to using the + /// real accessibility features. + void clearAccessibilityFeaturesTestValue() { + _accessibilityFeaturesTestValue = null; + onAccessibilityFeaturesChanged?.call(); + } + + @override + ui.VoidCallback? get onAccessibilityFeaturesChanged => _platformDispatcher.onAccessibilityFeaturesChanged; + @override + set onAccessibilityFeaturesChanged(ui.VoidCallback? callback) { + _platformDispatcher.onAccessibilityFeaturesChanged = callback; + } + + @override + void setIsolateDebugName(String name) { + _platformDispatcher.setIsolateDebugName(name); + } + + @override + void sendPlatformMessage( + String name, + ByteData? data, + ui.PlatformMessageResponseCallback? callback, + ) { + _platformDispatcher.sendPlatformMessage(name, data, callback); + } + + @Deprecated( + 'Instead of calling this callback, use ServicesBinding.instance.channelBuffers.push. ' + 'This feature was deprecated after v2.1.0-10.0.pre.' + ) + @override + ui.PlatformMessageCallback? get onPlatformMessage => _platformDispatcher.onPlatformMessage; + @Deprecated( + 'Instead of setting this callback, use ServicesBinding.instance.defaultBinaryMessenger.setMessageHandler. ' + 'This feature was deprecated after v2.1.0-10.0.pre.' + ) + @override + set onPlatformMessage(ui.PlatformMessageCallback? callback) { + _platformDispatcher.onPlatformMessage = callback; + } + + /// Delete any test value properties that have been set on this [TestPlatformDispatcher] + /// and return to reporting the real [ui.PlatformDispatcher] values for all + /// [PlatformDispatcher] properties. + /// + /// If desired, clearing of properties can be done on an individual basis, + /// e.g., [clearLocaleTestValue()]. + void clearAllTestValues() { + clearAccessibilityFeaturesTestValue(); + clearAlwaysUse24HourTestValue(); + clearDefaultRouteNameTestValue(); + clearPlatformBrightnessTestValue(); + clearLocaleTestValue(); + clearLocalesTestValue(); + clearSemanticsEnabledTestValue(); + clearTextScaleFactorTestValue(); + clearNativeSpellCheckServiceDefined(); + } + + @override + ui.VoidCallback? get onFrameDataChanged => _platformDispatcher.onFrameDataChanged; + @override + set onFrameDataChanged(ui.VoidCallback? value) { + _platformDispatcher.onFrameDataChanged = value; + } + + @override + ui.KeyDataCallback? get onKeyData => _platformDispatcher.onKeyData; + + @override + set onKeyData(ui.KeyDataCallback? onKeyData) { + _platformDispatcher.onKeyData = onKeyData; + } + + @override + ui.VoidCallback? get onPlatformConfigurationChanged => _platformDispatcher.onPlatformConfigurationChanged; + + @override + set onPlatformConfigurationChanged(ui.VoidCallback? onPlatformConfigurationChanged) { + _platformDispatcher.onPlatformConfigurationChanged = onPlatformConfigurationChanged; + } + + @override + ui.Locale? computePlatformResolvedLocale(List supportedLocales) => _platformDispatcher.computePlatformResolvedLocale(supportedLocales); + + @override + ui.FrameData get frameData => _platformDispatcher.frameData; + + @override + ByteData? getPersistentIsolateData() => _platformDispatcher.getPersistentIsolateData(); + + @override + Iterable get views => _platformDispatcher.views; + + /// This gives us some grace time when the dart:ui side adds something to + /// [PlatformDispatcher], and makes things easier when we do rolls to give + /// us time to catch up. + @override + dynamic noSuchMethod(Invocation invocation) { + return null; + } +} diff --git a/packages/flutter_test/test/controller_test.dart b/packages/flutter_test/test/controller_test.dart index 9e73da96fd6..b82ad818d11 100644 --- a/packages/flutter_test/test/controller_test.dart +++ b/packages/flutter_test/test/controller_test.dart @@ -711,25 +711,6 @@ void main() { }); }); - testWidgets('platformDispatcher exposes the platformDispatcher from binding', (WidgetTester tester) async { - expect(tester.platformDispatcher, tester.binding.platformDispatcher); - }); - - testWidgets('view exposes the implicitView from platformDispatcher', (WidgetTester tester) async { - expect(tester.view, tester.platformDispatcher.implicitView); - }); - - testWidgets('viewOf finds a view when the view is implicit', (WidgetTester tester) async { - await tester.pumpWidget(const MaterialApp( - home: Center( - child: Text('Test'), - ) - )); - - expect(() => tester.viewOf(find.text('Test')), isNot(throwsA(anything))); - expect(tester.viewOf(find.text('Test')), isA()); - }); - group('SemanticsController', () { group('find', () { testWidgets('throws when there are no semantics', (WidgetTester tester) async { diff --git a/packages/flutter_test/test/platform_dispatcher_test.dart b/packages/flutter_test/test/platform_dispatcher_test.dart index 5940f3adf0a..971c3b14ce7 100644 --- a/packages/flutter_test/test/platform_dispatcher_test.dart +++ b/packages/flutter_test/test/platform_dispatcher_test.dart @@ -7,17 +7,15 @@ import 'dart:ui' show AccessibilityFeatures, Brightness, Locale, PlatformDispatc import 'package:flutter/widgets.dart' show WidgetsBinding, WidgetsBindingObserver; import 'package:flutter_test/flutter_test.dart'; -import 'utils/fake_and_mock_utils.dart'; - void main() { - test('TestPlatformDispatcher can handle new methods without breaking', () { + test('TestWindow can handle new methods without breaking', () { final dynamic testPlatformDispatcher = TestPlatformDispatcher(platformDispatcher: PlatformDispatcher.instance); // ignore: avoid_dynamic_calls expect(testPlatformDispatcher.someNewProperty, null); }); - testWidgets('TestPlatformDispatcher can fake locale', (WidgetTester tester) async { - verifyPropertyFaked( + testWidgets('TestWindow can fake locale', (WidgetTester tester) async { + verifyThatTestPlatformDispatcherCanFakeProperty( tester: tester, realValue: PlatformDispatcher.instance.locale, fakeValue: const Locale('fake_language_code'), @@ -30,8 +28,8 @@ void main() { ); }); - testWidgets('TestPlatformDispatcher can fake locales', (WidgetTester tester) async { - verifyPropertyFaked>( + testWidgets('TestWindow can fake locales', (WidgetTester tester) async { + verifyThatTestPlatformDispatcherCanFakeProperty>( tester: tester, realValue: PlatformDispatcher.instance.locales, fakeValue: [const Locale('fake_language_code')], @@ -44,8 +42,8 @@ void main() { ); }); - testWidgets('TestPlatformDispatcher can fake text scale factor', (WidgetTester tester) async { - verifyPropertyFaked( + testWidgets('TestWindow can fake text scale factor', (WidgetTester tester) async { + verifyThatTestPlatformDispatcherCanFakeProperty( tester: tester, realValue: PlatformDispatcher.instance.textScaleFactor, fakeValue: 2.5, @@ -58,8 +56,8 @@ void main() { ); }); - testWidgets('TestPlatformDispatcher can fake clock format', (WidgetTester tester) async { - verifyPropertyFaked( + testWidgets('TestWindow can fake clock format', (WidgetTester tester) async { + verifyThatTestPlatformDispatcherCanFakeProperty( tester: tester, realValue: PlatformDispatcher.instance.alwaysUse24HourFormat, fakeValue: !PlatformDispatcher.instance.alwaysUse24HourFormat, @@ -72,8 +70,8 @@ void main() { ); }); - testWidgets('TestPlatformDispatcher can fake brieflyShowPassword', (WidgetTester tester) async { - verifyPropertyFaked( + testWidgets('TestWindow can fake brieflyShowPassword', (WidgetTester tester) async { + verifyThatTestPlatformDispatcherCanFakeProperty( tester: tester, realValue: PlatformDispatcher.instance.brieflyShowPassword, fakeValue: !PlatformDispatcher.instance.brieflyShowPassword, @@ -84,8 +82,8 @@ void main() { ); }); - testWidgets('TestPlatformDispatcher can fake default route name', (WidgetTester tester) async { - verifyPropertyFaked( + testWidgets('TestWindow can fake default route name', (WidgetTester tester) async { + verifyThatTestPlatformDispatcherCanFakeProperty( tester: tester, realValue: PlatformDispatcher.instance.defaultRouteName, fakeValue: 'fake_route', @@ -98,8 +96,8 @@ void main() { ); }); - testWidgets('TestPlatformDispatcher can fake accessibility features', (WidgetTester tester) async { - verifyPropertyFaked( + testWidgets('TestWindow can fake accessibility features', (WidgetTester tester) async { + verifyThatTestPlatformDispatcherCanFakeProperty( tester: tester, realValue: PlatformDispatcher.instance.accessibilityFeatures, fakeValue: const FakeAccessibilityFeatures(), @@ -112,8 +110,8 @@ void main() { ); }); - testWidgets('TestPlatformDispatcher can fake platform brightness', (WidgetTester tester) async { - verifyPropertyFaked( + testWidgets('TestWindow can fake platform brightness', (WidgetTester tester) async { + verifyThatTestPlatformDispatcherCanFakeProperty( tester: tester, realValue: Brightness.light, fakeValue: Brightness.dark, @@ -126,7 +124,7 @@ void main() { ); }); - testWidgets('TestPlatformDispatcher can clear out fake properties all at once', (WidgetTester tester) async { + testWidgets('TestWindow can clear out fake properties all at once', (WidgetTester tester) async { final Locale originalLocale = PlatformDispatcher.instance.locale; final double originalTextScaleFactor = PlatformDispatcher.instance.textScaleFactor; final TestPlatformDispatcher testPlatformDispatcher = retrieveTestBinding(tester).platformDispatcher; @@ -143,7 +141,7 @@ void main() { expect(WidgetsBinding.instance.platformDispatcher.textScaleFactor, originalTextScaleFactor); }); - testWidgets('TestPlatformDispatcher sends fake locales when WidgetsBindingObserver notifiers are called', (WidgetTester tester) async { + testWidgets('TestWindow sends fake locales when WidgetsBindingObserver notifiers are called', (WidgetTester tester) async { final List defaultLocales = WidgetsBinding.instance.platformDispatcher.locales; final TestObserver observer = TestObserver(); retrieveTestBinding(tester).addObserver(observer); @@ -154,8 +152,36 @@ void main() { }); } +void verifyThatTestPlatformDispatcherCanFakeProperty({ + required WidgetTester tester, + required PlatformDispatcherPropertyType? realValue, + required PlatformDispatcherPropertyType fakeValue, + required PlatformDispatcherPropertyType? Function() propertyRetriever, + required Function(TestWidgetsFlutterBinding, PlatformDispatcherPropertyType fakeValue) propertyFaker, +}) { + PlatformDispatcherPropertyType? propertyBeforeFaking; + PlatformDispatcherPropertyType? propertyAfterFaking; + + propertyBeforeFaking = propertyRetriever(); + + propertyFaker(retrieveTestBinding(tester), fakeValue); + + propertyAfterFaking = propertyRetriever(); + + expect(propertyBeforeFaking, realValue); + expect(propertyAfterFaking, fakeValue); +} + +TestWidgetsFlutterBinding retrieveTestBinding(WidgetTester tester) { + final WidgetsBinding binding = tester.binding; + assert(binding is TestWidgetsFlutterBinding); + final TestWidgetsFlutterBinding testBinding = binding as TestWidgetsFlutterBinding; + return testBinding; +} + class TestObserver with WidgetsBindingObserver { List? locales; + Locale? locale; @override void didChangeLocales(List? locales) { diff --git a/packages/flutter_test/test/utils/fake_and_mock_utils.dart b/packages/flutter_test/test/utils/fake_and_mock_utils.dart deleted file mode 100644 index db2b7ba4385..00000000000 --- a/packages/flutter_test/test/utils/fake_and_mock_utils.dart +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2014 The Flutter 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:ui'; - -import 'package:flutter/widgets.dart'; -import 'package:flutter_test/flutter_test.dart'; - -TestWidgetsFlutterBinding retrieveTestBinding(WidgetTester tester) { - final WidgetsBinding binding = tester.binding; - assert(binding is TestWidgetsFlutterBinding); - final TestWidgetsFlutterBinding testBinding = binding as TestWidgetsFlutterBinding; - return testBinding; -} - -void verifyPropertyFaked({ - required WidgetTester tester, - required TProperty realValue, - required TProperty fakeValue, - required TProperty Function() propertyRetriever, - required Function(TestWidgetsFlutterBinding, TProperty fakeValue) propertyFaker, - Matcher Function(TProperty) matcher = equals, -}) { - TProperty propertyBeforeFaking; - TProperty propertyAfterFaking; - - propertyBeforeFaking = propertyRetriever(); - - propertyFaker(retrieveTestBinding(tester), fakeValue); - - propertyAfterFaking = propertyRetriever(); - - expect( - realValue == fakeValue, - isFalse, - reason: 'Since the real value and fake value are equal, we cannot validate ' - 'that a property has been faked. Choose a different fake value to test.', - ); - expect(propertyBeforeFaking, matcher(realValue)); - expect(propertyAfterFaking, matcher(fakeValue)); -} - -void verifyPropertyReset({ - required WidgetTester tester, - required TProperty fakeValue, - required TProperty Function() propertyRetriever, - required Function() propertyResetter, - required Function(TProperty fakeValue) propertyFaker, - Matcher Function(TProperty) matcher = equals, -}) { - TProperty propertyBeforeFaking; - TProperty propertyAfterFaking; - TProperty propertyAfterReset; - - propertyBeforeFaking = propertyRetriever(); - - propertyFaker(fakeValue); - - propertyAfterFaking = propertyRetriever(); - - propertyResetter(); - - propertyAfterReset = propertyRetriever(); - - expect(propertyAfterFaking, matcher(fakeValue)); - expect(propertyAfterReset, matcher(propertyBeforeFaking)); -} - -Matcher matchesViewPadding(ViewPadding expected) => _FakeViewPaddingMatcher(expected); - -class _FakeViewPaddingMatcher extends Matcher { - _FakeViewPaddingMatcher(this.expected); - - final ViewPadding expected; - - @override - Description describe(Description description) { - description.add('two ViewPadding instances match'); - return description; - } - - @override - Description describeMismatch(dynamic item, Description mismatchDescription, Map matchState, bool verbose) { - assert(item is ViewPadding, 'Can only match against implementations of ViewPadding.'); - final ViewPadding actual = item as ViewPadding; - - if (actual.left != expected.left) { - mismatchDescription.add('actual.left (${actual.left}) did not match expected.left (${expected.left})'); - } - if (actual.top != expected.top) { - mismatchDescription.add('actual.top (${actual.top}) did not match expected.top (${expected.top})'); - } - if (actual.right != expected.right) { - mismatchDescription.add('actual.right (${actual.right}) did not match expected.right (${expected.right})'); - } - if (actual.bottom != expected.bottom) { - mismatchDescription.add('actual.bottom (${actual.bottom}) did not match expected.bottom (${expected.bottom})'); - } - - return mismatchDescription; - } - - @override - bool matches(dynamic item, Map matchState) { - assert(item is ViewPadding, 'Can only match against implementations of ViewPadding.'); - final ViewPadding actual = item as ViewPadding; - - return actual.left == expected.left && - actual.top == expected.top && - actual.right == expected.right && - actual.bottom == expected.bottom; - } -} diff --git a/packages/flutter_test/test/view_test.dart b/packages/flutter_test/test/view_test.dart deleted file mode 100644 index 721f0f67f9e..00000000000 --- a/packages/flutter_test/test/view_test.dart +++ /dev/null @@ -1,445 +0,0 @@ -// Copyright 2014 The Flutter 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:ui'; - -import 'package:collection/collection.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'utils/fake_and_mock_utils.dart'; - -void main() { - group('TestFlutterView', () { - FlutterView trueImplicitView() => PlatformDispatcher.instance.implicitView!; - FlutterView boundImplicitView() => WidgetsBinding.instance.platformDispatcher.implicitView!; - - tearDown(() { - final TestFlutterView view = (WidgetsBinding.instance as TestWidgetsFlutterBinding).platformDispatcher.views.single; - view.reset(); - }); - - testWidgets('can handle new methods without breaking', (WidgetTester tester) async { - final dynamic testView = tester.view; - // ignore: avoid_dynamic_calls - expect(testView.someNewProperty, null); - }); - - testWidgets('can fake devicePixelRatio', (WidgetTester tester) async { - verifyPropertyFaked( - tester: tester, - realValue: trueImplicitView().devicePixelRatio, - fakeValue: 2.5, - propertyRetriever: () => boundImplicitView().devicePixelRatio, - propertyFaker: (_, double fakeValue) { - tester.view.devicePixelRatio = fakeValue; - }, - ); - }); - - testWidgets('can reset devicePixelRatio', (WidgetTester tester) async { - verifyPropertyReset( - tester: tester, - fakeValue: 2.5, - propertyRetriever: () => boundImplicitView().devicePixelRatio, - propertyResetter: () { - tester.view.resetDevicePixelRatio(); - }, - propertyFaker: (double fakeValue) { - tester.view.devicePixelRatio = fakeValue; - }, - ); - }); - - testWidgets('can fake displayFeatures', (WidgetTester tester) async { - verifyPropertyFaked>( - tester: tester, - realValue: trueImplicitView().displayFeatures, - fakeValue: [const DisplayFeature(bounds: Rect.fromLTWH(0, 0, 500, 30), type: DisplayFeatureType.unknown, state: DisplayFeatureState.unknown)], - propertyRetriever: () => boundImplicitView().displayFeatures, - propertyFaker: (_, List fakeValue) { - tester.view.displayFeatures = fakeValue; - }, - ); - }); - - testWidgets('can reset displayFeatures', (WidgetTester tester) async { - verifyPropertyReset>( - tester: tester, - fakeValue: [const DisplayFeature(bounds: Rect.fromLTWH(0, 0, 500, 30), type: DisplayFeatureType.unknown, state: DisplayFeatureState.unknown)], - propertyRetriever: () => boundImplicitView().displayFeatures, - propertyResetter: () { - tester.view.resetDisplayFeatures(); - }, - propertyFaker: (List fakeValue) { - tester.view.displayFeatures = fakeValue; - }, - ); - }); - - testWidgets('can fake padding', (WidgetTester tester) async { - verifyPropertyFaked( - tester: tester, - realValue: trueImplicitView().padding, - fakeValue: const FakeViewPadding(), - propertyRetriever: () => boundImplicitView().padding, - propertyFaker: (_, ViewPadding fakeValue) { - tester.view.padding = fakeValue as FakeViewPadding; - }, - matcher: matchesViewPadding - ); - }); - - testWidgets('can reset padding', (WidgetTester tester) async { - verifyPropertyReset( - tester: tester, - fakeValue: const FakeViewPadding(), - propertyRetriever: () => boundImplicitView().padding, - propertyResetter: () { - tester.view.resetPadding(); - }, - propertyFaker: (ViewPadding fakeValue) { - tester.view.padding = fakeValue as FakeViewPadding; - }, - matcher: matchesViewPadding - ); - }); - - testWidgets('can fake physicalGeometry', (WidgetTester tester) async { - verifyPropertyFaked( - tester: tester, - realValue: trueImplicitView().physicalGeometry, - fakeValue: const Rect.fromLTWH(0, 0, 550, 850), - propertyRetriever: () => boundImplicitView().physicalGeometry, - propertyFaker: (_, Rect fakeValue) { - tester.view.physicalGeometry = fakeValue; - }, - ); - }); - - testWidgets('can reset physicalGeometry', (WidgetTester tester) async { - verifyPropertyReset( - tester: tester, - fakeValue: const Rect.fromLTWH(0, 0, 35, 475), - propertyRetriever: () => boundImplicitView().physicalGeometry, - propertyResetter: () { - tester.view.resetPhysicalGeometry(); - }, - propertyFaker: (Rect fakeValue) { - tester.view.physicalGeometry = fakeValue; - }, - ); - }); - - testWidgets('updating physicalGeometry also updates physicalSize', (WidgetTester tester) async { - const Rect testGeometry = Rect.fromLTWH(0, 0, 450, 575); - tester.view.physicalGeometry = testGeometry; - - expect(tester.view.physicalSize, testGeometry.size); - }); - - testWidgets('can fake physicalSize', (WidgetTester tester) async { - verifyPropertyFaked( - tester: tester, - realValue: trueImplicitView().physicalSize, - fakeValue: const Size(50, 50), - propertyRetriever: () => boundImplicitView().physicalSize, - propertyFaker: (_, Size fakeValue) { - tester.view.physicalSize = fakeValue; - }, - ); - }); - - testWidgets('can reset physicalSize', (WidgetTester tester) async { - verifyPropertyReset( - tester: tester, - fakeValue: const Size(50, 50), - propertyRetriever: () => boundImplicitView().physicalSize, - propertyResetter: () { - tester.view.resetPhysicalSize(); - }, - propertyFaker: (Size fakeValue) { - tester.view.physicalSize = fakeValue; - }, - ); - }); - - testWidgets('updating physicalSize also updates physicalGeometry', (WidgetTester tester) async { - const Rect testGeometry = Rect.fromLTWH(0, 0, 450, 575); - const Size testSize = Size(50, 50); - const Rect expectedGeometry = Rect.fromLTWH(0, 0, 50, 50); - - tester.view.physicalGeometry = testGeometry; - tester.view.physicalSize = testSize; - - expect(tester.view.physicalGeometry, expectedGeometry); - }); - - testWidgets('can fake systemGestureInsets', (WidgetTester tester) async { - verifyPropertyFaked( - tester: tester, - realValue: trueImplicitView().systemGestureInsets, - fakeValue: const FakeViewPadding(), - propertyRetriever: () => boundImplicitView().systemGestureInsets, - propertyFaker: (_, ViewPadding fakeValue) { - tester.view.systemGestureInsets = fakeValue as FakeViewPadding; - }, - matcher: matchesViewPadding - ); - }); - - testWidgets('can reset systemGestureInsets', (WidgetTester tester) async { - verifyPropertyReset( - tester: tester, - fakeValue: const FakeViewPadding(), - propertyRetriever: () => boundImplicitView().systemGestureInsets, - propertyResetter: () { - tester.view.resetSystemGestureInsets(); - }, - propertyFaker: (ViewPadding fakeValue) { - tester.view.systemGestureInsets = fakeValue as FakeViewPadding; - }, - matcher: matchesViewPadding - ); - }); - - testWidgets('can fake viewInsets', (WidgetTester tester) async { - verifyPropertyFaked( - tester: tester, - realValue: trueImplicitView().viewInsets, - fakeValue: const FakeViewPadding(), - propertyRetriever: () => boundImplicitView().viewInsets, - propertyFaker: (_, ViewPadding fakeValue) { - tester.view.viewInsets = fakeValue as FakeViewPadding; - }, - matcher: matchesViewPadding - ); - }); - - testWidgets('can reset viewInsets', (WidgetTester tester) async { - verifyPropertyReset( - tester: tester, - fakeValue: const FakeViewPadding(), - propertyRetriever: () => boundImplicitView().viewInsets, - propertyResetter: () { - tester.view.resetViewInsets(); - }, - propertyFaker: (ViewPadding fakeValue) { - tester.view.viewInsets = fakeValue as FakeViewPadding; - }, - matcher: matchesViewPadding - ); - }); - - testWidgets('can fake viewPadding', (WidgetTester tester) async { - verifyPropertyFaked( - tester: tester, - realValue: trueImplicitView().viewPadding, - fakeValue: const FakeViewPadding(), - propertyRetriever: () => boundImplicitView().viewPadding, - propertyFaker: (_, ViewPadding fakeValue) { - tester.view.viewPadding = fakeValue as FakeViewPadding; - }, - matcher: matchesViewPadding - ); - }); - - testWidgets('can reset viewPadding', (WidgetTester tester) async { - verifyPropertyReset( - tester: tester, - fakeValue: const FakeViewPadding(), - propertyRetriever: () => boundImplicitView().viewPadding, - propertyResetter: () { - tester.view.resetViewPadding(); - }, - propertyFaker: (ViewPadding fakeValue) { - tester.view.viewPadding = fakeValue as FakeViewPadding; - }, - matcher: matchesViewPadding - ); - }); - - testWidgets('can clear out fake properties all at once', (WidgetTester tester) async { - final FlutterViewSnapshot initial = FlutterViewSnapshot(tester.view); - - tester.view.devicePixelRatio = 7; - tester.view.displayFeatures = [const DisplayFeature(bounds: Rect.fromLTWH(0, 0, 20, 300), type: DisplayFeatureType.unknown, state: DisplayFeatureState.unknown)]; - tester.view.padding = const FakeViewPadding(); - tester.view.physicalGeometry = const Rect.fromLTWH(0, 0, 505, 805); - tester.view.systemGestureInsets = const FakeViewPadding(); - tester.view.viewInsets = const FakeViewPadding(); - tester.view.viewPadding = const FakeViewPadding(); - tester.view.gestureSettings = const GestureSettings(physicalTouchSlop: 4, physicalDoubleTapSlop: 5); - - final FlutterViewSnapshot faked = FlutterViewSnapshot(tester.view); - - tester.view.reset(); - - final FlutterViewSnapshot reset = FlutterViewSnapshot(tester.view); - - expect(initial, isNot(matchesSnapshot(faked))); - expect(initial, matchesSnapshot(reset)); - }); - - testWidgets('render is passed through to backing FlutterView', (WidgetTester tester) async { - final Scene expectedScene = SceneBuilder().build(); - final _FakeFlutterView backingView = _FakeFlutterView(); - final TestFlutterView view = TestFlutterView( - view: backingView, - platformDispatcher: tester.binding.platformDispatcher, - ); - - view.render(expectedScene); - - expect(backingView.lastRenderedScene, isNotNull); - expect(backingView.lastRenderedScene, expectedScene); - }); - - testWidgets('updateSemantics is passed through to backing FlutterView', (WidgetTester tester) async { - final SemanticsUpdate expectedUpdate = SemanticsUpdateBuilder().build(); - final _FakeFlutterView backingView = _FakeFlutterView(); - final TestFlutterView view = TestFlutterView( - view: backingView, - platformDispatcher: tester.binding.platformDispatcher, - ); - - view.updateSemantics(expectedUpdate); - - expect(backingView.lastSemanticsUpdate, isNotNull); - expect(backingView.lastSemanticsUpdate, expectedUpdate); - }); - }); -} - - -Matcher matchesSnapshot(FlutterViewSnapshot expected) => _FlutterViewSnapshotMatcher(expected); - -class _FlutterViewSnapshotMatcher extends Matcher { - _FlutterViewSnapshotMatcher(this.expected); - - final FlutterViewSnapshot expected; - - @override - Description describe(Description description) { - description.add('snapshot of a FlutterView matches'); - return description; - } - - @override - Description describeMismatch(dynamic item, Description mismatchDescription, Map matchState, bool verbose) { - assert(item is FlutterViewSnapshot, 'Can only match against snapshots of FlutterView.'); - final FlutterViewSnapshot actual = item as FlutterViewSnapshot; - - if (actual.devicePixelRatio != expected.devicePixelRatio) { - mismatchDescription.add('actual.devicePixelRatio (${actual.devicePixelRatio}) did not match expected.devicePixelRatio (${expected.devicePixelRatio})'); - } - if (!actual.displayFeatures.equals(expected.displayFeatures)) { - mismatchDescription.add('actual.displayFeatures did not match expected.devicePixelRatio'); - mismatchDescription.addAll('Actual: [', ',', ']', actual.displayFeatures); - mismatchDescription.addAll('Expected: [', ',', ']', expected.displayFeatures); - } - if (actual.gestureSettings != expected.gestureSettings) { - mismatchDescription.add('actual.gestureSettings (${actual.gestureSettings}) did not match expected.gestureSettings (${expected.gestureSettings})'); - } - - final Matcher paddingMatcher = matchesViewPadding(expected.padding); - if (!paddingMatcher.matches(actual.padding, matchState)) { - mismatchDescription.add('actual.padding (${actual.padding}) did not match expected.padding (${expected.padding})'); - paddingMatcher.describeMismatch(actual.padding, mismatchDescription, matchState, verbose); - } - - if (actual.physicalGeometry != expected.physicalGeometry) { - mismatchDescription.add('actual.physicalGeometry (${actual.physicalGeometry}) did not match expected.physicalGeometry (${expected.physicalGeometry})'); - } - if (actual.physicalSize != expected.physicalSize) { - mismatchDescription.add('actual.physicalSize (${actual.physicalSize}) did not match expected.physicalSize (${expected.physicalSize})'); - } - - final Matcher systemGestureInsetsMatcher = matchesViewPadding(expected.systemGestureInsets); - if (!systemGestureInsetsMatcher.matches(actual.systemGestureInsets, matchState)) { - mismatchDescription.add('actual.systemGestureInsets (${actual.systemGestureInsets}) did not match expected.systemGestureInsets (${expected.systemGestureInsets})'); - systemGestureInsetsMatcher.describeMismatch(actual.systemGestureInsets, mismatchDescription, matchState, verbose); - } - - if (actual.viewId != expected.viewId) { - mismatchDescription.add('actual.viewId (${actual.viewId}) did not match expected.viewId (${expected.viewId})'); - } - - final Matcher viewInsetsMatcher = matchesViewPadding(expected.viewInsets); - if (!viewInsetsMatcher.matches(actual.viewInsets, matchState)) { - mismatchDescription.add('actual.viewInsets (${actual.viewInsets}) did not match expected.viewInsets (${expected.viewInsets})'); - viewInsetsMatcher.describeMismatch(actual.viewInsets, mismatchDescription, matchState, verbose); - } - - final Matcher viewPaddingMatcher = matchesViewPadding(expected.viewPadding); - if (!viewPaddingMatcher.matches(actual.viewPadding, matchState)) { - mismatchDescription.add('actual.viewPadding (${actual.viewPadding}) did not match expected.devicePixelRatio (${expected.viewPadding})'); - viewPaddingMatcher.describeMismatch(actual.viewPadding, mismatchDescription, matchState, verbose); - } - - return mismatchDescription; - } - - @override - bool matches(dynamic item, Map matchState) { - assert(item is FlutterViewSnapshot, 'Can only match against snapshots of FlutterView.'); - final FlutterViewSnapshot actual = item as FlutterViewSnapshot; - - return actual.devicePixelRatio == expected.devicePixelRatio && - actual.displayFeatures.equals(expected.displayFeatures) && - actual.gestureSettings == expected.gestureSettings && - matchesViewPadding(expected.padding).matches(actual.padding, matchState) && - actual.physicalGeometry == expected.physicalGeometry && - actual.physicalSize == expected.physicalSize && - matchesViewPadding(expected.systemGestureInsets).matches(actual.padding, matchState) && - actual.viewId == expected.viewId && - matchesViewPadding(expected.viewInsets).matches(actual.viewInsets, matchState) && - matchesViewPadding(expected.viewPadding).matches(actual.viewPadding, matchState); - } -} - -class FlutterViewSnapshot { - FlutterViewSnapshot(FlutterView view) : - devicePixelRatio = view.devicePixelRatio, - displayFeatures = [...view.displayFeatures], - gestureSettings = view.gestureSettings, - padding = view.padding, - physicalGeometry = view.physicalGeometry, - physicalSize = view.physicalSize, - systemGestureInsets = view.systemGestureInsets, - viewId = view.viewId, - viewInsets = view.viewInsets, - viewPadding = view.viewPadding; - - final double devicePixelRatio; - final List displayFeatures; - final GestureSettings gestureSettings; - final ViewPadding padding; - final Rect physicalGeometry; - final Size physicalSize; - final ViewPadding systemGestureInsets; - final Object viewId; - final ViewPadding viewInsets; - final ViewPadding viewPadding; -} - -class _FakeFlutterView implements FlutterView { - SemanticsUpdate? lastSemanticsUpdate; - Scene? lastRenderedScene; - - @override - void updateSemantics(SemanticsUpdate update) { - lastSemanticsUpdate = update; - } - - @override - void render(Scene scene) { - lastRenderedScene = scene; - } - - @override - dynamic noSuchMethod(Invocation invocation) { - return null; - } -} diff --git a/packages/flutter_test/test/window_test.dart b/packages/flutter_test/test/window_test.dart index bb7380877b0..4385868f3bf 100644 --- a/packages/flutter_test/test/window_test.dart +++ b/packages/flutter_test/test/window_test.dart @@ -3,19 +3,13 @@ // found in the LICENSE file. import 'dart:ui' as ui show window; -import 'dart:ui'; +import 'dart:ui' show AccessibilityFeatures, Brightness, Locale, PlatformDispatcher, SemanticsUpdate, SingletonFlutterWindow, Size, ViewPadding; +import 'package:flutter/semantics.dart' show SemanticsUpdateBuilder; import 'package:flutter/widgets.dart' show WidgetsBinding, WidgetsBindingObserver; import 'package:flutter_test/flutter_test.dart'; -import 'utils/fake_and_mock_utils.dart'; - void main() { - tearDown(() { - final TestWindow window = WidgetsBinding.instance.window as TestWindow; - window.clearAllTestValues(); - }); - test('TestWindow can handle new methods without breaking', () { final dynamic testWindow = TestWindow(window: ui.window); // ignore: avoid_dynamic_calls @@ -23,7 +17,7 @@ void main() { }); testWidgets('TestWindow can fake device pixel ratio', (WidgetTester tester) async { - verifyPropertyFaked( + verifyThatTestWindowCanFakeProperty( tester: tester, realValue: ui.window.devicePixelRatio, fakeValue: 2.5, @@ -37,7 +31,7 @@ void main() { }); testWidgets('TestWindow can fake physical size', (WidgetTester tester) async { - verifyPropertyFaked( + verifyThatTestWindowCanFakeProperty( tester: tester, realValue: ui.window.physicalSize, fakeValue: const Size(50, 50), @@ -51,7 +45,7 @@ void main() { }); testWidgets('TestWindow can fake view insets', (WidgetTester tester) async { - verifyPropertyFaked( + verifyThatTestWindowCanFakeProperty( tester: tester, realValue: ui.window.viewInsets, fakeValue: const FakeViewPadding(), @@ -61,12 +55,11 @@ void main() { propertyFaker: (TestWidgetsFlutterBinding binding, ViewPadding fakeValue) { binding.window.viewInsetsTestValue = fakeValue; }, - matcher: matchesViewPadding, ); }); testWidgets('TestWindow can fake padding', (WidgetTester tester) async { - verifyPropertyFaked( + verifyThatTestWindowCanFakeProperty( tester: tester, realValue: ui.window.padding, fakeValue: const FakeViewPadding(), @@ -76,12 +69,11 @@ void main() { propertyFaker: (TestWidgetsFlutterBinding binding, ViewPadding fakeValue) { binding.window.paddingTestValue = fakeValue; }, - matcher: matchesViewPadding ); }); testWidgets('TestWindow can fake locale', (WidgetTester tester) async { - verifyPropertyFaked( + verifyThatTestWindowCanFakeProperty( tester: tester, realValue: ui.window.locale, fakeValue: const Locale('fake_language_code'), @@ -95,7 +87,7 @@ void main() { }); testWidgets('TestWindow can fake locales', (WidgetTester tester) async { - verifyPropertyFaked>( + verifyThatTestWindowCanFakeProperty>( tester: tester, realValue: ui.window.locales, fakeValue: [const Locale('fake_language_code')], @@ -109,7 +101,7 @@ void main() { }); testWidgets('TestWindow can fake text scale factor', (WidgetTester tester) async { - verifyPropertyFaked( + verifyThatTestWindowCanFakeProperty( tester: tester, realValue: ui.window.textScaleFactor, fakeValue: 2.5, @@ -123,7 +115,7 @@ void main() { }); testWidgets('TestWindow can fake clock format', (WidgetTester tester) async { - verifyPropertyFaked( + verifyThatTestWindowCanFakeProperty( tester: tester, realValue: ui.window.alwaysUse24HourFormat, fakeValue: !ui.window.alwaysUse24HourFormat, @@ -137,7 +129,7 @@ void main() { }); testWidgets('TestWindow can fake brieflyShowPassword', (WidgetTester tester) async { - verifyPropertyFaked( + verifyThatTestWindowCanFakeProperty( tester: tester, realValue: ui.window.brieflyShowPassword, fakeValue: !ui.window.brieflyShowPassword, @@ -149,7 +141,7 @@ void main() { }); testWidgets('TestWindow can fake default route name', (WidgetTester tester) async { - verifyPropertyFaked( + verifyThatTestWindowCanFakeProperty( tester: tester, realValue: ui.window.defaultRouteName, fakeValue: 'fake_route', @@ -163,7 +155,7 @@ void main() { }); testWidgets('TestWindow can fake accessibility features', (WidgetTester tester) async { - verifyPropertyFaked( + verifyThatTestWindowCanFakeProperty( tester: tester, realValue: ui.window.accessibilityFeatures, fakeValue: const FakeAccessibilityFeatures(), @@ -177,7 +169,7 @@ void main() { }); testWidgets('TestWindow can fake platform brightness', (WidgetTester tester) async { - verifyPropertyFaked( + verifyThatTestWindowCanFakeProperty( tester: tester, realValue: Brightness.light, fakeValue: Brightness.dark, @@ -217,27 +209,63 @@ void main() { retrieveTestBinding(tester).window.localesTestValue = defaultLocales; }); - testWidgets('Updates to window also update tester.view', (WidgetTester tester) async { - tester.binding.window.devicePixelRatioTestValue = 7; - tester.binding.window.displayFeaturesTestValue = [const DisplayFeature(bounds: Rect.fromLTWH(0, 0, 20, 300), type: DisplayFeatureType.unknown, state: DisplayFeatureState.unknown)]; - tester.binding.window.paddingTestValue = const FakeViewPadding(); - tester.binding.window.physicalSizeTestValue = const Size(505, 805); - tester.binding.window.systemGestureInsetsTestValue = const FakeViewPadding(); - tester.binding.window.viewInsetsTestValue = const FakeViewPadding(); - tester.binding.window.viewPaddingTestValue = const FakeViewPadding(); - tester.binding.window.gestureSettingsTestValue = const GestureSettings(physicalTouchSlop: 4, physicalDoubleTapSlop: 5); - - expect(tester.binding.window.devicePixelRatio, tester.view.devicePixelRatio); - expect(tester.binding.window.displayFeatures, tester.view.displayFeatures); - expect(tester.binding.window.padding, tester.view.padding); - expect(tester.binding.window.physicalSize, tester.view.physicalSize); - expect(tester.binding.window.systemGestureInsets, tester.view.systemGestureInsets); - expect(tester.binding.window.viewInsets, tester.view.viewInsets); - expect(tester.binding.window.viewPadding, tester.view.viewPadding); - expect(tester.binding.window.gestureSettings, tester.view.gestureSettings); +test('Window test', () { + final FakeSingletonWindow fakeWindow = FakeSingletonWindow(); + final TestWindow testWindow = TestWindow(window: fakeWindow); + final SemanticsUpdate update = SemanticsUpdateBuilder().build(); + testWindow.updateSemantics(update); + expect(fakeWindow.lastUpdate, update); }); } +void verifyThatTestWindowCanFakeProperty({ + required WidgetTester tester, + required WindowPropertyType? realValue, + required WindowPropertyType fakeValue, + required WindowPropertyType? Function() propertyRetriever, + required Function(TestWidgetsFlutterBinding, WindowPropertyType fakeValue) propertyFaker, +}) { + WindowPropertyType? propertyBeforeFaking; + WindowPropertyType? propertyAfterFaking; + + propertyBeforeFaking = propertyRetriever(); + + propertyFaker(retrieveTestBinding(tester), fakeValue); + + propertyAfterFaking = propertyRetriever(); + + expect(propertyBeforeFaking, realValue); + expect(propertyAfterFaking, fakeValue); +} + +TestWidgetsFlutterBinding retrieveTestBinding(WidgetTester tester) { + final WidgetsBinding binding = tester.binding; + assert(binding is TestWidgetsFlutterBinding); + final TestWidgetsFlutterBinding testBinding = binding as TestWidgetsFlutterBinding; + return testBinding; +} + +class FakeViewPadding implements ViewPadding { + const FakeViewPadding({ + this.left = 0.0, + this.top = 0.0, + this.right = 0.0, + this.bottom = 0.0, + }); + + @override + final double left; + + @override + final double top; + + @override + final double right; + + @override + final double bottom; +} + class TestObserver with WidgetsBindingObserver { List? locales; Locale? locale; @@ -247,3 +275,15 @@ class TestObserver with WidgetsBindingObserver { this.locales = locales; } } + +class FakeSingletonWindow extends Fake implements SingletonFlutterWindow { + SemanticsUpdate? lastUpdate; + + @override + PlatformDispatcher get platformDispatcher => PlatformDispatcher.instance; + + @override + void updateSemantics(SemanticsUpdate update) { + lastUpdate = update; + } +} diff --git a/packages/integration_test/lib/integration_test.dart b/packages/integration_test/lib/integration_test.dart index f1df051bc3a..254cc89888c 100644 --- a/packages/integration_test/lib/integration_test.dart +++ b/packages/integration_test/lib/integration_test.dart @@ -120,9 +120,9 @@ https://flutter.dev/docs/testing/integration-tests#testing-on-firebase-test-lab ViewConfiguration createViewConfiguration() { final double devicePixelRatio = window.devicePixelRatio; final Size size = _surfaceSize ?? window.physicalSize / devicePixelRatio; - return TestViewConfiguration.fromView( + return TestViewConfiguration( size: size, - view: window, + window: window, ); }