Revert PRs relating to single window assumption (#122369)

* Revert "Remove references to BindingBase.window (#122119)"

This reverts commit c7681f00cf.

* Revert "Remove another reference to BindingBase.window (#122341)"

This reverts commit 6ec4445063.

* Revert "Reland (2): Removes single window assumptions from `flutter_test` (#122233)"

This reverts commit eb3d317ea0.

* Revert "Remove single view assumption from TestViewConfiguration (#122352)"

This reverts commit 927289fb4e.

* Revert "Updates `flutter/test/cupertino` to no longer use `TestWindow` (#122325)"

This reverts commit 67e17e45f0.

* Revert "Updates `flutter/test/gestures` to no longer reference `TestWindow` (#122327)"

This reverts commit c2a5111cc0.

* Revert "Updates `flutter/test/rendering` to no longer use `TestWindow` (#122347)"

This reverts commit 28b65e089b.

* Revert "Updates `flutter_localizations/test` to stop using `TestWindow` (#122321)"

This reverts commit 01367d52d7.
This commit is contained in:
Casey Hillers 2023-03-09 22:53:38 -08:00 committed by GitHub
parent ac550c6356
commit 1f42612323
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 1488 additions and 2749 deletions

View File

@ -31,13 +31,13 @@ Future<void> main() async {
await tester.pump(); // Start drawer animation await tester.pump(); // Start drawer animation
await tester.pump(const Duration(seconds: 1)); // Complete 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), 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), size: const Size(355.0, 635.0),
view: tester.view, window: RendererBinding.instance.window,
); );
final RenderView renderView = WidgetsBinding.instance.renderView; final RenderView renderView = WidgetsBinding.instance.renderView;
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.benchmark; binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.benchmark;

View File

@ -58,8 +58,8 @@ void main() {
expect(find.text('Account Balance'), findsNothing); expect(find.text('Account Balance'), findsNothing);
// drag the drawer out // drag the drawer out
final Offset left = Offset(0.0, (tester.view.physicalSize / tester.view.devicePixelRatio).height / 2.0); final Offset left = Offset(0.0, (WidgetsBinding.instance.window.physicalSize / WidgetsBinding.instance.window.devicePixelRatio).height / 2.0);
final Offset right = Offset((tester.view.physicalSize / tester.view.devicePixelRatio).width, left.dy); final Offset right = Offset((WidgetsBinding.instance.window.physicalSize / WidgetsBinding.instance.window.devicePixelRatio).width, left.dy);
final TestGesture gesture = await tester.startGesture(left); final TestGesture gesture = await tester.startGesture(left);
await tester.pump(); await tester.pump();
await gesture.moveTo(right); await gesture.moveTo(right);

View File

@ -901,13 +901,15 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
/// Used by [runApp] to wrap the provided `rootWidget` in the default [View]. /// Used by [runApp] to wrap the provided `rootWidget` in the default [View].
/// ///
/// The [View] determines into what [FlutterView] the app is rendered into. /// 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 /// The `rootWidget` widget provided to this method must not already be
/// wrapped in a [View]. /// wrapped in a [View].
Widget wrapWithDefaultView(Widget rootWidget) { Widget wrapWithDefaultView(Widget rootWidget) {
return View( return View(
view: platformDispatcher.implicitView!, view: window,
child: rootWidget, child: rootWidget,
); );
} }

View File

@ -1702,7 +1702,6 @@ void main() {
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(
view: tester.view,
pages: myPages, pages: myPages,
onPopPage: (Route<dynamic> route, dynamic result) { onPopPage: (Route<dynamic> route, dynamic result) {
assert(false); // The test shouldn't call this. assert(false); // The test shouldn't call this.
@ -1729,7 +1728,6 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(
view: tester.view,
pages: myPages, pages: myPages,
onPopPage: (Route<dynamic> route, dynamic result) { onPopPage: (Route<dynamic> route, dynamic result) {
assert(false); // The test shouldn't call this. assert(false); // The test shouldn't call this.
@ -1758,7 +1756,6 @@ void main() {
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(
view: tester.view,
pages: myPages, pages: myPages,
onPopPage: (Route<dynamic> route, dynamic result) { onPopPage: (Route<dynamic> route, dynamic result) {
assert(false); // The test shouldn't call this. assert(false); // The test shouldn't call this.
@ -1780,7 +1777,6 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(
view: tester.view,
pages: myPages, pages: myPages,
onPopPage: (Route<dynamic> route, dynamic result) { onPopPage: (Route<dynamic> route, dynamic result) {
assert(false); // The test shouldn't call this. assert(false); // The test shouldn't call this.
@ -2217,13 +2213,12 @@ class TransitionDetector extends DefaultTransitionDelegate<void> {
Widget buildNavigator({ Widget buildNavigator({
required List<Page<dynamic>> pages, required List<Page<dynamic>> pages,
required FlutterView view,
PopPageCallback? onPopPage, PopPageCallback? onPopPage,
GlobalKey<NavigatorState>? key, GlobalKey<NavigatorState>? key,
TransitionDelegate<dynamic>? transitionDelegate, TransitionDelegate<dynamic>? transitionDelegate,
}) { }) {
return MediaQuery( return MediaQuery(
data: MediaQueryData.fromView(view), data: MediaQueryData.fromView(WidgetsBinding.instance.window),
child: Localizations( child: Localizations(
locale: const Locale('en', 'US'), locale: const Locale('en', 'US'),
delegates: const <LocalizationsDelegate<dynamic>>[ delegates: const <LocalizationsDelegate<dynamic>>[

View File

@ -251,7 +251,7 @@ void main() {
const double inset = 3; const double inset = 3;
const double scaleFactor = 2; 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(); final ScrollController scrollController = ScrollController();
await tester.pumpWidget( await tester.pumpWidget(

View File

@ -2,10 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // 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: // reduced-test-set:
// This file is run as part of a reduced test set in CI on Mac and Windows // This file is run as part of a reduced test set in CI on Mac and Windows
// machines. // machines.
@Tags(<String>['reduced-test-set']) @Tags(<String>['reduced-test-set', 'no-shuffle'])
library; library;
import 'dart:ui' as ui show BoxHeightStyle, BoxWidthStyle, Color; import 'dart:ui' as ui show BoxHeightStyle, BoxWidthStyle, Color;
@ -4998,11 +5003,9 @@ void main() {
group('Text selection toolbar', () { group('Text selection toolbar', () {
testWidgets('Collapsed selection works', (WidgetTester tester) async { 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; EditableText.debugDeterministicCursor = true;
tester.binding.window.physicalSizeTestValue = const Size(400, 400);
tester.binding.window.devicePixelRatioTestValue = 1;
TextEditingController controller; TextEditingController controller;
EditableTextState state; EditableTextState state;
Offset bottomLeftSelectionPosition; Offset bottomLeftSelectionPosition;
@ -5180,14 +5183,15 @@ void main() {
), ),
), ),
); );
tester.binding.window.clearPhysicalSizeTestValue();
tester.binding.window.clearDevicePixelRatioTestValue();
}); });
testWidgets('selecting multiple words works', (WidgetTester tester) async { 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; EditableText.debugDeterministicCursor = true;
tester.binding.window.physicalSizeTestValue = const Size(400, 400);
tester.binding.window.devicePixelRatioTestValue = 1;
final TextEditingController controller; final TextEditingController controller;
final EditableTextState state; final EditableTextState state;
@ -5249,14 +5253,15 @@ void main() {
), ),
), ),
); );
tester.binding.window.clearPhysicalSizeTestValue();
tester.binding.window.clearDevicePixelRatioTestValue();
}); });
testWidgets('selecting multiline works', (WidgetTester tester) async { 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; EditableText.debugDeterministicCursor = true;
tester.binding.window.physicalSizeTestValue = const Size(400, 400);
tester.binding.window.devicePixelRatioTestValue = 1;
final TextEditingController controller; final TextEditingController controller;
final EditableTextState state; final EditableTextState state;
@ -5322,6 +5327,9 @@ void main() {
), ),
), ),
); );
tester.binding.window.clearPhysicalSizeTestValue();
tester.binding.window.clearDevicePixelRatioTestValue();
}); });
// This is a regression test for // This is a regression test for

View File

@ -246,8 +246,8 @@ void main() {
testWidgets("When a menu item doesn't fit, a second page is used.", (WidgetTester tester) async { 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. // Set the screen size to more narrow, so that Paste can't fit.
tester.view.physicalSize = const Size(800, 800); tester.binding.window.physicalSizeTestValue = const Size(800, 800);
addTearDown(tester.view.reset); addTearDown(tester.binding.window.clearPhysicalSizeTestValue);
final TextEditingController controller = TextEditingController(text: 'abc def ghi'); final TextEditingController controller = TextEditingController(text: 'abc def ghi');
await tester.pumpWidget(CupertinoApp( await tester.pumpWidget(CupertinoApp(
@ -318,8 +318,8 @@ void main() {
testWidgets('A smaller menu puts each button on its own page.', (WidgetTester tester) async { 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 // Set the screen size to more narrow, so that two buttons can't fit on
// the same page. // the same page.
tester.view.physicalSize = const Size(640, 800); tester.binding.window.physicalSizeTestValue = const Size(640, 800);
addTearDown(tester.view.reset); addTearDown(tester.binding.window.clearPhysicalSizeTestValue);
final TextEditingController controller = TextEditingController(text: 'abc def ghi'); final TextEditingController controller = TextEditingController(text: 'abc def ghi');
await tester.pumpWidget(CupertinoApp( await tester.pumpWidget(CupertinoApp(

View File

@ -188,8 +188,8 @@ void main() {
testWidgets('does not paginate if children fit with zero margin', (WidgetTester tester) async { testWidgets('does not paginate if children fit with zero margin', (WidgetTester tester) async {
final List<Widget> children = List<Widget>.generate(7, (int i) => const TestBox()); final List<Widget> children = List<Widget>.generate(7, (int i) => const TestBox());
final double spacerWidth = 1.0 / tester.view.devicePixelRatio; final double spacerWidth = 1.0 / tester.binding.window.devicePixelRatio;
final double dividerWidth = 1.0 / tester.view.devicePixelRatio; final double dividerWidth = 1.0 / tester.binding.window.devicePixelRatio;
const double borderRadius = 8.0; // Should match _kToolbarBorderRadius const double borderRadius = 8.0; // Should match _kToolbarBorderRadius
final double width = 7 * TestBox.itemWidth + 6 * (dividerWidth + 2 * spacerWidth) + 2 * borderRadius; final double width = 7 * TestBox.itemWidth + 6 * (dividerWidth + 2 * spacerWidth) + 2 * borderRadius;
await tester.pumpWidget( await tester.pumpWidget(

View File

@ -101,7 +101,7 @@ void main() {
expect(events.length, 1); expect(events.length, 1);
expect(events[0], isA<PointerDownEvent>()); expect(events[0], isA<PointerDownEvent>());
expect(events[0].timeStamp, currentTestFrameTime() + kSamplingOffset); 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 // Now the system time is epoch + 20ms
requestFrame(); requestFrame();
@ -109,8 +109,8 @@ void main() {
expect(events.length, 2); expect(events.length, 2);
expect(events[1].timeStamp, currentTestFrameTime() + kSamplingOffset); expect(events[1].timeStamp, currentTestFrameTime() + kSamplingOffset);
expect(events[1], isA<PointerMoveEvent>()); expect(events[1], isA<PointerMoveEvent>());
expect(events[1].position, Offset(22.5 / 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 / tester.view.devicePixelRatio, 0.0)); expect(events[1].delta, Offset(15.0 / GestureBinding.instance.window.devicePixelRatio, 0.0));
// Now the system time is epoch + 30ms // Now the system time is epoch + 30ms
requestFrame(); requestFrame();
@ -118,8 +118,8 @@ void main() {
expect(events.length, 4); expect(events.length, 4);
expect(events[2].timeStamp, currentTestFrameTime() + kSamplingOffset); expect(events[2].timeStamp, currentTestFrameTime() + kSamplingOffset);
expect(events[2], isA<PointerMoveEvent>()); expect(events[2], isA<PointerMoveEvent>());
expect(events[2].position, Offset(37.5 / 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 / tester.view.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].timeStamp, currentTestFrameTime() + kSamplingOffset);
expect(events[3], isA<PointerUpEvent>()); expect(events[3], isA<PointerUpEvent>());
}); });

View File

@ -162,8 +162,6 @@ void main() {
expect(events[1], isA<PointerCancelEvent>()); expect(events[1], isA<PointerCancelEvent>());
}); });
const double devicePixelRatio = 2.5;
test('Can expand add and hover pointers', () { test('Can expand add and hover pointers', () {
const ui.PointerDataPacket packet = ui.PointerDataPacket( const ui.PointerDataPacket packet = ui.PointerDataPacket(
data: <ui.PointerData>[ data: <ui.PointerData>[
@ -175,7 +173,7 @@ void main() {
], ],
); );
final List<PointerEvent> events = PointerEventConverter.expand(packet.data, devicePixelRatio).toList(); final List<PointerEvent> events = PointerEventConverter.expand(packet.data, GestureBinding.instance.window.devicePixelRatio).toList();
expect(events.length, 5); expect(events.length, 5);
expect(events[0], isA<PointerAddedEvent>()); expect(events[0], isA<PointerAddedEvent>());
@ -191,7 +189,7 @@ void main() {
ui.PointerData(change: ui.PointerChange.add, device: 24), ui.PointerData(change: ui.PointerChange.add, device: 24),
], ],
); );
List<PointerEvent> events = PointerEventConverter.expand(packet.data, devicePixelRatio).toList(); List<PointerEvent> events = PointerEventConverter.expand(packet.data, GestureBinding.instance.window.devicePixelRatio).toList();
expect(events.length, 1); expect(events.length, 1);
expect(events[0], isA<PointerAddedEvent>()); expect(events[0], isA<PointerAddedEvent>());
@ -207,7 +205,7 @@ void main() {
ui.PointerData(signalKind: ui.PointerSignalKind.scroll, device: 24, scrollDeltaY: double.negativeInfinity, scrollDeltaX: 10), 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); expect(events.length, 0);
// Send packet with a valid scroll event. // Send packet with a valid scroll event.
@ -217,7 +215,7 @@ void main() {
], ],
); );
// Make sure PointerEventConverter can expand when device pixel ratio is valid. // 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.length, 1);
expect(events[0], isA<PointerScrollEvent>()); expect(events[0], isA<PointerScrollEvent>());
@ -234,7 +232,7 @@ void main() {
], ],
); );
final List<PointerEvent> events = PointerEventConverter.expand(packet.data, devicePixelRatio).toList(); final List<PointerEvent> events = PointerEventConverter.expand(packet.data, GestureBinding.instance.window.devicePixelRatio).toList();
expect(events.length, 2); expect(events.length, 2);
expect(events[0], isA<PointerAddedEvent>()); expect(events[0], isA<PointerAddedEvent>());
@ -242,7 +240,7 @@ void main() {
}); });
test('Should synthesize kPrimaryButton for touch when no button is set', () { 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( final ui.PointerDataPacket packet = ui.PointerDataPacket(
data: <ui.PointerData>[ data: <ui.PointerData>[
ui.PointerData(change: ui.PointerChange.add, physicalX: location.dx, physicalY: location.dy), ui.PointerData(change: ui.PointerChange.add, physicalX: location.dx, physicalY: location.dy),
@ -253,7 +251,7 @@ void main() {
], ],
); );
final List<PointerEvent> events = PointerEventConverter.expand(packet.data, devicePixelRatio).toList(); final List<PointerEvent> events = PointerEventConverter.expand(packet.data, GestureBinding.instance.window.devicePixelRatio).toList();
expect(events.length, 5); expect(events.length, 5);
expect(events[0], isA<PointerAddedEvent>()); expect(events[0], isA<PointerAddedEvent>());
@ -269,7 +267,7 @@ void main() {
}); });
test('Should not synthesize kPrimaryButton for touch when a button is set', () { 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( final ui.PointerDataPacket packet = ui.PointerDataPacket(
data: <ui.PointerData>[ data: <ui.PointerData>[
ui.PointerData(change: ui.PointerChange.add, physicalX: location.dx, physicalY: location.dy), ui.PointerData(change: ui.PointerChange.add, physicalX: location.dx, physicalY: location.dy),
@ -280,7 +278,7 @@ void main() {
], ],
); );
final List<PointerEvent> events = PointerEventConverter.expand(packet.data, devicePixelRatio).toList(); final List<PointerEvent> events = PointerEventConverter.expand(packet.data, GestureBinding.instance.window.devicePixelRatio).toList();
expect(events.length, 5); expect(events.length, 5);
expect(events[0], isA<PointerAddedEvent>()); expect(events[0], isA<PointerAddedEvent>());
@ -296,7 +294,7 @@ void main() {
}); });
test('Should synthesize kPrimaryButton for stylus when no button is set', () { 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>[ for (final PointerDeviceKind kind in <PointerDeviceKind>[
PointerDeviceKind.stylus, PointerDeviceKind.stylus,
PointerDeviceKind.invertedStylus, PointerDeviceKind.invertedStylus,
@ -312,7 +310,7 @@ void main() {
], ],
); );
final List<PointerEvent> events = PointerEventConverter.expand(packet.data, devicePixelRatio).toList(); final List<PointerEvent> events = PointerEventConverter.expand(packet.data, GestureBinding.instance.window.devicePixelRatio).toList();
expect(events.length, 5); expect(events.length, 5);
expect(events[0], isA<PointerAddedEvent>()); expect(events[0], isA<PointerAddedEvent>());
@ -329,7 +327,7 @@ void main() {
}); });
test('Should synthesize kPrimaryButton for unknown devices when no button is set', () { 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; const PointerDeviceKind kind = PointerDeviceKind.unknown;
final ui.PointerDataPacket packet = ui.PointerDataPacket( final ui.PointerDataPacket packet = ui.PointerDataPacket(
data: <ui.PointerData>[ data: <ui.PointerData>[
@ -341,7 +339,7 @@ void main() {
], ],
); );
final List<PointerEvent> events = PointerEventConverter.expand(packet.data, devicePixelRatio).toList(); final List<PointerEvent> events = PointerEventConverter.expand(packet.data, GestureBinding.instance.window.devicePixelRatio).toList();
expect(events.length, 5); expect(events.length, 5);
expect(events[0], isA<PointerAddedEvent>()); expect(events[0], isA<PointerAddedEvent>());
@ -357,7 +355,7 @@ void main() {
}); });
test('Should not synthesize kPrimaryButton for mouse', () { 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>[ for (final PointerDeviceKind kind in <PointerDeviceKind>[
PointerDeviceKind.mouse, PointerDeviceKind.mouse,
]) { ]) {
@ -371,7 +369,7 @@ void main() {
], ],
); );
final List<PointerEvent> events = PointerEventConverter.expand(packet.data, devicePixelRatio).toList(); final List<PointerEvent> events = PointerEventConverter.expand(packet.data, GestureBinding.instance.window.devicePixelRatio).toList();
expect(events.length, 5); expect(events.length, 5);
expect(events[0], isA<PointerAddedEvent>()); expect(events[0], isA<PointerAddedEvent>());

View File

@ -90,9 +90,7 @@ class NestedDraggableCase extends StatelessWidget {
void main() { void main() {
testWidgets('Scroll Views get the same ScrollConfiguration as GestureDetectors', (WidgetTester tester) async { testWidgets('Scroll Views get the same ScrollConfiguration as GestureDetectors', (WidgetTester tester) async {
tester.view.gestureSettings = const ui.GestureSettings(physicalTouchSlop: 4); tester.binding.window.gestureSettingsTestValue = const ui.GestureSettings(physicalTouchSlop: 4);
addTearDown(tester.view.reset);
final TestResult result = TestResult(); final TestResult result = TestResult();
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
@ -110,11 +108,11 @@ void main() {
expect(result.dragStarted, true); expect(result.dragStarted, true);
expect(result.dragUpdate, true); expect(result.dragUpdate, true);
tester.binding.window.clearGestureSettingsTestValue();
}); });
testWidgets('Scroll Views get the same ScrollConfiguration as Draggables', (WidgetTester tester) async { testWidgets('Scroll Views get the same ScrollConfiguration as Draggables', (WidgetTester tester) async {
tester.view.gestureSettings = const ui.GestureSettings(physicalTouchSlop: 4); tester.binding.window.gestureSettingsTestValue = const ui.GestureSettings(physicalTouchSlop: 4);
addTearDown(tester.view.reset);
final TestResult result = TestResult(); final TestResult result = TestResult();
@ -133,5 +131,6 @@ void main() {
expect(result.dragStarted, true); expect(result.dragStarted, true);
expect(result.dragUpdate, true); expect(result.dragUpdate, true);
tester.binding.window.clearGestureSettingsTestValue();
}); });
} }

View File

@ -235,7 +235,7 @@ void main() {
' MediaQuery\n' ' MediaQuery\n'
' _MediaQueryFromView\n' ' _MediaQueryFromView\n'
' _ViewScope\n' ' _ViewScope\n'
' View-[GlobalObjectKey TestFlutterView#00000]\n' ' View-[GlobalObjectKey TestWindow#00000]\n'
' [root]\n' ' [root]\n'
' Typically, the Scaffold widget is introduced by the MaterialApp\n' ' Typically, the Scaffold widget is introduced by the MaterialApp\n'
' or WidgetsApp widget at the top of your application widget tree.\n' ' or WidgetsApp widget at the top of your application widget tree.\n'
@ -376,7 +376,7 @@ void main() {
' MediaQuery\n' ' MediaQuery\n'
' _MediaQueryFromView\n' ' _MediaQueryFromView\n'
' _ViewScope\n' ' _ViewScope\n'
' View-[GlobalObjectKey TestFlutterView#00000]\n' ' View-[GlobalObjectKey TestWindow#00000]\n'
' [root]\n' ' [root]\n'
' Typically, the ScaffoldMessenger widget is introduced by the\n' ' Typically, the ScaffoldMessenger widget is introduced by the\n'
' MaterialApp at the top of your application widget tree.\n' ' MaterialApp at the top of your application widget tree.\n'

View File

@ -1042,7 +1042,6 @@ void main() {
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(
view: tester.view,
pages: myPages, pages: myPages,
onPopPage: (Route<dynamic> route, dynamic result) { onPopPage: (Route<dynamic> route, dynamic result) {
assert(false); // The test should never execute this. assert(false); // The test should never execute this.
@ -1061,7 +1060,6 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(
view: tester.view,
pages: myPages, pages: myPages,
onPopPage: (Route<dynamic> route, dynamic result) { onPopPage: (Route<dynamic> route, dynamic result) {
assert(false); // The test should never execute this. assert(false); // The test should never execute this.
@ -1087,7 +1085,6 @@ void main() {
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(
view: tester.view,
pages: myPages, pages: myPages,
onPopPage: (Route<dynamic> route, dynamic result) { onPopPage: (Route<dynamic> route, dynamic result) {
assert(false); // The test should never execute this. assert(false); // The test should never execute this.
@ -1109,7 +1106,6 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(
view: tester.view,
pages: myPages, pages: myPages,
onPopPage: (Route<dynamic> route, dynamic result) { onPopPage: (Route<dynamic> route, dynamic result) {
assert(false); // The test should never execute this. assert(false); // The test should never execute this.
@ -1218,12 +1214,11 @@ class TransitionDetector extends DefaultTransitionDelegate<void> {
Widget buildNavigator({ Widget buildNavigator({
required List<Page<dynamic>> pages, required List<Page<dynamic>> pages,
required PopPageCallback onPopPage, required PopPageCallback onPopPage,
required ui.FlutterView view,
GlobalKey<NavigatorState>? key, GlobalKey<NavigatorState>? key,
TransitionDelegate<dynamic>? transitionDelegate, TransitionDelegate<dynamic>? transitionDelegate,
}) { }) {
return MediaQuery( return MediaQuery(
data: MediaQueryData.fromView(view), data: MediaQueryData.fromView(WidgetsBinding.instance.window),
child: Localizations( child: Localizations(
locale: const Locale('en', 'US'), locale: const Locale('en', 'US'),
delegates: const <LocalizationsDelegate<dynamic>>[ delegates: const <LocalizationsDelegate<dynamic>>[

View File

@ -2454,7 +2454,7 @@ void main() {
' MediaQuery\n' ' MediaQuery\n'
' _MediaQueryFromView\n' ' _MediaQueryFromView\n'
' _ViewScope\n' ' _ViewScope\n'
' View-[GlobalObjectKey TestFlutterView#e6136]\n' ' View-[GlobalObjectKey TestWindow#e6136]\n'
' [root]\n' ' [root]\n'
' Typically, the ScaffoldMessenger widget is introduced by the\n' ' Typically, the ScaffoldMessenger widget is introduced by the\n'
' MaterialApp at the top of your application widget tree.\n', ' MaterialApp at the top of your application widget tree.\n',

View File

@ -52,7 +52,7 @@ void main() {
test('debugInvertOversizedImages', () async { test('debugInvertOversizedImages', () async {
debugInvertOversizedImages = true; 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 FlutterExceptionHandler? oldFlutterError = FlutterError.onError;
final List<String> messages = <String>[]; final List<String> messages = <String>[];
@ -180,7 +180,7 @@ void main() {
expect(imageSizeInfo, isNotNull); expect(imageSizeInfo, isNotNull);
expect(imageSizeInfo.source, 'test.png'); expect(imageSizeInfo.source, 'test.png');
expect(imageSizeInfo.imageSize, const Size(300, 300)); 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 // Make sure that we don't report an identical image size info if we
// redraw in the next frame. // redraw in the next frame.
@ -219,7 +219,7 @@ void main() {
expect(imageSizeInfo, isNotNull); expect(imageSizeInfo, isNotNull);
expect(imageSizeInfo.source, 'test.png'); expect(imageSizeInfo.source, 'test.png');
expect(imageSizeInfo.imageSize, const Size(300, 300)); 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 // Make sure that we don't report an identical image size info if we
// redraw in the next frame. // redraw in the next frame.
@ -237,7 +237,7 @@ void main() {
expect(imageSizeInfo, isNotNull); expect(imageSizeInfo, isNotNull);
expect(imageSizeInfo.source, 'test.png'); expect(imageSizeInfo.source, 'test.png');
expect(imageSizeInfo.imageSize, const Size(300, 300)); 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; debugOnPaintImage = null;
}); });
@ -261,7 +261,7 @@ void main() {
expect(imageSizeInfo, isNotNull); expect(imageSizeInfo, isNotNull);
expect(imageSizeInfo.source, '<Unknown Image(300×200)>'); expect(imageSizeInfo.source, '<Unknown Image(300×200)>');
expect(imageSizeInfo.imageSize, const Size(300, 200)); 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; debugOnPaintImage = null;
}); });

View File

@ -44,7 +44,7 @@ void main() {
expect(offscreen.child.hasSize, isFalse); expect(offscreen.child.hasSize, isFalse);
expect(offscreen.painted, isFalse); expect(offscreen.painted, isFalse);
// Attach the offscreen to a custom render view and owner // 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(); final PipelineOwner pipelineOwner = PipelineOwner();
renderView.attach(pipelineOwner); renderView.attach(pipelineOwner);
renderView.child = offscreen.root; renderView.child = offscreen.root;
@ -66,7 +66,6 @@ void main() {
pipelineOwner.flushPaint(); pipelineOwner.flushPaint();
expect(offscreen.painted, isTrue); expect(offscreen.painted, isTrue);
}); });
test('offscreen layout does not affect onscreen', () { test('offscreen layout does not affect onscreen', () {
final TestLayout onscreen = TestLayout(); final TestLayout onscreen = TestLayout();
final TestLayout offscreen = TestLayout(); final TestLayout offscreen = TestLayout();
@ -75,7 +74,7 @@ void main() {
expect(offscreen.child.hasSize, isFalse); expect(offscreen.child.hasSize, isFalse);
expect(offscreen.painted, isFalse); expect(offscreen.painted, isFalse);
// Attach the offscreen to a custom render view and owner // 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(); final PipelineOwner pipelineOwner = PipelineOwner();
renderView.attach(pipelineOwner); renderView.attach(pipelineOwner);
renderView.child = offscreen.root; renderView.child = offscreen.root;

View File

@ -169,7 +169,7 @@ void main() {
test('switching layer link of an attached leader layer should not crash', () { test('switching layer link of an attached leader layer should not crash', () {
final LayerLink link = LayerLink(); final LayerLink link = LayerLink();
final LeaderLayer leaderLayer = LeaderLayer(link: link); 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); leaderLayer.attach(view);
final LayerLink link2 = LayerLink(); final LayerLink link2 = LayerLink();
leaderLayer.link = link2; leaderLayer.link = link2;
@ -182,7 +182,7 @@ void main() {
final LayerLink link = LayerLink(); final LayerLink link = LayerLink();
final LeaderLayer leaderLayer1 = LeaderLayer(link: link); final LeaderLayer leaderLayer1 = LeaderLayer(link: link);
final LeaderLayer leaderLayer2 = 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); leaderLayer1.attach(view);
leaderLayer2.attach(view); leaderLayer2.attach(view);
leaderLayer2.detach(); leaderLayer2.detach();

View File

@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
@ -14,18 +16,18 @@ void main() {
const double deviceWidth = 480.0; const double deviceWidth = 480.0;
const double devicePixelRatio = 2.0; const double devicePixelRatio = 2.0;
void setupTestDevice(WidgetTester tester) { void setupTestDevice() {
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
const FakeViewPadding padding = FakeViewPadding( const FakeViewPadding padding = FakeViewPadding(
top: statusBarHeight * devicePixelRatio, top: statusBarHeight * devicePixelRatio,
bottom: navigationBarHeight * devicePixelRatio, bottom: navigationBarHeight * devicePixelRatio,
); );
addTearDown(tester.view.reset); binding.window
tester.view ..viewPaddingTestValue = padding
..viewPadding = padding ..paddingTestValue = padding
..padding = padding ..devicePixelRatioTestValue = devicePixelRatio
..devicePixelRatio = devicePixelRatio ..physicalSizeTestValue = const Size(
..physicalSize = const Size(
deviceWidth * devicePixelRatio, deviceWidth * devicePixelRatio,
deviceHeight * devicePixelRatio, deviceHeight * devicePixelRatio,
); );
@ -50,7 +52,7 @@ void main() {
testWidgets( testWidgets(
'statusBarColor is set for annotated view', 'statusBarColor is set for annotated view',
(WidgetTester tester) async { (WidgetTester tester) async {
setupTestDevice(tester); setupTestDevice();
await tester.pumpWidget(const AnnotatedRegion<SystemUiOverlayStyle>( await tester.pumpWidget(const AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle( value: SystemUiOverlayStyle(
statusBarColor: Colors.blue, statusBarColor: Colors.blue,
@ -70,7 +72,7 @@ void main() {
testWidgets( testWidgets(
"statusBarColor isn't set when view covers less than half of the system status bar", "statusBarColor isn't set when view covers less than half of the system status bar",
(WidgetTester tester) async { (WidgetTester tester) async {
setupTestDevice(tester); setupTestDevice();
const double lessThanHalfOfTheStatusBarHeight = const double lessThanHalfOfTheStatusBarHeight =
statusBarHeight / 2.0 - 1; statusBarHeight / 2.0 - 1;
await tester.pumpWidget(const Align( await tester.pumpWidget(const Align(
@ -95,7 +97,7 @@ void main() {
testWidgets( testWidgets(
'statusBarColor is set when view covers more than half of tye system status bar', 'statusBarColor is set when view covers more than half of tye system status bar',
(WidgetTester tester) async { (WidgetTester tester) async {
setupTestDevice(tester); setupTestDevice();
const double moreThanHalfOfTheStatusBarHeight = const double moreThanHalfOfTheStatusBarHeight =
statusBarHeight / 2.0 + 1; statusBarHeight / 2.0 + 1;
await tester.pumpWidget(const Align( await tester.pumpWidget(const Align(
@ -125,7 +127,7 @@ void main() {
testWidgets( testWidgets(
"systemNavigationBarColor isn't set for non Android device", "systemNavigationBarColor isn't set for non Android device",
(WidgetTester tester) async { (WidgetTester tester) async {
setupTestDevice(tester); setupTestDevice();
await tester.pumpWidget(const AnnotatedRegion<SystemUiOverlayStyle>( await tester.pumpWidget(const AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle( value: SystemUiOverlayStyle(
systemNavigationBarColor: Colors.blue, systemNavigationBarColor: Colors.blue,
@ -156,7 +158,7 @@ void main() {
testWidgets( testWidgets(
'systemNavigationBarColor is set for annotated view', 'systemNavigationBarColor is set for annotated view',
(WidgetTester tester) async { (WidgetTester tester) async {
setupTestDevice(tester); setupTestDevice();
await tester.pumpWidget(const AnnotatedRegion<SystemUiOverlayStyle>( await tester.pumpWidget(const AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle( value: SystemUiOverlayStyle(
systemNavigationBarColor: Colors.blue, systemNavigationBarColor: Colors.blue,
@ -176,7 +178,7 @@ void main() {
testWidgets( testWidgets(
"systemNavigationBarColor isn't set when view covers less than half of navigation bar", "systemNavigationBarColor isn't set when view covers less than half of navigation bar",
(WidgetTester tester) async { (WidgetTester tester) async {
setupTestDevice(tester); setupTestDevice();
const double lessThanHalfOfTheNavigationBarHeight = const double lessThanHalfOfTheNavigationBarHeight =
navigationBarHeight / 2.0 - 1; navigationBarHeight / 2.0 - 1;
await tester.pumpWidget(const Align( await tester.pumpWidget(const Align(
@ -201,7 +203,7 @@ void main() {
testWidgets( testWidgets(
'systemNavigationBarColor is set when view covers more than half of navigation bar', 'systemNavigationBarColor is set when view covers more than half of navigation bar',
(WidgetTester tester) async { (WidgetTester tester) async {
setupTestDevice(tester); setupTestDevice();
const double moreThanHalfOfTheNavigationBarHeight = const double moreThanHalfOfTheNavigationBarHeight =
navigationBarHeight / 2.0 + 1; navigationBarHeight / 2.0 + 1;
await tester.pumpWidget(const Align( 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 { 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( await tester.pumpWidget(
const Column(children: <Widget>[ const Column(children: <Widget>[
Expanded(child: AnnotatedRegion<SystemUiOverlayStyle>( Expanded(child: AnnotatedRegion<SystemUiOverlayStyle>(
@ -254,7 +256,7 @@ void main() {
}, variant: TargetPlatformVariant.only(TargetPlatform.android)); }, variant: TargetPlatformVariant.only(TargetPlatform.android));
testWidgets('Top only AnnotatedRegion provides status bar and navigation bar style properties', (WidgetTester tester) async { testWidgets('Top only AnnotatedRegion provides status bar and navigation bar style properties', (WidgetTester tester) async {
setupTestDevice(tester); setupTestDevice();
await tester.pumpWidget( await tester.pumpWidget(
const Column(children: <Widget>[ const Column(children: <Widget>[
Expanded(child: AnnotatedRegion<SystemUiOverlayStyle>( Expanded(child: AnnotatedRegion<SystemUiOverlayStyle>(
@ -274,7 +276,7 @@ void main() {
}, variant: TargetPlatformVariant.only(TargetPlatform.android)); }, variant: TargetPlatformVariant.only(TargetPlatform.android));
testWidgets('Bottom only AnnotatedRegion provides status bar and navigation bar style properties', (WidgetTester tester) async { testWidgets('Bottom only AnnotatedRegion provides status bar and navigation bar style properties', (WidgetTester tester) async {
setupTestDevice(tester); setupTestDevice();
await tester.pumpWidget( await tester.pumpWidget(
const Column(children: <Widget>[ const Column(children: <Widget>[
Expanded(child: SizedBox.expand()), Expanded(child: SizedBox.expand()),
@ -294,3 +296,21 @@ void main() {
}, variant: TargetPlatformVariant.only(TargetPlatform.android)); }, 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;
}

View File

@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui' as ui;
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
@ -30,9 +32,10 @@ void main() {
}); });
test('does not replace the root layer unnecessarily', () { test('does not replace the root layer unnecessarily', () {
final ui.FlutterView window = TestWindow(window: RendererBinding.instance.window);
final RenderView view = RenderView( final RenderView view = RenderView(
configuration: createViewConfiguration(), configuration: createViewConfiguration(),
window: RendererBinding.instance.platformDispatcher.views.single, window: window,
); );
final PipelineOwner owner = PipelineOwner(); final PipelineOwner owner = PipelineOwner();
view.attach(owner); view.attach(owner);
@ -45,10 +48,11 @@ void main() {
expect(identical(view.debugLayer, firstLayer), false); 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( final RenderView view = RenderView(
configuration: createViewConfiguration(size: const Size(100.0, 100.0)), configuration: createViewConfiguration(size: const Size(100.0, 100.0)),
window: RendererBinding.instance.platformDispatcher.views.single, window: window,
); );
final PipelineOwner owner = PipelineOwner(); final PipelineOwner owner = PipelineOwner();
view.attach(owner); view.attach(owner);

View File

@ -10,6 +10,8 @@
@Tags(<String>['reduced-test-set']) @Tags(<String>['reduced-test-set'])
library; library;
import 'dart:ui' as ui;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
@ -780,14 +782,19 @@ void main() {
} }
testWidgets('Reverse List showOnScreen', (WidgetTester tester) async { 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 screenHeight = 400.0;
const double screenWidth = 400.0; const double screenWidth = 400.0;
const double itemHeight = screenHeight / 10.0; const double itemHeight = screenHeight / 10.0;
const ValueKey<String> centerKey = ValueKey<String>('center'); const ValueKey<String> centerKey = ValueKey<String>('center');
tester.view.devicePixelRatio = 1.0; tester.binding.window.devicePixelRatioTestValue = 1.0;
tester.view.physicalSize = const Size(screenWidth, screenHeight); tester.binding.window.physicalSizeTestValue = const Size(screenWidth, screenHeight);
await tester.pumpWidget(Directionality( await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,

View File

@ -29,13 +29,13 @@ void main() {
), ),
); );
int? result = RendererBinding.instance.renderView.debugLayer!.find<int>(Offset( int? result = RendererBinding.instance.renderView.debugLayer!.find<int>(Offset(
10.0 * tester.view.devicePixelRatio, 10.0 * RendererBinding.instance.window.devicePixelRatio,
10.0 * tester.view.devicePixelRatio, 10.0 * RendererBinding.instance.window.devicePixelRatio,
)); ));
expect(result, null); expect(result, null);
result = RendererBinding.instance.renderView.debugLayer!.find<int>(Offset( result = RendererBinding.instance.renderView.debugLayer!.find<int>(Offset(
50.0 * tester.view.devicePixelRatio, 50.0 * RendererBinding.instance.window.devicePixelRatio,
50.0 * tester.view.devicePixelRatio, 50.0 * RendererBinding.instance.window.devicePixelRatio,
)); ));
expect(result, 1); expect(result, 1);
}); });

View File

@ -13,7 +13,7 @@ import 'package:flutter_test/flutter_test.dart';
import '../rendering/mock_canvas.dart'; import '../rendering/mock_canvas.dart';
void main() { void main() {
group('Container control tests:', () { testWidgets('Container control test', (WidgetTester tester) async {
final Container container = Container( final Container container = Container(
alignment: Alignment.bottomRight, alignment: Alignment.bottomRight,
padding: const EdgeInsets.all(7.0), padding: const EdgeInsets.all(7.0),
@ -39,7 +39,8 @@ void main() {
), ),
); );
testWidgets('paints as expected', (WidgetTester tester) async { expect(container, hasOneLineDescription);
await tester.pumpWidget(Align( await tester.pumpWidget(Align(
alignment: Alignment.topLeft, alignment: Alignment.topLeft,
child: container, child: container,
@ -53,29 +54,8 @@ void main() {
..rect(rect: const Rect.fromLTWH(26.0, 43.0, 25.0, 33.0), color: const Color(0xFFFFFF00)) ..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)), ..rect(rect: const Rect.fromLTWH(5.0, 5.0, 53.0, 78.0), color: const Color(0x7F0000FF)),
); );
});
group('diagnostics', () {
testWidgets('has reasonable default diagnostics', (WidgetTester tester) async {
await tester.pumpWidget(Align(
alignment: Alignment.topLeft,
child: container,
));
final RenderBox box = tester.renderObject(find.byType(Container));
expect(container, hasOneLineDescription);
expect(box, hasAGoodToStringDeep); expect(box, hasAGoodToStringDeep);
});
testWidgets('has expected info diagnostics', (WidgetTester tester) async {
await tester.pumpWidget(Align(
alignment: Alignment.topLeft,
child: container,
));
final RenderBox box = tester.renderObject(find.byType(Container));
expect( expect(
box.toStringDeep(minLevel: DiagnosticLevel.info), box.toStringDeep(minLevel: DiagnosticLevel.info),
equalsIgnoringHashCodes( equalsIgnoringHashCodes(
@ -138,26 +118,14 @@ void main() {
' android)\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( expect(
// Using the redundant value to ensure the test is explicitly for box.toStringDeep(),
// debug diagnostics, regardless of any changes to the default value.
// ignore: avoid_redundant_argument_values
box.toStringDeep(minLevel: DiagnosticLevel.debug),
equalsIgnoringHashCodes( equalsIgnoringHashCodes(
'RenderPadding#00000 relayoutBoundary=up1\n' 'RenderPadding#00000 relayoutBoundary=up1\n'
' │ creator: Padding ← Container ← Align ← MediaQuery ←\n' ' │ creator: Padding ← Container ← Align ← MediaQuery ←\n'
' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\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' ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n'
' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n' ' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n'
' │ size: Size(63.0, 88.0)\n' ' │ size: Size(63.0, 88.0)\n'
@ -166,7 +134,7 @@ void main() {
' └─child: RenderConstrainedBox#00000 relayoutBoundary=up2\n' ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up2\n'
' │ creator: ConstrainedBox ← Padding ← Container ← Align ←\n' ' │ creator: ConstrainedBox ← Padding ← Container ← Align ←\n'
' │ MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' ' │ MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n'
' │ View-[GlobalObjectKey TestFlutterView#00000] ← [root]\n' ' │ View-[GlobalObjectKey TestWindow#00000] ← [root]\n'
' │ parentData: offset=Offset(5.0, 5.0) (can use size)\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' ' │ constraints: BoxConstraints(0.0<=w<=790.0, 0.0<=h<=590.0)\n'
' │ size: Size(53.0, 78.0)\n' ' │ size: Size(53.0, 78.0)\n'
@ -175,7 +143,7 @@ void main() {
' └─child: RenderDecoratedBox#00000\n' ' └─child: RenderDecoratedBox#00000\n'
' │ creator: DecoratedBox ← ConstrainedBox ← Padding ← Container ←\n' ' │ creator: DecoratedBox ← ConstrainedBox ← Padding ← Container ←\n'
' │ Align ← MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' ' │ Align ← MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n'
' │ View-[GlobalObjectKey TestFlutterView#00000] ← [root]\n' ' │ View-[GlobalObjectKey TestWindow#00000] ← [root]\n'
' │ parentData: <none> (can use size)\n' ' │ parentData: <none> (can use size)\n'
' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n'
' │ size: Size(53.0, 78.0)\n' ' │ size: Size(53.0, 78.0)\n'
@ -188,8 +156,7 @@ void main() {
' └─child: _RenderColoredBox#00000\n' ' └─child: _RenderColoredBox#00000\n'
' │ creator: ColoredBox ← DecoratedBox ← ConstrainedBox ← Padding ←\n' ' │ creator: ColoredBox ← DecoratedBox ← ConstrainedBox ← Padding ←\n'
' │ Container ← Align ← MediaQuery ← _MediaQueryFromView ←\n' ' │ Container ← Align ← MediaQuery ← _MediaQueryFromView ←\n'
' │ _ViewScope ← View-[GlobalObjectKey TestFlutterView#00000] ←\n' ' │ _ViewScope ← View-[GlobalObjectKey TestWindow#00000] ← [root]\n'
' │ [root]\n'
' │ parentData: <none> (can use size)\n' ' │ parentData: <none> (can use size)\n'
' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n'
' │ size: Size(53.0, 78.0)\n' ' │ size: Size(53.0, 78.0)\n'
@ -198,8 +165,7 @@ void main() {
' └─child: RenderPadding#00000\n' ' └─child: RenderPadding#00000\n'
' │ creator: Padding ← ColoredBox ← DecoratedBox ← ConstrainedBox ←\n' ' │ creator: Padding ← ColoredBox ← DecoratedBox ← ConstrainedBox ←\n'
' │ Padding ← Container ← Align ← MediaQuery ← _MediaQueryFromView\n' ' │ Padding ← Container ← Align ← MediaQuery ← _MediaQueryFromView\n'
' │ ← _ViewScope ← View-[GlobalObjectKey TestFlutterView#00000] ←\n' ' │ ← _ViewScope ← View-[GlobalObjectKey TestWindow#00000] ← [root]\n'
' │ [root]\n'
' │ parentData: <none> (can use size)\n' ' │ parentData: <none> (can use size)\n'
' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n'
' │ size: Size(53.0, 78.0)\n' ' │ size: Size(53.0, 78.0)\n'
@ -209,7 +175,7 @@ void main() {
' │ creator: Align ← Padding ← ColoredBox ← DecoratedBox ←\n' ' │ creator: Align ← Padding ← ColoredBox ← DecoratedBox ←\n'
' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n' ' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n'
' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n'
' │ TestFlutterView#00000] ← ⋯\n' ' │ TestWindow#00000] ← ⋯\n'
' │ parentData: offset=Offset(7.0, 7.0) (can use size)\n' ' │ parentData: offset=Offset(7.0, 7.0) (can use size)\n'
' │ constraints: BoxConstraints(w=39.0, h=64.0)\n' ' │ constraints: BoxConstraints(w=39.0, h=64.0)\n'
' │ size: Size(39.0, 64.0)\n' ' │ size: Size(39.0, 64.0)\n'
@ -240,15 +206,6 @@ void main() {
' android)\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( expect(
box.toStringDeep(minLevel: DiagnosticLevel.fine), box.toStringDeep(minLevel: DiagnosticLevel.fine),
@ -256,7 +213,7 @@ void main() {
'RenderPadding#00000 relayoutBoundary=up1\n' 'RenderPadding#00000 relayoutBoundary=up1\n'
' │ creator: Padding ← Container ← Align ← MediaQuery ←\n' ' │ creator: Padding ← Container ← Align ← MediaQuery ←\n'
' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\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' ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n'
' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n' ' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n'
' │ layer: null\n' ' │ layer: null\n'
@ -268,7 +225,7 @@ void main() {
' └─child: RenderConstrainedBox#00000 relayoutBoundary=up2\n' ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up2\n'
' │ creator: ConstrainedBox ← Padding ← Container ← Align ←\n' ' │ creator: ConstrainedBox ← Padding ← Container ← Align ←\n'
' │ MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' ' │ MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n'
' │ View-[GlobalObjectKey TestFlutterView#00000] ← [root]\n' ' │ View-[GlobalObjectKey TestWindow#00000] ← [root]\n'
' │ parentData: offset=Offset(5.0, 5.0) (can use size)\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' ' │ constraints: BoxConstraints(0.0<=w<=790.0, 0.0<=h<=590.0)\n'
' │ layer: null\n' ' │ layer: null\n'
@ -279,7 +236,7 @@ void main() {
' └─child: RenderDecoratedBox#00000\n' ' └─child: RenderDecoratedBox#00000\n'
' │ creator: DecoratedBox ← ConstrainedBox ← Padding ← Container ←\n' ' │ creator: DecoratedBox ← ConstrainedBox ← Padding ← Container ←\n'
' │ Align ← MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' ' │ Align ← MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n'
' │ View-[GlobalObjectKey TestFlutterView#00000] ← [root]\n' ' │ View-[GlobalObjectKey TestWindow#00000] ← [root]\n'
' │ parentData: <none> (can use size)\n' ' │ parentData: <none> (can use size)\n'
' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n'
' │ layer: null\n' ' │ layer: null\n'
@ -300,8 +257,7 @@ void main() {
' └─child: _RenderColoredBox#00000\n' ' └─child: _RenderColoredBox#00000\n'
' │ creator: ColoredBox ← DecoratedBox ← ConstrainedBox ← Padding ←\n' ' │ creator: ColoredBox ← DecoratedBox ← ConstrainedBox ← Padding ←\n'
' │ Container ← Align ← MediaQuery ← _MediaQueryFromView ←\n' ' │ Container ← Align ← MediaQuery ← _MediaQueryFromView ←\n'
' │ _ViewScope ← View-[GlobalObjectKey TestFlutterView#00000] ←\n' ' │ _ViewScope ← View-[GlobalObjectKey TestWindow#00000] ← [root]\n'
' │ [root]\n'
' │ parentData: <none> (can use size)\n' ' │ parentData: <none> (can use size)\n'
' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n'
' │ layer: null\n' ' │ layer: null\n'
@ -312,8 +268,7 @@ void main() {
' └─child: RenderPadding#00000\n' ' └─child: RenderPadding#00000\n'
' │ creator: Padding ← ColoredBox ← DecoratedBox ← ConstrainedBox ←\n' ' │ creator: Padding ← ColoredBox ← DecoratedBox ← ConstrainedBox ←\n'
' │ Padding ← Container ← Align ← MediaQuery ← _MediaQueryFromView\n' ' │ Padding ← Container ← Align ← MediaQuery ← _MediaQueryFromView\n'
' │ ← _ViewScope ← View-[GlobalObjectKey TestFlutterView#00000] ←\n' ' │ ← _ViewScope ← View-[GlobalObjectKey TestWindow#00000] ← [root]\n'
' │ [root]\n'
' │ parentData: <none> (can use size)\n' ' │ parentData: <none> (can use size)\n'
' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n'
' │ layer: null\n' ' │ layer: null\n'
@ -326,7 +281,7 @@ void main() {
' │ creator: Align ← Padding ← ColoredBox ← DecoratedBox ←\n' ' │ creator: Align ← Padding ← ColoredBox ← DecoratedBox ←\n'
' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n' ' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n'
' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n'
' │ TestFlutterView#00000] ← ⋯\n' ' │ TestWindow#00000] ← ⋯\n'
' │ parentData: offset=Offset(7.0, 7.0) (can use size)\n' ' │ parentData: offset=Offset(7.0, 7.0) (can use size)\n'
' │ constraints: BoxConstraints(w=39.0, h=64.0)\n' ' │ constraints: BoxConstraints(w=39.0, h=64.0)\n'
' │ layer: null\n' ' │ layer: null\n'
@ -370,15 +325,6 @@ void main() {
' android)\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( expect(
box.toStringDeep(minLevel: DiagnosticLevel.hidden), box.toStringDeep(minLevel: DiagnosticLevel.hidden),
@ -387,7 +333,7 @@ void main() {
' │ needsCompositing: false\n' ' │ needsCompositing: false\n'
' │ creator: Padding ← Container ← Align ← MediaQuery ←\n' ' │ creator: Padding ← Container ← Align ← MediaQuery ←\n'
' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\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' ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n'
' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n' ' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n'
' │ layer: null\n' ' │ layer: null\n'
@ -402,7 +348,7 @@ void main() {
' │ needsCompositing: false\n' ' │ needsCompositing: false\n'
' │ creator: ConstrainedBox ← Padding ← Container ← Align ←\n' ' │ creator: ConstrainedBox ← Padding ← Container ← Align ←\n'
' │ MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' ' │ MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n'
' │ View-[GlobalObjectKey TestFlutterView#00000] ← [root]\n' ' │ View-[GlobalObjectKey TestWindow#00000] ← [root]\n'
' │ parentData: offset=Offset(5.0, 5.0) (can use size)\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' ' │ constraints: BoxConstraints(0.0<=w<=790.0, 0.0<=h<=590.0)\n'
' │ layer: null\n' ' │ layer: null\n'
@ -416,7 +362,7 @@ void main() {
' │ needsCompositing: false\n' ' │ needsCompositing: false\n'
' │ creator: DecoratedBox ← ConstrainedBox ← Padding ← Container ←\n' ' │ creator: DecoratedBox ← ConstrainedBox ← Padding ← Container ←\n'
' │ Align ← MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' ' │ Align ← MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n'
' │ View-[GlobalObjectKey TestFlutterView#00000] ← [root]\n' ' │ View-[GlobalObjectKey TestWindow#00000] ← [root]\n'
' │ parentData: <none> (can use size)\n' ' │ parentData: <none> (can use size)\n'
' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n'
' │ layer: null\n' ' │ layer: null\n'
@ -440,8 +386,7 @@ void main() {
' │ needsCompositing: false\n' ' │ needsCompositing: false\n'
' │ creator: ColoredBox ← DecoratedBox ← ConstrainedBox ← Padding ←\n' ' │ creator: ColoredBox ← DecoratedBox ← ConstrainedBox ← Padding ←\n'
' │ Container ← Align ← MediaQuery ← _MediaQueryFromView ←\n' ' │ Container ← Align ← MediaQuery ← _MediaQueryFromView ←\n'
' │ _ViewScope ← View-[GlobalObjectKey TestFlutterView#00000] ←\n' ' │ _ViewScope ← View-[GlobalObjectKey TestWindow#00000] ← [root]\n'
' │ [root]\n'
' │ parentData: <none> (can use size)\n' ' │ parentData: <none> (can use size)\n'
' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n'
' │ layer: null\n' ' │ layer: null\n'
@ -455,8 +400,7 @@ void main() {
' │ needsCompositing: false\n' ' │ needsCompositing: false\n'
' │ creator: Padding ← ColoredBox ← DecoratedBox ← ConstrainedBox ←\n' ' │ creator: Padding ← ColoredBox ← DecoratedBox ← ConstrainedBox ←\n'
' │ Padding ← Container ← Align ← MediaQuery ← _MediaQueryFromView\n' ' │ Padding ← Container ← Align ← MediaQuery ← _MediaQueryFromView\n'
' │ ← _ViewScope ← View-[GlobalObjectKey TestFlutterView#00000] ←\n' ' │ ← _ViewScope ← View-[GlobalObjectKey TestWindow#00000] ← [root]\n'
' │ [root]\n'
' │ parentData: <none> (can use size)\n' ' │ parentData: <none> (can use size)\n'
' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n'
' │ layer: null\n' ' │ layer: null\n'
@ -472,7 +416,7 @@ void main() {
' │ creator: Align ← Padding ← ColoredBox ← DecoratedBox ←\n' ' │ creator: Align ← Padding ← ColoredBox ← DecoratedBox ←\n'
' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n' ' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n'
' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n'
' │ TestFlutterView#00000] ← ⋯\n' ' │ TestWindow#00000] ← ⋯\n'
' │ parentData: offset=Offset(7.0, 7.0) (can use size)\n' ' │ parentData: offset=Offset(7.0, 7.0) (can use size)\n'
' │ constraints: BoxConstraints(w=39.0, h=64.0)\n' ' │ constraints: BoxConstraints(w=39.0, h=64.0)\n'
' │ layer: null\n' ' │ layer: null\n'
@ -524,13 +468,6 @@ void main() {
' android)\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 RenderBox decoratedBox = tester.renderObject(find.byType(DecoratedBox).last);
final PaintingContext context = _MockPaintingContext(); final PaintingContext context = _MockPaintingContext();
@ -554,8 +491,6 @@ void main() {
' BoxPainter for BoxDecoration(color: Color(0xffffff00))\n', ' BoxPainter for BoxDecoration(color: Color(0xffffff00))\n',
); );
}); });
});
});
testWidgets('Can be placed in an infinite box', (WidgetTester tester) async { testWidgets('Can be placed in an infinite box', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(

View File

@ -374,7 +374,7 @@ void main() {
' creator: ConstrainedBox ← Container ← LayoutWithMissingId ←\n' ' creator: ConstrainedBox ← Container ← LayoutWithMissingId ←\n'
' CustomMultiChildLayout ← Center ← MediaQuery ←\n' ' CustomMultiChildLayout ← Center ← MediaQuery ←\n'
' _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' ' _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n'
' TestFlutterView#00000] ← [root]\n' ' TestWindow#00000] ← [root]\n'
' parentData: offset=Offset(0.0, 0.0); id=null\n' ' parentData: offset=Offset(0.0, 0.0); id=null\n'
' constraints: MISSING\n' ' constraints: MISSING\n'
' size: MISSING\n' ' size: MISSING\n'

View File

@ -11,7 +11,7 @@ void main() {
group('DisplayFeatureSubScreen', () { group('DisplayFeatureSubScreen', () {
testWidgets('without Directionality or anchor', (WidgetTester tester) async { testWidgets('without Directionality or anchor', (WidgetTester tester) async {
const Key childKey = Key('childKey'); const Key childKey = Key('childKey');
final MediaQueryData mediaQuery = MediaQueryData.fromView(tester.view).copyWith( final MediaQueryData mediaQuery = MediaQueryData.fromView(WidgetsBinding.instance.window).copyWith(
displayFeatures: <DisplayFeature>[ displayFeatures: <DisplayFeature>[
const DisplayFeature( const DisplayFeature(
bounds: Rect.fromLTRB(390, 0, 410, 600), bounds: Rect.fromLTRB(390, 0, 410, 600),
@ -39,7 +39,7 @@ void main() {
testWidgets('with anchorPoint', (WidgetTester tester) async { testWidgets('with anchorPoint', (WidgetTester tester) async {
const Key childKey = Key('childKey'); const Key childKey = Key('childKey');
final MediaQueryData mediaQuery = MediaQueryData.fromView(tester.view).copyWith( final MediaQueryData mediaQuery = MediaQueryData.fromView(WidgetsBinding.instance.window).copyWith(
displayFeatures: <DisplayFeature>[ displayFeatures: <DisplayFeature>[
const DisplayFeature( const DisplayFeature(
bounds: Rect.fromLTRB(390, 0, 410, 600), bounds: Rect.fromLTRB(390, 0, 410, 600),
@ -70,7 +70,7 @@ void main() {
testWidgets('with infinity anchorpoint', (WidgetTester tester) async { testWidgets('with infinity anchorpoint', (WidgetTester tester) async {
const Key childKey = Key('childKey'); const Key childKey = Key('childKey');
final MediaQueryData mediaQuery = MediaQueryData.fromView(tester.view).copyWith( final MediaQueryData mediaQuery = MediaQueryData.fromView(WidgetsBinding.instance.window).copyWith(
displayFeatures: <DisplayFeature>[ displayFeatures: <DisplayFeature>[
const DisplayFeature( const DisplayFeature(
bounds: Rect.fromLTRB(390, 0, 410, 600), bounds: Rect.fromLTRB(390, 0, 410, 600),
@ -101,7 +101,7 @@ void main() {
testWidgets('with horizontal hinge and anchorPoint', (WidgetTester tester) async { testWidgets('with horizontal hinge and anchorPoint', (WidgetTester tester) async {
const Key childKey = Key('childKey'); const Key childKey = Key('childKey');
final MediaQueryData mediaQuery = MediaQueryData.fromView(tester.view).copyWith( final MediaQueryData mediaQuery = MediaQueryData.fromView(WidgetsBinding.instance.window).copyWith(
displayFeatures: <DisplayFeature>[ displayFeatures: <DisplayFeature>[
const DisplayFeature( const DisplayFeature(
bounds: Rect.fromLTRB(0, 290, 800, 310), bounds: Rect.fromLTRB(0, 290, 800, 310),
@ -131,7 +131,7 @@ void main() {
testWidgets('with multiple display features and anchorPoint', (WidgetTester tester) async { testWidgets('with multiple display features and anchorPoint', (WidgetTester tester) async {
const Key childKey = Key('childKey'); const Key childKey = Key('childKey');
final MediaQueryData mediaQuery = MediaQueryData.fromView(tester.view).copyWith( final MediaQueryData mediaQuery = MediaQueryData.fromView(WidgetsBinding.instance.window).copyWith(
displayFeatures: <DisplayFeature>[ displayFeatures: <DisplayFeature>[
const DisplayFeature( const DisplayFeature(
bounds: Rect.fromLTRB(0, 290, 800, 310), bounds: Rect.fromLTRB(0, 290, 800, 310),
@ -166,7 +166,7 @@ void main() {
testWidgets('with non-splitting display features and anchorPoint', (WidgetTester tester) async { testWidgets('with non-splitting display features and anchorPoint', (WidgetTester tester) async {
const Key childKey = Key('childKey'); const Key childKey = Key('childKey');
final MediaQueryData mediaQuery = MediaQueryData.fromView(tester.view).copyWith( final MediaQueryData mediaQuery = MediaQueryData.fromView(WidgetsBinding.instance.window).copyWith(
displayFeatures: <DisplayFeature>[ displayFeatures: <DisplayFeature>[
// Top notch // Top notch
const DisplayFeature( const DisplayFeature(
@ -211,7 +211,7 @@ void main() {
testWidgets('with size 0 display feature in half-opened posture and anchorPoint', (WidgetTester tester) async { testWidgets('with size 0 display feature in half-opened posture and anchorPoint', (WidgetTester tester) async {
const Key childKey = Key('childKey'); const Key childKey = Key('childKey');
final MediaQueryData mediaQuery = MediaQueryData.fromView(tester.view).copyWith( final MediaQueryData mediaQuery = MediaQueryData.fromView(WidgetsBinding.instance.window).copyWith(
displayFeatures: <DisplayFeature>[ displayFeatures: <DisplayFeature>[
const DisplayFeature( const DisplayFeature(
bounds: Rect.fromLTRB(0, 300, 800, 300), bounds: Rect.fromLTRB(0, 300, 800, 300),

View File

@ -1230,7 +1230,7 @@ void main() {
' │ primaryFocus: FocusNode#00000(Child 4 [PRIMARY FOCUS])\n' ' │ primaryFocus: FocusNode#00000(Child 4 [PRIMARY FOCUS])\n'
' │ primaryFocusCreator: Container-[GlobalKey#00000] ← MediaQuery ←\n' ' │ primaryFocusCreator: Container-[GlobalKey#00000] ← MediaQuery ←\n'
' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n'
' │ TestFlutterView#00000] ← [root]\n' ' │ TestWindow#00000] ← [root]\n'
'\n' '\n'
' └─rootScope: FocusScopeNode#00000(Root Focus Scope [IN FOCUS PATH])\n' ' └─rootScope: FocusScopeNode#00000(Root Focus Scope [IN FOCUS PATH])\n'
' │ IN FOCUS PATH\n' ' │ IN FOCUS PATH\n'

View File

@ -2,16 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui' show FlutterView;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
const Size _kTestViewSize = Size(800.0, 600.0); const Size _kTestViewSize = Size(800.0, 600.0);
class ScheduledFrameTrackingPlatformDispatcher extends TestPlatformDispatcher { class ScheduledFrameTrackingWindow extends TestWindow {
ScheduledFrameTrackingPlatformDispatcher({ required super.platformDispatcher }); ScheduledFrameTrackingWindow({ required super.window });
int _scheduledFrameCount = 0; int _scheduledFrameCount = 0;
int get scheduledFrameCount => _scheduledFrameCount; int get scheduledFrameCount => _scheduledFrameCount;
@ -28,16 +26,16 @@ class ScheduledFrameTrackingPlatformDispatcher extends TestPlatformDispatcher {
} }
class ScheduledFrameTrackingBindings extends AutomatedTestWidgetsFlutterBinding { class ScheduledFrameTrackingBindings extends AutomatedTestWidgetsFlutterBinding {
late final ScheduledFrameTrackingPlatformDispatcher _platformDispatcher = ScheduledFrameTrackingPlatformDispatcher(platformDispatcher: super.platformDispatcher); late final ScheduledFrameTrackingWindow _window = ScheduledFrameTrackingWindow(window: super.window);
@override @override
ScheduledFrameTrackingPlatformDispatcher get platformDispatcher => _platformDispatcher; ScheduledFrameTrackingWindow get window => _window;
} }
class OffscreenRenderView extends RenderView { class OffscreenRenderView extends RenderView {
OffscreenRenderView({required FlutterView view}) : super( OffscreenRenderView() : super(
configuration: const ViewConfiguration(size: _kTestViewSize), configuration: const ViewConfiguration(size: _kTestViewSize),
window: view, window: WidgetsBinding.instance.window,
); );
@override @override
@ -47,14 +45,13 @@ class OffscreenRenderView extends RenderView {
} }
class OffscreenWidgetTree { class OffscreenWidgetTree {
OffscreenWidgetTree(this.view) { OffscreenWidgetTree() {
renderView.attach(pipelineOwner); renderView.attach(pipelineOwner);
renderView.prepareInitialFrame(); renderView.prepareInitialFrame();
pipelineOwner.requestVisualUpdate(); pipelineOwner.requestVisualUpdate();
} }
final FlutterView view; final RenderView renderView = OffscreenRenderView();
late final RenderView renderView = OffscreenRenderView(view: view);
final BuildOwner buildOwner = BuildOwner(focusManager: FocusManager()); final BuildOwner buildOwner = BuildOwner(focusManager: FocusManager());
final PipelineOwner pipelineOwner = PipelineOwner(); final PipelineOwner pipelineOwner = PipelineOwner();
RenderObjectToWidgetElement<RenderBox>? root; RenderObjectToWidgetElement<RenderBox>? root;
@ -171,12 +168,12 @@ void main() {
testWidgets('RenderObjectToWidgetAdapter.attachToRenderTree does not schedule frame', (WidgetTester tester) async { testWidgets('RenderObjectToWidgetAdapter.attachToRenderTree does not schedule frame', (WidgetTester tester) async {
expect(WidgetsBinding.instance, isA<ScheduledFrameTrackingBindings>()); expect(WidgetsBinding.instance, isA<ScheduledFrameTrackingBindings>());
final ScheduledFrameTrackingPlatformDispatcher platformDispatcher = tester.platformDispatcher as ScheduledFrameTrackingPlatformDispatcher; final ScheduledFrameTrackingWindow window = WidgetsBinding.instance.window as ScheduledFrameTrackingWindow;
platformDispatcher.resetScheduledFrameCount(); window.resetScheduledFrameCount();
expect(platformDispatcher.scheduledFrameCount, isZero); expect(window.scheduledFrameCount, isZero);
final OffscreenWidgetTree tree = OffscreenWidgetTree(tester.view); final OffscreenWidgetTree tree = OffscreenWidgetTree();
tree.pumpWidget(const SizedBox.shrink()); tree.pumpWidget(const SizedBox.shrink());
expect(platformDispatcher.scheduledFrameCount, isZero); expect(window.scheduledFrameCount, isZero);
}); });
testWidgets('no crosstalk between widget build owners', (WidgetTester tester) async { testWidgets('no crosstalk between widget build owners', (WidgetTester tester) async {
@ -184,7 +181,7 @@ void main() {
final Counter counter1 = Counter(); final Counter counter1 = Counter();
final Trigger trigger2 = Trigger(); final Trigger trigger2 = Trigger();
final Counter counter2 = Counter(); final Counter counter2 = Counter();
final OffscreenWidgetTree tree = OffscreenWidgetTree(tester.view); final OffscreenWidgetTree tree = OffscreenWidgetTree();
// Both counts should start at zero // Both counts should start at zero
expect(counter1.count, equals(0)); expect(counter1.count, equals(0));
expect(counter2.count, equals(0)); expect(counter2.count, equals(0));
@ -230,7 +227,7 @@ void main() {
}); });
testWidgets('no crosstalk between focus nodes', (WidgetTester tester) async { 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 onscreenFocus = FocusNode();
final FocusNode offscreenFocus = FocusNode(); final FocusNode offscreenFocus = FocusNode();
await tester.pumpWidget( await tester.pumpWidget(
@ -253,7 +250,7 @@ void main() {
}); });
testWidgets('able to tear down offscreen tree', (WidgetTester tester) async { testWidgets('able to tear down offscreen tree', (WidgetTester tester) async {
final OffscreenWidgetTree tree = OffscreenWidgetTree(tester.view); final OffscreenWidgetTree tree = OffscreenWidgetTree();
final List<WidgetState> states = <WidgetState>[]; final List<WidgetState> states = <WidgetState>[];
tree.pumpWidget(SizedBox(child: TestStates(states: states))); tree.pumpWidget(SizedBox(child: TestStates(states: states)));
expect(states, <WidgetState>[WidgetState.initialized]); expect(states, <WidgetState>[WidgetState.initialized]);

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // 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/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -146,10 +146,10 @@ void main() {
}); });
testWidgets('MediaQueryData.fromView is sane', (WidgetTester tester) async { 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, hasOneLineDescription);
expect(data.hashCode, equals(data.copyWith().hashCode)); 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.accessibleNavigation, false);
expect(data.invertColors, false); expect(data.invertColors, false);
expect(data.disableAnimations, false); expect(data.disableAnimations, false);
@ -173,17 +173,26 @@ void main() {
navigationMode: NavigationMode.directional, 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, hasOneLineDescription);
expect(data.hashCode, data.copyWith().hashCode); expect(data.hashCode, data.copyWith().hashCode);
expect(data.size, tester.view.physicalSize / tester.view.devicePixelRatio); expect(data.size, view.physicalSize / view.devicePixelRatio);
expect(data.devicePixelRatio, tester.view.devicePixelRatio); expect(data.devicePixelRatio, view.devicePixelRatio);
expect(data.textScaleFactor, platformData.textScaleFactor); expect(data.textScaleFactor, platformData.textScaleFactor);
expect(data.platformBrightness, platformData.platformBrightness); expect(data.platformBrightness, platformData.platformBrightness);
expect(data.padding, EdgeInsets.fromViewPadding(tester.view.padding, tester.view.devicePixelRatio)); expect(data.padding, EdgeInsets.fromViewPadding(view.padding, view.devicePixelRatio));
expect(data.viewPadding, EdgeInsets.fromViewPadding(tester.view.viewPadding, tester.view.devicePixelRatio)); expect(data.viewPadding, EdgeInsets.fromViewPadding(view.viewPadding, view.devicePixelRatio));
expect(data.viewInsets, EdgeInsets.fromViewPadding(tester.view.viewInsets, tester.view.devicePixelRatio)); expect(data.viewInsets, EdgeInsets.fromViewPadding(view.viewInsets, view.devicePixelRatio));
expect(data.systemGestureInsets, EdgeInsets.fromViewPadding(tester.view.systemGestureInsets, tester.view.devicePixelRatio)); expect(data.systemGestureInsets, EdgeInsets.fromViewPadding(view.systemGestureInsets, view.devicePixelRatio));
expect(data.accessibleNavigation, platformData.accessibleNavigation); expect(data.accessibleNavigation, platformData.accessibleNavigation);
expect(data.invertColors, platformData.invertColors); expect(data.invertColors, platformData.invertColors);
expect(data.disableAnimations, platformData.disableAnimations); expect(data.disableAnimations, platformData.disableAnimations);
@ -191,37 +200,48 @@ void main() {
expect(data.highContrast, platformData.highContrast); expect(data.highContrast, platformData.highContrast);
expect(data.alwaysUse24HourFormat, platformData.alwaysUse24HourFormat); expect(data.alwaysUse24HourFormat, platformData.alwaysUse24HourFormat);
expect(data.navigationMode, platformData.navigationMode); expect(data.navigationMode, platformData.navigationMode);
expect(data.gestureSettings, DeviceGestureSettings.fromView(tester.view)); expect(data.gestureSettings, DeviceGestureSettings.fromView(view));
expect(data.displayFeatures, tester.view.displayFeatures); expect(data.displayFeatures, view.displayFeatures);
}); });
testWidgets('MediaQueryData.fromView uses data from platformDispatcher if no platformData is provided', (WidgetTester tester) async { 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 ..textScaleFactorTestValue = 123
..platformBrightnessTestValue = Brightness.dark ..platformBrightnessTestValue = Brightness.dark
..accessibilityFeaturesTestValue = FakeAccessibilityFeatures.allOn; ..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, hasOneLineDescription);
expect(data.hashCode, data.copyWith().hashCode); expect(data.hashCode, data.copyWith().hashCode);
expect(data.size, tester.view.physicalSize / tester.view.devicePixelRatio); expect(data.size, view.physicalSize / view.devicePixelRatio);
expect(data.devicePixelRatio, tester.view.devicePixelRatio); expect(data.devicePixelRatio, view.devicePixelRatio);
expect(data.textScaleFactor, tester.platformDispatcher.textScaleFactor); expect(data.textScaleFactor, platformDispatcher.textScaleFactor);
expect(data.platformBrightness, tester.platformDispatcher.platformBrightness); expect(data.platformBrightness, platformDispatcher.platformBrightness);
expect(data.padding, EdgeInsets.fromViewPadding(tester.view.padding, tester.view.devicePixelRatio)); expect(data.padding, EdgeInsets.fromViewPadding(view.padding, view.devicePixelRatio));
expect(data.viewPadding, EdgeInsets.fromViewPadding(tester.view.viewPadding, tester.view.devicePixelRatio)); expect(data.viewPadding, EdgeInsets.fromViewPadding(view.viewPadding, view.devicePixelRatio));
expect(data.viewInsets, EdgeInsets.fromViewPadding(tester.view.viewInsets, tester.view.devicePixelRatio)); expect(data.viewInsets, EdgeInsets.fromViewPadding(view.viewInsets, view.devicePixelRatio));
expect(data.systemGestureInsets, EdgeInsets.fromViewPadding(tester.view.systemGestureInsets, tester.view.devicePixelRatio)); expect(data.systemGestureInsets, EdgeInsets.fromViewPadding(view.systemGestureInsets, view.devicePixelRatio));
expect(data.accessibleNavigation, tester.platformDispatcher.accessibilityFeatures.accessibleNavigation); expect(data.accessibleNavigation, platformDispatcher.accessibilityFeatures.accessibleNavigation);
expect(data.invertColors, tester.platformDispatcher.accessibilityFeatures.invertColors); expect(data.invertColors, platformDispatcher.accessibilityFeatures.invertColors);
expect(data.disableAnimations, tester.platformDispatcher.accessibilityFeatures.disableAnimations); expect(data.disableAnimations, platformDispatcher.accessibilityFeatures.disableAnimations);
expect(data.boldText, tester.platformDispatcher.accessibilityFeatures.boldText); expect(data.boldText, platformDispatcher.accessibilityFeatures.boldText);
expect(data.highContrast, tester.platformDispatcher.accessibilityFeatures.highContrast); expect(data.highContrast, platformDispatcher.accessibilityFeatures.highContrast);
expect(data.alwaysUse24HourFormat, tester.platformDispatcher.alwaysUse24HourFormat); expect(data.alwaysUse24HourFormat, platformDispatcher.alwaysUse24HourFormat);
expect(data.navigationMode, NavigationMode.traditional); expect(data.navigationMode, NavigationMode.traditional);
expect(data.gestureSettings, DeviceGestureSettings.fromView(tester.view)); expect(data.gestureSettings, DeviceGestureSettings.fromView(view));
expect(data.displayFeatures, tester.view.displayFeatures); expect(data.displayFeatures, view.displayFeatures);
}); });
testWidgets('MediaQuery.fromView injects a new MediaQuery with data from view, preserving platform-specific data', (WidgetTester tester) async { 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, 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; late MediaQueryData data;
await tester.pumpWidget(MediaQuery( await tester.pumpWidget(MediaQuery(
data: platformData, data: platformData,
child: MediaQuery.fromView( child: MediaQuery.fromView(
view: tester.view, view: view,
child: Builder( child: Builder(
builder: (BuildContext context) { builder: (BuildContext context) {
data = MediaQuery.of(context); data = MediaQuery.of(context);
@ -252,14 +281,14 @@ void main() {
)); ));
expect(data, isNot(platformData)); expect(data, isNot(platformData));
expect(data.size, tester.view.physicalSize / tester.view.devicePixelRatio); expect(data.size, view.physicalSize / view.devicePixelRatio);
expect(data.devicePixelRatio, tester.view.devicePixelRatio); expect(data.devicePixelRatio, view.devicePixelRatio);
expect(data.textScaleFactor, platformData.textScaleFactor); expect(data.textScaleFactor, platformData.textScaleFactor);
expect(data.platformBrightness, platformData.platformBrightness); expect(data.platformBrightness, platformData.platformBrightness);
expect(data.padding, EdgeInsets.fromViewPadding(tester.view.padding, tester.view.devicePixelRatio)); expect(data.padding, EdgeInsets.fromViewPadding(view.padding, view.devicePixelRatio));
expect(data.viewPadding, EdgeInsets.fromViewPadding(tester.view.viewPadding, tester.view.devicePixelRatio)); expect(data.viewPadding, EdgeInsets.fromViewPadding(view.viewPadding, view.devicePixelRatio));
expect(data.viewInsets, EdgeInsets.fromViewPadding(tester.view.viewInsets, tester.view.devicePixelRatio)); expect(data.viewInsets, EdgeInsets.fromViewPadding(view.viewInsets, view.devicePixelRatio));
expect(data.systemGestureInsets, EdgeInsets.fromViewPadding(tester.view.systemGestureInsets, tester.view.devicePixelRatio)); expect(data.systemGestureInsets, EdgeInsets.fromViewPadding(view.systemGestureInsets, view.devicePixelRatio));
expect(data.accessibleNavigation, platformData.accessibleNavigation); expect(data.accessibleNavigation, platformData.accessibleNavigation);
expect(data.invertColors, platformData.invertColors); expect(data.invertColors, platformData.invertColors);
expect(data.disableAnimations, platformData.disableAnimations); expect(data.disableAnimations, platformData.disableAnimations);
@ -267,16 +296,27 @@ void main() {
expect(data.highContrast, platformData.highContrast); expect(data.highContrast, platformData.highContrast);
expect(data.alwaysUse24HourFormat, platformData.alwaysUse24HourFormat); expect(data.alwaysUse24HourFormat, platformData.alwaysUse24HourFormat);
expect(data.navigationMode, platformData.navigationMode); expect(data.navigationMode, platformData.navigationMode);
expect(data.gestureSettings, DeviceGestureSettings.fromView(tester.view)); expect(data.gestureSettings, DeviceGestureSettings.fromView(view));
expect(data.displayFeatures, tester.view.displayFeatures); expect(data.displayFeatures, view.displayFeatures);
}); });
testWidgets('MediaQuery.fromView injects a new MediaQuery with data from view when no surrounding MediaQuery exists', (WidgetTester tester) async { 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 ..textScaleFactorTestValue = 123
..platformBrightnessTestValue = Brightness.dark ..platformBrightnessTestValue = Brightness.dark
..accessibilityFeaturesTestValue = FakeAccessibilityFeatures.allOn; ..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; late MediaQueryData data;
MediaQueryData? outerData; MediaQueryData? outerData;
@ -286,7 +326,7 @@ void main() {
builder: (BuildContext context) { builder: (BuildContext context) {
outerData = MediaQuery.maybeOf(context); outerData = MediaQuery.maybeOf(context);
return MediaQuery.fromView( return MediaQuery.fromView(
view: tester.view, view: view,
child: Builder( child: Builder(
builder: (BuildContext context) { builder: (BuildContext context) {
data = MediaQuery.of(context); data = MediaQuery.of(context);
@ -299,34 +339,33 @@ void main() {
); );
expect(outerData, isNull); expect(outerData, isNull);
expect(data.size, tester.view.physicalSize / tester.view.devicePixelRatio); expect(data.size, view.physicalSize / view.devicePixelRatio);
expect(data.devicePixelRatio, tester.view.devicePixelRatio); expect(data.devicePixelRatio, view.devicePixelRatio);
expect(data.textScaleFactor, tester.platformDispatcher.textScaleFactor); expect(data.textScaleFactor, platformDispatcher.textScaleFactor);
expect(data.platformBrightness, tester.platformDispatcher.platformBrightness); expect(data.platformBrightness, platformDispatcher.platformBrightness);
expect(data.padding, EdgeInsets.fromViewPadding(tester.view.padding, tester.view.devicePixelRatio)); expect(data.padding, EdgeInsets.fromViewPadding(view.padding, view.devicePixelRatio));
expect(data.viewPadding, EdgeInsets.fromViewPadding(tester.view.viewPadding, tester.view.devicePixelRatio)); expect(data.viewPadding, EdgeInsets.fromViewPadding(view.viewPadding, view.devicePixelRatio));
expect(data.viewInsets, EdgeInsets.fromViewPadding(tester.view.viewInsets, tester.view.devicePixelRatio)); expect(data.viewInsets, EdgeInsets.fromViewPadding(view.viewInsets, view.devicePixelRatio));
expect(data.systemGestureInsets, EdgeInsets.fromViewPadding(tester.view.systemGestureInsets, tester.view.devicePixelRatio)); expect(data.systemGestureInsets, EdgeInsets.fromViewPadding(view.systemGestureInsets, view.devicePixelRatio));
expect(data.accessibleNavigation, tester.platformDispatcher.accessibilityFeatures.accessibleNavigation); expect(data.accessibleNavigation, platformDispatcher.accessibilityFeatures.accessibleNavigation);
expect(data.invertColors, tester.platformDispatcher.accessibilityFeatures.invertColors); expect(data.invertColors, platformDispatcher.accessibilityFeatures.invertColors);
expect(data.disableAnimations, tester.platformDispatcher.accessibilityFeatures.disableAnimations); expect(data.disableAnimations, platformDispatcher.accessibilityFeatures.disableAnimations);
expect(data.boldText, tester.platformDispatcher.accessibilityFeatures.boldText); expect(data.boldText, platformDispatcher.accessibilityFeatures.boldText);
expect(data.highContrast, tester.platformDispatcher.accessibilityFeatures.highContrast); expect(data.highContrast, platformDispatcher.accessibilityFeatures.highContrast);
expect(data.alwaysUse24HourFormat, tester.platformDispatcher.alwaysUse24HourFormat); expect(data.alwaysUse24HourFormat, platformDispatcher.alwaysUse24HourFormat);
expect(data.navigationMode, NavigationMode.traditional); expect(data.navigationMode, NavigationMode.traditional);
expect(data.gestureSettings, DeviceGestureSettings.fromView(tester.view)); expect(data.gestureSettings, DeviceGestureSettings.fromView(view));
expect(data.displayFeatures, tester.view.displayFeatures); expect(data.displayFeatures, view.displayFeatures);
}); });
testWidgets('MediaQuery.fromView updates on notifications (no parent data)', (WidgetTester tester) async { testWidgets('MediaQuery.fromView updates on notifications (no parent data)', (WidgetTester tester) async {
addTearDown(() => tester.platformDispatcher.clearAllTestValues()); tester.binding.platformDispatcher
addTearDown(() => tester.view.reset());
tester.platformDispatcher
..textScaleFactorTestValue = 123 ..textScaleFactorTestValue = 123
..platformBrightnessTestValue = Brightness.dark ..platformBrightnessTestValue = Brightness.dark
..accessibilityFeaturesTestValue = FakeAccessibilityFeatures.allOn; ..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; late MediaQueryData data;
MediaQueryData? outerData; MediaQueryData? outerData;
@ -337,7 +376,7 @@ void main() {
builder: (BuildContext context) { builder: (BuildContext context) {
outerData = MediaQuery.maybeOf(context); outerData = MediaQuery.maybeOf(context);
return MediaQuery.fromView( return MediaQuery.fromView(
view: tester.view, view: tester.binding.window,
child: Builder( child: Builder(
builder: (BuildContext context) { builder: (BuildContext context) {
rebuildCount++; rebuildCount++;
@ -354,39 +393,38 @@ void main() {
expect(rebuildCount, 1); expect(rebuildCount, 1);
expect(data.textScaleFactor, 123); expect(data.textScaleFactor, 123);
tester.platformDispatcher.textScaleFactorTestValue = 456; tester.binding.platformDispatcher.textScaleFactorTestValue = 456;
await tester.pump(); await tester.pump();
expect(data.textScaleFactor, 456); expect(data.textScaleFactor, 456);
expect(rebuildCount, 2); expect(rebuildCount, 2);
expect(data.platformBrightness, Brightness.dark); expect(data.platformBrightness, Brightness.dark);
tester.platformDispatcher.platformBrightnessTestValue = Brightness.light; tester.binding.platformDispatcher.platformBrightnessTestValue = Brightness.light;
await tester.pump(); await tester.pump();
expect(data.platformBrightness, Brightness.light); expect(data.platformBrightness, Brightness.light);
expect(rebuildCount, 3); expect(rebuildCount, 3);
expect(data.accessibleNavigation, true); expect(data.accessibleNavigation, true);
tester.platformDispatcher.accessibilityFeaturesTestValue = const FakeAccessibilityFeatures(); tester.binding.platformDispatcher.accessibilityFeaturesTestValue = const FakeAccessibilityFeatures();
await tester.pump(); await tester.pump();
expect(data.accessibleNavigation, false); expect(data.accessibleNavigation, false);
expect(rebuildCount, 4); expect(rebuildCount, 4);
expect(data.devicePixelRatio, 44); expect(data.devicePixelRatio, 44);
tester.view.devicePixelRatio = 55; tester.binding.window.devicePixelRatioTestValue = 55;
await tester.pump(); await tester.pump();
expect(data.devicePixelRatio, 55); expect(data.devicePixelRatio, 55);
expect(rebuildCount, 5); expect(rebuildCount, 5);
}); });
testWidgets('MediaQuery.fromView updates on notifications (with parent data)', (WidgetTester tester) async { testWidgets('MediaQuery.fromView updates on notifications (with parent data)', (WidgetTester tester) async {
addTearDown(() => tester.platformDispatcher.clearAllTestValues()); tester.binding.platformDispatcher
addTearDown(() => tester.view.reset());
tester.platformDispatcher
..textScaleFactorTestValue = 123 ..textScaleFactorTestValue = 123
..platformBrightnessTestValue = Brightness.dark ..platformBrightnessTestValue = Brightness.dark
..accessibilityFeaturesTestValue = FakeAccessibilityFeatures.allOn; ..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; late MediaQueryData data;
int rebuildCount = 0; int rebuildCount = 0;
@ -398,7 +436,7 @@ void main() {
accessibleNavigation: true, accessibleNavigation: true,
), ),
child: MediaQuery.fromView( child: MediaQuery.fromView(
view: tester.view, view: tester.binding.window,
child: Builder( child: Builder(
builder: (BuildContext context) { builder: (BuildContext context) {
rebuildCount++; rebuildCount++;
@ -413,25 +451,25 @@ void main() {
expect(rebuildCount, 1); expect(rebuildCount, 1);
expect(data.textScaleFactor, 44); expect(data.textScaleFactor, 44);
tester.platformDispatcher.textScaleFactorTestValue = 456; tester.binding.platformDispatcher.textScaleFactorTestValue = 456;
await tester.pump(); await tester.pump();
expect(data.textScaleFactor, 44); expect(data.textScaleFactor, 44);
expect(rebuildCount, 1); expect(rebuildCount, 1);
expect(data.platformBrightness, Brightness.dark); expect(data.platformBrightness, Brightness.dark);
tester.platformDispatcher.platformBrightnessTestValue = Brightness.light; tester.binding.platformDispatcher.platformBrightnessTestValue = Brightness.light;
await tester.pump(); await tester.pump();
expect(data.platformBrightness, Brightness.dark); expect(data.platformBrightness, Brightness.dark);
expect(rebuildCount, 1); expect(rebuildCount, 1);
expect(data.accessibleNavigation, true); expect(data.accessibleNavigation, true);
tester.platformDispatcher.accessibilityFeaturesTestValue = const FakeAccessibilityFeatures(); tester.binding.platformDispatcher.accessibilityFeaturesTestValue = const FakeAccessibilityFeatures();
await tester.pump(); await tester.pump();
expect(data.accessibleNavigation, true); expect(data.accessibleNavigation, true);
expect(rebuildCount, 1); expect(rebuildCount, 1);
expect(data.devicePixelRatio, 44); expect(data.devicePixelRatio, 44);
tester.view.devicePixelRatio = 55; tester.binding.window.devicePixelRatioTestValue = 55;
await tester.pump(); await tester.pump();
expect(data.devicePixelRatio, 55); expect(data.devicePixelRatio, 55);
expect(rebuildCount, 2); expect(rebuildCount, 2);
@ -449,7 +487,7 @@ void main() {
return MediaQuery( return MediaQuery(
data: MediaQueryData(textScaleFactor: textScaleFactor), data: MediaQueryData(textScaleFactor: textScaleFactor),
child: MediaQuery.fromView( child: MediaQuery.fromView(
view: tester.view, view: tester.binding.window,
child: Builder( child: Builder(
builder: (BuildContext context) { builder: (BuildContext context) {
rebuildCount++; rebuildCount++;
@ -475,7 +513,7 @@ void main() {
}); });
testWidgets('MediaQueryData.copyWith defaults to source', (WidgetTester tester) async { 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(); final MediaQueryData copied = data.copyWith();
expect(copied.size, data.size); expect(copied.size, data.size);
expect(copied.devicePixelRatio, data.devicePixelRatio); 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( final MediaQueryData copied = data.copyWith(
size: customSize, size: customSize,
devicePixelRatio: customDevicePixelRatio, devicePixelRatio: customDevicePixelRatio,
@ -1287,11 +1325,11 @@ void main() {
expect(subScreenMediaQuery.displayFeatures, <DisplayFeature>[cutoutDisplayFeature]); expect(subScreenMediaQuery.displayFeatures, <DisplayFeature>[cutoutDisplayFeature]);
}); });
testWidgets('MediaQueryData.gestureSettings is set from view.gestureSettings', (WidgetTester tester) async { testWidgets('MediaQueryData.gestureSettings is set from window.viewConfiguration', (WidgetTester tester) async {
tester.view.gestureSettings = const GestureSettings(physicalDoubleTapSlop: 100, physicalTouchSlop: 100); tester.binding.window.gestureSettingsTestValue = const GestureSettings(physicalDoubleTapSlop: 100, physicalTouchSlop: 100);
addTearDown(() => tester.view.resetGestureSettings());
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 { testWidgets('MediaQuery can be partially depended-on', (WidgetTester tester) async {
@ -1473,3 +1511,52 @@ Future<void> pumpWidgetWithoutViewWrapper({required WidgetTester tester, require
tester.binding.scheduleFrame(); tester.binding.scheduleFrame();
return tester.binding.pump(); 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<DisplayFeature> displayFeatures = <DisplayFeature>[];
@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;
}

View File

@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui' show FlutterView;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
@ -2679,7 +2677,6 @@ void main() {
group('Page api', () { group('Page api', () {
Widget buildNavigator({ Widget buildNavigator({
required FlutterView view,
required List<Page<dynamic>> pages, required List<Page<dynamic>> pages,
required PopPageCallback onPopPage, required PopPageCallback onPopPage,
GlobalKey<NavigatorState>? key, GlobalKey<NavigatorState>? key,
@ -2687,7 +2684,7 @@ void main() {
List<NavigatorObserver> observers = const <NavigatorObserver>[], List<NavigatorObserver> observers = const <NavigatorObserver>[],
}) { }) {
return MediaQuery( return MediaQuery(
data: MediaQueryData.fromView(view), data: MediaQueryData.fromView(WidgetsBinding.instance.window),
child: Localizations( child: Localizations(
locale: const Locale('en', 'US'), locale: const Locale('en', 'US'),
delegates: const <LocalizationsDelegate<dynamic>>[ delegates: const <LocalizationsDelegate<dynamic>>[
@ -2721,12 +2718,7 @@ void main() {
} }
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
expect(find.text('third'), findsOneWidget); expect(find.text('third'), findsOneWidget);
expect(find.text('second'), findsNothing); expect(find.text('second'), findsNothing);
@ -2758,42 +2750,22 @@ void main() {
bool onPopPage(Route<dynamic> route, dynamic result) => false; bool onPopPage(Route<dynamic> route, dynamic result) => false;
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages1, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages1,
onPopPage: onPopPage,
key: navigator,
),
); );
await tester.pump(); await tester.pump();
expect(find.text('initial'), findsOneWidget); expect(find.text('initial'), findsOneWidget);
// Update multiple times without waiting for pop to finish to leave // Update multiple times without waiting for pop to finish to leave
// multiple popping route entries in route stack with the same page key. // multiple popping route entries in route stack with the same page key.
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages2, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages2,
onPopPage: onPopPage,
key: navigator,
),
); );
await tester.pump(); await tester.pump();
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages1, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages1,
onPopPage: onPopPage,
key: navigator,
),
); );
await tester.pump(); await tester.pump();
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages2, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages2,
onPopPage: onPopPage,
key: navigator,
),
); );
await tester.pumpAndSettle(); await tester.pumpAndSettle();
@ -2897,12 +2869,7 @@ void main() {
} }
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
expect(find.text('initial'), findsOneWidget); expect(find.text('initial'), findsOneWidget);
@ -2937,12 +2904,7 @@ void main() {
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
// The third page is transitioning, and the secondary animation of first // The third page is transitioning, and the secondary animation of first
// page should chain with the third page. The animation of second page // page should chain with the third page. The animation of second page
@ -2997,12 +2959,7 @@ void main() {
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
await tester.pump(const Duration(milliseconds: 30)); await tester.pump(const Duration(milliseconds: 30));
expect(secondaryAnimationOfRouteOne.value, primaryAnimationOfRouteTwo.value); expect(secondaryAnimationOfRouteOne.value, primaryAnimationOfRouteTwo.value);
@ -3062,12 +3019,7 @@ void main() {
return route.didPop(result); return route.didPop(result);
} }
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
expect(find.text('third'), findsOneWidget); expect(find.text('third'), findsOneWidget);
expect(find.text('second'), findsNothing); expect(find.text('second'), findsNothing);
@ -3081,12 +3033,7 @@ void main() {
myPages = myPages.reversed.toList(); myPages = myPages.reversed.toList();
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
// Reversed routes are still chained up correctly. // Reversed routes are still chained up correctly.
expect(secondaryAnimationOfRouteThree.value, primaryAnimationOfRouteTwo.value); expect(secondaryAnimationOfRouteThree.value, primaryAnimationOfRouteTwo.value);
@ -3169,12 +3116,7 @@ void main() {
} }
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
expect(find.text('second'), findsOneWidget); expect(find.text('second'), findsOneWidget);
expect(find.text('initial'), findsNothing); expect(find.text('initial'), findsNothing);
@ -3203,12 +3145,7 @@ void main() {
const TestPage(key: ValueKey<String>('3'), name:'third'), const TestPage(key: ValueKey<String>('3'), name:'third'),
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(find.text('initial'), findsNothing); expect(find.text('initial'), findsNothing);
@ -3239,12 +3176,7 @@ void main() {
const TestPage(key: ValueKey<String>('2'), name:'second'), const TestPage(key: ValueKey<String>('2'), name:'second'),
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
// Swaps the order without any adding or removing should not trigger any // Swaps the order without any adding or removing should not trigger any
// transition. The routes should update without a pumpAndSettle // transition. The routes should update without a pumpAndSettle
@ -3316,12 +3248,7 @@ void main() {
// Add initial page route with one pageless route. // Add initial page route with one pageless route.
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
bool initialPageless1Completed = false; bool initialPageless1Completed = false;
navigator.currentState!.push( navigator.currentState!.push(
@ -3337,12 +3264,7 @@ void main() {
const TestPage(key: ValueKey<String>('2'), name: 'second'), const TestPage(key: ValueKey<String>('2'), name: 'second'),
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
await tester.pumpAndSettle(); await tester.pumpAndSettle();
bool secondPageless1Completed = false; bool secondPageless1Completed = false;
@ -3367,12 +3289,7 @@ void main() {
const TestPage(key: ValueKey<String>('3'), name: 'third'), const TestPage(key: ValueKey<String>('3'), name: 'third'),
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
await tester.pumpAndSettle(); await tester.pumpAndSettle();
bool thirdPageless1Completed = false; bool thirdPageless1Completed = false;
@ -3395,12 +3312,7 @@ void main() {
const TestPage(key: ValueKey<String>('2'), name: 'second'), const TestPage(key: ValueKey<String>('2'), name: 'second'),
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
// The pageless route of initial page route should be completed. // The pageless route of initial page route should be completed.
expect(initialPageless1Completed, true); expect(initialPageless1Completed, true);
@ -3412,12 +3324,7 @@ void main() {
const TestPage(key: ValueKey<String>('3'), name: 'third'), const TestPage(key: ValueKey<String>('3'), name: 'third'),
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(secondPageless1Completed, true); expect(secondPageless1Completed, true);
@ -3428,12 +3335,7 @@ void main() {
const TestPage(key: ValueKey<String>('4'), name: 'forth'), const TestPage(key: ValueKey<String>('4'), name: 'forth'),
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
expect(thirdPageless1Completed, true); expect(thirdPageless1Completed, true);
await tester.pumpAndSettle(); await tester.pumpAndSettle();
@ -3454,12 +3356,7 @@ void main() {
} }
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
expect(find.text('second'), findsOneWidget); expect(find.text('second'), findsOneWidget);
expect(find.text('initial'), findsNothing); expect(find.text('initial'), findsNothing);
@ -3481,12 +3378,7 @@ void main() {
const TestPage(key: ValueKey<String>('2'), name:'second'), const TestPage(key: ValueKey<String>('2'), name:'second'),
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
await tester.pumpAndSettle(); await tester.pumpAndSettle();
@ -3519,7 +3411,6 @@ void main() {
// Add initial page route with one pageless route. // Add initial page route with one pageless route.
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(
view: tester.view,
pages: myPages, pages: myPages,
onPopPage: onPopPage, onPopPage: onPopPage,
key: navigator, key: navigator,
@ -3541,7 +3432,6 @@ void main() {
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(
view: tester.view,
pages: myPages, pages: myPages,
onPopPage: onPopPage, onPopPage: onPopPage,
key: navigator, key: navigator,
@ -3571,7 +3461,6 @@ void main() {
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(
view: tester.view,
pages: myPages, pages: myPages,
onPopPage: onPopPage, onPopPage: onPopPage,
key: navigator, key: navigator,
@ -3599,7 +3488,6 @@ void main() {
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(
view: tester.view,
pages: myPages, pages: myPages,
onPopPage: onPopPage, onPopPage: onPopPage,
key: navigator, key: navigator,
@ -3617,7 +3505,6 @@ void main() {
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(
view: tester.view,
pages: myPages, pages: myPages,
onPopPage: onPopPage, onPopPage: onPopPage,
key: navigator, key: navigator,
@ -3635,7 +3522,6 @@ void main() {
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(
view: tester.view,
pages: myPages, pages: myPages,
onPopPage: onPopPage, onPopPage: onPopPage,
key: navigator, key: navigator,
@ -3661,12 +3547,7 @@ void main() {
return route.didPop(result); return route.didPop(result);
} }
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
// Pops the second page route. // Pops the second page route.
@ -3674,12 +3555,7 @@ void main() {
const TestPage(key: ValueKey<String>('1'), name: 'initial'), const TestPage(key: ValueKey<String>('1'), name: 'initial'),
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
// Re-push the second page again before it finishes popping. // Re-push the second page again before it finishes popping.
@ -3688,12 +3564,7 @@ void main() {
const TestPage(key: ValueKey<String>('2'), name: 'second'), const TestPage(key: ValueKey<String>('2'), name: 'second'),
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
// It should not crash the app. // It should not crash the app.
@ -3713,12 +3584,7 @@ void main() {
return route.didPop(result); return route.didPop(result);
} }
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
// Pops the second page route. // Pops the second page route.
@ -3726,12 +3592,7 @@ void main() {
const TestPage(key: ValueKey<String>('1'), name: 'initial'), const TestPage(key: ValueKey<String>('1'), name: 'initial'),
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
// Updates the pages again before second page finishes popping. // Updates the pages again before second page finishes popping.
@ -3739,12 +3600,7 @@ void main() {
const TestPage(key: ValueKey<String>('1'), name: 'initial'), const TestPage(key: ValueKey<String>('1'), name: 'initial'),
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
// It should not crash the app. // It should not crash the app.
@ -3765,12 +3621,7 @@ void main() {
return route.didPop(result); return route.didPop(result);
} }
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
// Pushes a pageless route. // Pushes a pageless route.
showDialog<void>( showDialog<void>(
@ -3787,12 +3638,7 @@ void main() {
const TestPage(key: ValueKey<String>('1'), name: 'initial'), const TestPage(key: ValueKey<String>('1'), name: 'initial'),
]; ];
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator),
view: tester.view,
pages: myPages,
onPopPage: onPopPage,
key: navigator,
),
); );
// It should not crash the app. // It should not crash the app.
expect(tester.takeException(), isNull); expect(tester.takeException(), isNull);
@ -3831,7 +3677,6 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(
view: tester.view,
pages: myPages, pages: myPages,
onPopPage: onPopPage, onPopPage: onPopPage,
key: navigator, key: navigator,
@ -3845,7 +3690,6 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
buildNavigator( buildNavigator(
view: tester.view,
pages: myPages, pages: myPages,
onPopPage: onPopPage, onPopPage: onPopPage,
key: navigator, key: navigator,

View File

@ -223,7 +223,7 @@ void main() {
'_RenderDiagonal#00000 relayoutBoundary=up1\n' '_RenderDiagonal#00000 relayoutBoundary=up1\n'
' │ creator: _Diagonal ← Align ← Directionality ← MediaQuery ←\n' ' │ creator: _Diagonal ← Align ← Directionality ← MediaQuery ←\n'
' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\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' ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n'
' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n' ' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n'
' │ size: Size(190.0, 220.0)\n' ' │ size: Size(190.0, 220.0)\n'
@ -231,7 +231,7 @@ void main() {
' ├─topLeft: RenderConstrainedBox#00000 relayoutBoundary=up2\n' ' ├─topLeft: RenderConstrainedBox#00000 relayoutBoundary=up2\n'
' │ creator: SizedBox ← _Diagonal ← Align ← Directionality ←\n' ' │ creator: SizedBox ← _Diagonal ← Align ← Directionality ←\n'
' │ MediaQuery ← _MediaQueryFromView ← _ViewScope ←\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' ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n'
' │ constraints: BoxConstraints(unconstrained)\n' ' │ constraints: BoxConstraints(unconstrained)\n'
' │ size: Size(80.0, 100.0)\n' ' │ size: Size(80.0, 100.0)\n'
@ -240,7 +240,7 @@ void main() {
' └─bottomRight: RenderConstrainedBox#00000 relayoutBoundary=up2\n' ' └─bottomRight: RenderConstrainedBox#00000 relayoutBoundary=up2\n'
' creator: SizedBox ← _Diagonal ← Align ← Directionality ←\n' ' creator: SizedBox ← _Diagonal ← Align ← Directionality ←\n'
' MediaQuery ← _MediaQueryFromView ← _ViewScope ←\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' ' parentData: offset=Offset(80.0, 100.0) (can use size)\n'
' constraints: BoxConstraints(unconstrained)\n' ' constraints: BoxConstraints(unconstrained)\n'
' size: Size(110.0, 120.0)\n' ' size: Size(110.0, 120.0)\n'

View File

@ -227,9 +227,10 @@ void main() {
const Size kCommonScreenSizeLandscape = Size(1770, 1070); const Size kCommonScreenSizeLandscape = Size(1770, 1070);
Future<void> showPicker(WidgetTester tester, Locale locale, Size size) async { Future<void> showPicker(WidgetTester tester, Locale locale, Size size) async {
tester.view.physicalSize = size; tester.binding.window.physicalSizeTestValue = size;
tester.view.devicePixelRatio = 1.0; addTearDown(tester.binding.window.clearPhysicalSizeTestValue);
addTearDown(tester.view.reset); tester.binding.window.devicePixelRatioTestValue = 1.0;
addTearDown(tester.binding.window.clearDevicePixelRatioTestValue);
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
home: Builder( home: Builder(

View File

@ -9,9 +9,8 @@ import 'package:flutter_test/flutter_test.dart';
void main() { void main() {
testWidgets('can localize the header in all known formats - portrait', (WidgetTester tester) async { testWidgets('can localize the header in all known formats - portrait', (WidgetTester tester) async {
// Ensure picker is displayed in portrait mode. // Ensure picker is displayed in portrait mode.
tester.view.physicalSize = const Size(400, 800); tester.binding.window.physicalSizeTestValue = const Size(400, 800);
tester.view.devicePixelRatio = 1; tester.binding.window.devicePixelRatioTestValue = 1;
addTearDown(tester.view.reset);
final Finder stringFragmentTextFinder = find.descendant( final Finder stringFragmentTextFinder = find.descendant(
of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_StringFragment'), 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 tester.tapAt(Offset(center.dx, center.dy - 50.0));
await finishPicker(tester); await finishPicker(tester);
} }
tester.binding.window.clearPhysicalSizeTestValue();
tester.binding.window.clearDevicePixelRatioTestValue();
}); });
testWidgets('can localize the header in all known formats - landscape', (WidgetTester tester) async { testWidgets('can localize the header in all known formats - landscape', (WidgetTester tester) async {
// Ensure picker is displayed in landscape mode. // Ensure picker is displayed in landscape mode.
tester.view.physicalSize = const Size(800, 400); tester.binding.window.physicalSizeTestValue = const Size(800, 400);
tester.view.devicePixelRatio = 1; tester.binding.window.devicePixelRatioTestValue = 1;
addTearDown(tester.view.reset);
final Finder stringFragmentTextFinder = find.descendant( final Finder stringFragmentTextFinder = find.descendant(
of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_StringFragment'), 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 tester.tapAt(Offset(center.dx, center.dy - 50.0));
await finishPicker(tester); await finishPicker(tester);
} }
tester.binding.window.clearPhysicalSizeTestValue();
tester.binding.window.clearDevicePixelRatioTestValue();
}); });
testWidgets('can localize input mode in all known formats', (WidgetTester tester) async { testWidgets('can localize input mode in all known formats', (WidgetTester tester) async {

View File

@ -182,18 +182,17 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
/// ///
/// This constructor overrides the [debugPrint] global hook to point to /// This constructor overrides the [debugPrint] global hook to point to
/// [debugPrintOverride], which can be overridden by subclasses. /// [debugPrintOverride], which can be overridden by subclasses.
TestWidgetsFlutterBinding() : platformDispatcher = TestPlatformDispatcher( TestWidgetsFlutterBinding() : _window = TestWindow(window: ui.window) {
platformDispatcher: PlatformDispatcher.instance,
) {
debugPrint = debugPrintOverride; debugPrint = debugPrintOverride;
debugDisableShadows = disableShadows; debugDisableShadows = disableShadows;
} }
@override @override
late final TestWindow window; TestWindow get window => _window;
final TestWindow _window;
@override @override
final TestPlatformDispatcher platformDispatcher; TestPlatformDispatcher get platformDispatcher => _window.platformDispatcher;
@override @override
TestRestorationManager get restorationManager { TestRestorationManager get restorationManager {
@ -347,12 +346,6 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
@override @override
void initInstances() { 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(); super.initInstances();
_instance = this; _instance = this;
timeDilation = 1.0; // just in case the developer has artificially changed it for development timeDilation = 1.0; // just in case the developer has artificially changed it for development
@ -1919,9 +1912,9 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
@override @override
ViewConfiguration createViewConfiguration() { ViewConfiguration createViewConfiguration() {
return TestViewConfiguration.fromView( return TestViewConfiguration(
size: _surfaceSize ?? _kDefaultTestViewportSize, 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 is in logical pixels. The resulting ViewConfiguration maps the given
/// size onto the actual display using the [BoxFit.contain] algorithm. /// size onto the actual display using the [BoxFit.contain] algorithm.
class TestViewConfiguration extends ViewConfiguration { 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 /// If a [window] instance is not provided it defaults to [ui.window].
/// 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.'
)
factory TestViewConfiguration({ factory TestViewConfiguration({
Size size = _kDefaultTestViewportSize, Size size = _kDefaultTestViewportSize,
ui.FlutterView? window, 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. TestViewConfiguration._(Size size, ui.FlutterView window)
/// : _paintMatrix = _getMatrix(size, window.devicePixelRatio, window),
/// The [size] defaults to 800x600. _hitTestMatrix = _getMatrix(size, 1.0, window),
TestViewConfiguration.fromView({required ui.FlutterView view, super.size = _kDefaultTestViewportSize}) super(size: size, devicePixelRatio: window.devicePixelRatio);
: _paintMatrix = _getMatrix(size, view.devicePixelRatio, view),
_hitTestMatrix = _getMatrix(size, 1.0, view),
super(devicePixelRatio: view.devicePixelRatio);
static Matrix4 _getMatrix(Size size, double devicePixelRatio, ui.FlutterView window) { static Matrix4 _getMatrix(Size size, double devicePixelRatio, ui.FlutterView window) {
final double inverseRatio = devicePixelRatio / window.devicePixelRatio; final double inverseRatio = devicePixelRatio / window.devicePixelRatio;

View File

@ -14,7 +14,6 @@ import 'event_simulation.dart';
import 'finders.dart'; import 'finders.dart';
import 'test_async_utils.dart'; import 'test_async_utils.dart';
import 'test_pointer.dart'; import 'test_pointer.dart';
import 'window.dart';
/// The default drag touch slop used to break up a large drag into multiple /// The default drag touch slop used to break up a large drag into multiple
/// smaller moves. /// smaller moves.
@ -235,37 +234,6 @@ abstract class WidgetController {
/// A reference to the current instance of the binding. /// A reference to the current instance of the binding.
final WidgetsBinding 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 /// Provides access to a [SemanticsController] for testing anything related to
/// the [Semantics] tree. /// the [Semantics] tree.
/// ///
@ -289,26 +257,6 @@ abstract class WidgetController {
// TODO(ianh): verify that the return values are of type T and throw // TODO(ianh): verify that the return values are of type T and throw
// a good message otherwise, in all the generic methods below // 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<View>(
find.ancestor(
of: finder,
matching: find.byType(View),
)
);
return view.view as TestFlutterView;
}
/// Checks if `finder` exists in the tree. /// Checks if `finder` exists in the tree.
bool any(Finder finder) { bool any(Finder finder) {
TestAsyncUtils.guardSync(); TestAsyncUtils.guardSync();

File diff suppressed because it is too large Load Diff

View File

@ -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<TestFlutterView>());
});
group('SemanticsController', () { group('SemanticsController', () {
group('find', () { group('find', () {
testWidgets('throws when there are no semantics', (WidgetTester tester) async { testWidgets('throws when there are no semantics', (WidgetTester tester) async {

View File

@ -7,17 +7,15 @@ import 'dart:ui' show AccessibilityFeatures, Brightness, Locale, PlatformDispatc
import 'package:flutter/widgets.dart' show WidgetsBinding, WidgetsBindingObserver; import 'package:flutter/widgets.dart' show WidgetsBinding, WidgetsBindingObserver;
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'utils/fake_and_mock_utils.dart';
void main() { 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); final dynamic testPlatformDispatcher = TestPlatformDispatcher(platformDispatcher: PlatformDispatcher.instance);
// ignore: avoid_dynamic_calls // ignore: avoid_dynamic_calls
expect(testPlatformDispatcher.someNewProperty, null); expect(testPlatformDispatcher.someNewProperty, null);
}); });
testWidgets('TestPlatformDispatcher can fake locale', (WidgetTester tester) async { testWidgets('TestWindow can fake locale', (WidgetTester tester) async {
verifyPropertyFaked<Locale>( verifyThatTestPlatformDispatcherCanFakeProperty<Locale>(
tester: tester, tester: tester,
realValue: PlatformDispatcher.instance.locale, realValue: PlatformDispatcher.instance.locale,
fakeValue: const Locale('fake_language_code'), fakeValue: const Locale('fake_language_code'),
@ -30,8 +28,8 @@ void main() {
); );
}); });
testWidgets('TestPlatformDispatcher can fake locales', (WidgetTester tester) async { testWidgets('TestWindow can fake locales', (WidgetTester tester) async {
verifyPropertyFaked<List<Locale>>( verifyThatTestPlatformDispatcherCanFakeProperty<List<Locale>>(
tester: tester, tester: tester,
realValue: PlatformDispatcher.instance.locales, realValue: PlatformDispatcher.instance.locales,
fakeValue: <Locale>[const Locale('fake_language_code')], fakeValue: <Locale>[const Locale('fake_language_code')],
@ -44,8 +42,8 @@ void main() {
); );
}); });
testWidgets('TestPlatformDispatcher can fake text scale factor', (WidgetTester tester) async { testWidgets('TestWindow can fake text scale factor', (WidgetTester tester) async {
verifyPropertyFaked<double>( verifyThatTestPlatformDispatcherCanFakeProperty<double>(
tester: tester, tester: tester,
realValue: PlatformDispatcher.instance.textScaleFactor, realValue: PlatformDispatcher.instance.textScaleFactor,
fakeValue: 2.5, fakeValue: 2.5,
@ -58,8 +56,8 @@ void main() {
); );
}); });
testWidgets('TestPlatformDispatcher can fake clock format', (WidgetTester tester) async { testWidgets('TestWindow can fake clock format', (WidgetTester tester) async {
verifyPropertyFaked<bool>( verifyThatTestPlatformDispatcherCanFakeProperty<bool>(
tester: tester, tester: tester,
realValue: PlatformDispatcher.instance.alwaysUse24HourFormat, realValue: PlatformDispatcher.instance.alwaysUse24HourFormat,
fakeValue: !PlatformDispatcher.instance.alwaysUse24HourFormat, fakeValue: !PlatformDispatcher.instance.alwaysUse24HourFormat,
@ -72,8 +70,8 @@ void main() {
); );
}); });
testWidgets('TestPlatformDispatcher can fake brieflyShowPassword', (WidgetTester tester) async { testWidgets('TestWindow can fake brieflyShowPassword', (WidgetTester tester) async {
verifyPropertyFaked<bool>( verifyThatTestPlatformDispatcherCanFakeProperty<bool>(
tester: tester, tester: tester,
realValue: PlatformDispatcher.instance.brieflyShowPassword, realValue: PlatformDispatcher.instance.brieflyShowPassword,
fakeValue: !PlatformDispatcher.instance.brieflyShowPassword, fakeValue: !PlatformDispatcher.instance.brieflyShowPassword,
@ -84,8 +82,8 @@ void main() {
); );
}); });
testWidgets('TestPlatformDispatcher can fake default route name', (WidgetTester tester) async { testWidgets('TestWindow can fake default route name', (WidgetTester tester) async {
verifyPropertyFaked<String>( verifyThatTestPlatformDispatcherCanFakeProperty<String>(
tester: tester, tester: tester,
realValue: PlatformDispatcher.instance.defaultRouteName, realValue: PlatformDispatcher.instance.defaultRouteName,
fakeValue: 'fake_route', fakeValue: 'fake_route',
@ -98,8 +96,8 @@ void main() {
); );
}); });
testWidgets('TestPlatformDispatcher can fake accessibility features', (WidgetTester tester) async { testWidgets('TestWindow can fake accessibility features', (WidgetTester tester) async {
verifyPropertyFaked<AccessibilityFeatures>( verifyThatTestPlatformDispatcherCanFakeProperty<AccessibilityFeatures>(
tester: tester, tester: tester,
realValue: PlatformDispatcher.instance.accessibilityFeatures, realValue: PlatformDispatcher.instance.accessibilityFeatures,
fakeValue: const FakeAccessibilityFeatures(), fakeValue: const FakeAccessibilityFeatures(),
@ -112,8 +110,8 @@ void main() {
); );
}); });
testWidgets('TestPlatformDispatcher can fake platform brightness', (WidgetTester tester) async { testWidgets('TestWindow can fake platform brightness', (WidgetTester tester) async {
verifyPropertyFaked<Brightness>( verifyThatTestPlatformDispatcherCanFakeProperty<Brightness>(
tester: tester, tester: tester,
realValue: Brightness.light, realValue: Brightness.light,
fakeValue: Brightness.dark, 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 Locale originalLocale = PlatformDispatcher.instance.locale;
final double originalTextScaleFactor = PlatformDispatcher.instance.textScaleFactor; final double originalTextScaleFactor = PlatformDispatcher.instance.textScaleFactor;
final TestPlatformDispatcher testPlatformDispatcher = retrieveTestBinding(tester).platformDispatcher; final TestPlatformDispatcher testPlatformDispatcher = retrieveTestBinding(tester).platformDispatcher;
@ -143,7 +141,7 @@ void main() {
expect(WidgetsBinding.instance.platformDispatcher.textScaleFactor, originalTextScaleFactor); 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<Locale> defaultLocales = WidgetsBinding.instance.platformDispatcher.locales; final List<Locale> defaultLocales = WidgetsBinding.instance.platformDispatcher.locales;
final TestObserver observer = TestObserver(); final TestObserver observer = TestObserver();
retrieveTestBinding(tester).addObserver(observer); retrieveTestBinding(tester).addObserver(observer);
@ -154,8 +152,36 @@ void main() {
}); });
} }
void verifyThatTestPlatformDispatcherCanFakeProperty<PlatformDispatcherPropertyType>({
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 { class TestObserver with WidgetsBindingObserver {
List<Locale>? locales; List<Locale>? locales;
Locale? locale;
@override @override
void didChangeLocales(List<Locale>? locales) { void didChangeLocales(List<Locale>? locales) {

View File

@ -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<TProperty>({
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<TProperty>({
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<dynamic, dynamic> 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<dynamic, dynamic> 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;
}
}

View File

@ -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<double>(
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<double>(
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<List<DisplayFeature>>(
tester: tester,
realValue: trueImplicitView().displayFeatures,
fakeValue: <DisplayFeature>[const DisplayFeature(bounds: Rect.fromLTWH(0, 0, 500, 30), type: DisplayFeatureType.unknown, state: DisplayFeatureState.unknown)],
propertyRetriever: () => boundImplicitView().displayFeatures,
propertyFaker: (_, List<DisplayFeature> fakeValue) {
tester.view.displayFeatures = fakeValue;
},
);
});
testWidgets('can reset displayFeatures', (WidgetTester tester) async {
verifyPropertyReset<List<DisplayFeature>>(
tester: tester,
fakeValue: <DisplayFeature>[const DisplayFeature(bounds: Rect.fromLTWH(0, 0, 500, 30), type: DisplayFeatureType.unknown, state: DisplayFeatureState.unknown)],
propertyRetriever: () => boundImplicitView().displayFeatures,
propertyResetter: () {
tester.view.resetDisplayFeatures();
},
propertyFaker: (List<DisplayFeature> fakeValue) {
tester.view.displayFeatures = fakeValue;
},
);
});
testWidgets('can fake padding', (WidgetTester tester) async {
verifyPropertyFaked<ViewPadding>(
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<ViewPadding>(
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<Rect>(
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<Rect>(
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<Size>(
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<Size>(
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<ViewPadding>(
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<ViewPadding>(
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<ViewPadding>(
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<ViewPadding>(
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<ViewPadding>(
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<ViewPadding>(
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 = <DisplayFeature>[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<dynamic, dynamic> 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<dynamic, dynamic> 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 = <DisplayFeature>[...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<DisplayFeature> 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;
}
}

View File

@ -3,19 +3,13 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui' as ui show window; 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/widgets.dart' show WidgetsBinding, WidgetsBindingObserver;
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'utils/fake_and_mock_utils.dart';
void main() { void main() {
tearDown(() {
final TestWindow window = WidgetsBinding.instance.window as TestWindow;
window.clearAllTestValues();
});
test('TestWindow can handle new methods without breaking', () { test('TestWindow can handle new methods without breaking', () {
final dynamic testWindow = TestWindow(window: ui.window); final dynamic testWindow = TestWindow(window: ui.window);
// ignore: avoid_dynamic_calls // ignore: avoid_dynamic_calls
@ -23,7 +17,7 @@ void main() {
}); });
testWidgets('TestWindow can fake device pixel ratio', (WidgetTester tester) async { testWidgets('TestWindow can fake device pixel ratio', (WidgetTester tester) async {
verifyPropertyFaked<double>( verifyThatTestWindowCanFakeProperty<double>(
tester: tester, tester: tester,
realValue: ui.window.devicePixelRatio, realValue: ui.window.devicePixelRatio,
fakeValue: 2.5, fakeValue: 2.5,
@ -37,7 +31,7 @@ void main() {
}); });
testWidgets('TestWindow can fake physical size', (WidgetTester tester) async { testWidgets('TestWindow can fake physical size', (WidgetTester tester) async {
verifyPropertyFaked<Size>( verifyThatTestWindowCanFakeProperty<Size>(
tester: tester, tester: tester,
realValue: ui.window.physicalSize, realValue: ui.window.physicalSize,
fakeValue: const Size(50, 50), fakeValue: const Size(50, 50),
@ -51,7 +45,7 @@ void main() {
}); });
testWidgets('TestWindow can fake view insets', (WidgetTester tester) async { testWidgets('TestWindow can fake view insets', (WidgetTester tester) async {
verifyPropertyFaked<ViewPadding>( verifyThatTestWindowCanFakeProperty<ViewPadding>(
tester: tester, tester: tester,
realValue: ui.window.viewInsets, realValue: ui.window.viewInsets,
fakeValue: const FakeViewPadding(), fakeValue: const FakeViewPadding(),
@ -61,12 +55,11 @@ void main() {
propertyFaker: (TestWidgetsFlutterBinding binding, ViewPadding fakeValue) { propertyFaker: (TestWidgetsFlutterBinding binding, ViewPadding fakeValue) {
binding.window.viewInsetsTestValue = fakeValue; binding.window.viewInsetsTestValue = fakeValue;
}, },
matcher: matchesViewPadding,
); );
}); });
testWidgets('TestWindow can fake padding', (WidgetTester tester) async { testWidgets('TestWindow can fake padding', (WidgetTester tester) async {
verifyPropertyFaked<ViewPadding>( verifyThatTestWindowCanFakeProperty<ViewPadding>(
tester: tester, tester: tester,
realValue: ui.window.padding, realValue: ui.window.padding,
fakeValue: const FakeViewPadding(), fakeValue: const FakeViewPadding(),
@ -76,12 +69,11 @@ void main() {
propertyFaker: (TestWidgetsFlutterBinding binding, ViewPadding fakeValue) { propertyFaker: (TestWidgetsFlutterBinding binding, ViewPadding fakeValue) {
binding.window.paddingTestValue = fakeValue; binding.window.paddingTestValue = fakeValue;
}, },
matcher: matchesViewPadding
); );
}); });
testWidgets('TestWindow can fake locale', (WidgetTester tester) async { testWidgets('TestWindow can fake locale', (WidgetTester tester) async {
verifyPropertyFaked<Locale>( verifyThatTestWindowCanFakeProperty<Locale>(
tester: tester, tester: tester,
realValue: ui.window.locale, realValue: ui.window.locale,
fakeValue: const Locale('fake_language_code'), fakeValue: const Locale('fake_language_code'),
@ -95,7 +87,7 @@ void main() {
}); });
testWidgets('TestWindow can fake locales', (WidgetTester tester) async { testWidgets('TestWindow can fake locales', (WidgetTester tester) async {
verifyPropertyFaked<List<Locale>>( verifyThatTestWindowCanFakeProperty<List<Locale>>(
tester: tester, tester: tester,
realValue: ui.window.locales, realValue: ui.window.locales,
fakeValue: <Locale>[const Locale('fake_language_code')], fakeValue: <Locale>[const Locale('fake_language_code')],
@ -109,7 +101,7 @@ void main() {
}); });
testWidgets('TestWindow can fake text scale factor', (WidgetTester tester) async { testWidgets('TestWindow can fake text scale factor', (WidgetTester tester) async {
verifyPropertyFaked<double>( verifyThatTestWindowCanFakeProperty<double>(
tester: tester, tester: tester,
realValue: ui.window.textScaleFactor, realValue: ui.window.textScaleFactor,
fakeValue: 2.5, fakeValue: 2.5,
@ -123,7 +115,7 @@ void main() {
}); });
testWidgets('TestWindow can fake clock format', (WidgetTester tester) async { testWidgets('TestWindow can fake clock format', (WidgetTester tester) async {
verifyPropertyFaked<bool>( verifyThatTestWindowCanFakeProperty<bool>(
tester: tester, tester: tester,
realValue: ui.window.alwaysUse24HourFormat, realValue: ui.window.alwaysUse24HourFormat,
fakeValue: !ui.window.alwaysUse24HourFormat, fakeValue: !ui.window.alwaysUse24HourFormat,
@ -137,7 +129,7 @@ void main() {
}); });
testWidgets('TestWindow can fake brieflyShowPassword', (WidgetTester tester) async { testWidgets('TestWindow can fake brieflyShowPassword', (WidgetTester tester) async {
verifyPropertyFaked<bool>( verifyThatTestWindowCanFakeProperty<bool>(
tester: tester, tester: tester,
realValue: ui.window.brieflyShowPassword, realValue: ui.window.brieflyShowPassword,
fakeValue: !ui.window.brieflyShowPassword, fakeValue: !ui.window.brieflyShowPassword,
@ -149,7 +141,7 @@ void main() {
}); });
testWidgets('TestWindow can fake default route name', (WidgetTester tester) async { testWidgets('TestWindow can fake default route name', (WidgetTester tester) async {
verifyPropertyFaked<String>( verifyThatTestWindowCanFakeProperty<String>(
tester: tester, tester: tester,
realValue: ui.window.defaultRouteName, realValue: ui.window.defaultRouteName,
fakeValue: 'fake_route', fakeValue: 'fake_route',
@ -163,7 +155,7 @@ void main() {
}); });
testWidgets('TestWindow can fake accessibility features', (WidgetTester tester) async { testWidgets('TestWindow can fake accessibility features', (WidgetTester tester) async {
verifyPropertyFaked<AccessibilityFeatures>( verifyThatTestWindowCanFakeProperty<AccessibilityFeatures>(
tester: tester, tester: tester,
realValue: ui.window.accessibilityFeatures, realValue: ui.window.accessibilityFeatures,
fakeValue: const FakeAccessibilityFeatures(), fakeValue: const FakeAccessibilityFeatures(),
@ -177,7 +169,7 @@ void main() {
}); });
testWidgets('TestWindow can fake platform brightness', (WidgetTester tester) async { testWidgets('TestWindow can fake platform brightness', (WidgetTester tester) async {
verifyPropertyFaked<Brightness>( verifyThatTestWindowCanFakeProperty<Brightness>(
tester: tester, tester: tester,
realValue: Brightness.light, realValue: Brightness.light,
fakeValue: Brightness.dark, fakeValue: Brightness.dark,
@ -217,27 +209,63 @@ void main() {
retrieveTestBinding(tester).window.localesTestValue = defaultLocales; retrieveTestBinding(tester).window.localesTestValue = defaultLocales;
}); });
testWidgets('Updates to window also update tester.view', (WidgetTester tester) async { test('Window test', () {
tester.binding.window.devicePixelRatioTestValue = 7; final FakeSingletonWindow fakeWindow = FakeSingletonWindow();
tester.binding.window.displayFeaturesTestValue = <DisplayFeature>[const DisplayFeature(bounds: Rect.fromLTWH(0, 0, 20, 300), type: DisplayFeatureType.unknown, state: DisplayFeatureState.unknown)]; final TestWindow testWindow = TestWindow(window: fakeWindow);
tester.binding.window.paddingTestValue = const FakeViewPadding(); final SemanticsUpdate update = SemanticsUpdateBuilder().build();
tester.binding.window.physicalSizeTestValue = const Size(505, 805); testWindow.updateSemantics(update);
tester.binding.window.systemGestureInsetsTestValue = const FakeViewPadding(); expect(fakeWindow.lastUpdate, update);
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);
}); });
} }
void verifyThatTestWindowCanFakeProperty<WindowPropertyType>({
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 { class TestObserver with WidgetsBindingObserver {
List<Locale>? locales; List<Locale>? locales;
Locale? locale; Locale? locale;
@ -247,3 +275,15 @@ class TestObserver with WidgetsBindingObserver {
this.locales = locales; this.locales = locales;
} }
} }
class FakeSingletonWindow extends Fake implements SingletonFlutterWindow {
SemanticsUpdate? lastUpdate;
@override
PlatformDispatcher get platformDispatcher => PlatformDispatcher.instance;
@override
void updateSemantics(SemanticsUpdate update) {
lastUpdate = update;
}
}

View File

@ -120,9 +120,9 @@ https://flutter.dev/docs/testing/integration-tests#testing-on-firebase-test-lab
ViewConfiguration createViewConfiguration() { ViewConfiguration createViewConfiguration() {
final double devicePixelRatio = window.devicePixelRatio; final double devicePixelRatio = window.devicePixelRatio;
final Size size = _surfaceSize ?? window.physicalSize / devicePixelRatio; final Size size = _surfaceSize ?? window.physicalSize / devicePixelRatio;
return TestViewConfiguration.fromView( return TestViewConfiguration(
size: size, size: size,
view: window, window: window,
); );
} }