Reputation: 10881
I have a Flutter widget which shows extra data depending on the screen size. Does anyone know a way of testing this widget on multiple different screen sizes?
I've had a look through the widget_tester source code but can't find anything.
Upvotes: 52
Views: 31389
Reputation: 1142
To test the UI in landscape mode you have to set the device size
tester.view.physicalSize = const Size(1179, 2556); // any landscape size
and at the end of the test you have to reset it on the normal size
tester.view.resetPhysicalSize();
ex:-
testWidgets('Test the widget in landscape', (WidgetTester tester) async {
tester.view.physicalSize = const Size(1179, 2556);
await tester.pumpWidget(sut);
await tester.pump();
tester.view.resetPhysicalSize();
});
Upvotes: 0
Reputation: 876
Since version 3.10.0, the window singleton is deprecated( https://docs.flutter.dev/release/breaking-changes/window-singleton). Therefore, the size must now be set as follows:
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets("foo", (tester) async {
tester.view.devicePixelRatio = 1.0;
tester.view.physicalSize = Size(800, 600);
// resets the screen to its original size after the test end
addTearDown(tester.view.resetPhysicalSize);
// TODO: do something
});
}
Upvotes: 19
Reputation: 17397
I would recommend to wrap testWidgets so you do not have to make changes to all your tests when you want to add a platform or size for screen. Here is a matrix that tests some sizes and platforms:
const List<Size> _testedSizes = [
Size(800, 600),
Size(600, 800),
];
void testWidgetInPlatformMatrix(
String description,
Future<void> Function(WidgetTester) callback,
) {
for (var size in _testedSizes) {
testWidgets(
'$description ($size)',
(widgetTester) async {
await widgetTester.binding.setSurfaceSize(size);
return callback(widgetTester);
},
variant: TargetPlatformVariant.mobile(),
);
}
}
then you'd use testWidgetInPlatformMatrix
instead of testWidgets
:
testWidgetInPlatformMatrix('Counter increments smoke test',
(WidgetTester tester) async {
//...
});
Upvotes: 0
Reputation: 2563
Currently the safest way is to use setSurfaceSize
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets("foo", (tester) async {
tester.binding.setSurfaceSize(Size(400, 400));
// reset
tester.binding.setSurfaceSize(null);
// continue
});
}
See here for related Github issue
Upvotes: 7
Reputation: 277537
You can specify custom surface size by using WidgetTester
The following code will run a test with a screen size of 42x42
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets("foo", (tester) async {
tester.binding.window.physicalSizeTestValue = Size(42, 42);
// resets the screen to its original size after the test end
addTearDown(tester.binding.window.clearPhysicalSizeTestValue);
// TODO: do something
});
}
Upvotes: 76
Reputation: 1272
You could try this widget to test your widgets changing screen size in realtime
Screen Size Test
https://pub.dev/packages/screen_size_test
Preview
Demo https://dartpad.dartlang.org/43d9c47a8bf031ce3ef2f6314c9dbd52
Code Sample
import 'package:screen_size_test/screen_size_test.dart';
...
MaterialApp(
title: 'Demo',
builder: (context, child) => ScreenSizeTest(
child: child,
),
home: Scaffold(
body: ListView(
children: List.generate(
20,
(index) => Container(
padding: EdgeInsets.all(10),
child: Placeholder(),
)),
),
),
)
Upvotes: 3
Reputation: 1424
There is a package called device_preview that can simulate your flutter app running on different devices.
Upvotes: 15
Reputation: 568
@rémi-rousselet's solution works perfectly!
In addition if you want to test an orientation change, try this:
const double PORTRAIT_WIDTH = 400.0;
const double PORTRAIT_HEIGHT = 800.0;
const double LANDSCAPE_WIDTH = PORTRAIT_HEIGHT;
const double LANDSCAPE_HEIGHT = PORTRAIT_WIDTH;
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
await binding.setSurfaceSize(Size(PORTRAIT_WIDTH, PORTRAIT_HEIGHT));
await tester.pumpWidget(MyWidget());
// test in portrait
await binding.setSurfaceSize(Size(LANDSCAPE_WIDTH, LANDSCAPE_HEIGHT));
await tester.pumpAndSettle();
// OrientationBuilder gets triggered
// test in landscape
Upvotes: 9
Reputation: 3138
Not sure why but solution of @rémi-rousselet didn't work for me. I've had to specify screen size using binding.window.physicalSizeTestValue
and binding.window.devicePixelRatioTestValue
so that output is fully deterministic
I've added a little bit more code for flutter beginners like me. Check this:
void main() {
final TestWidgetsFlutterBinding binding =
TestWidgetsFlutterBinding.ensureInitialized();
testWidgets("Basic layout test (mobile device)", (tester) async {
binding.window.physicalSizeTestValue = Size(400, 200);
binding.window.devicePixelRatioTestValue = 1.0;
await tester.pumpWidget(new MyApp());
expect(find.byType(MyHomePage), findsOneWidget);
// etc.
});
}
Upvotes: 39
Reputation: 10881
Although @Rémi Rousselet's answer was very helpful it didn't completely solve my problem. It turns out that I could just wrap my widget under test in a MediaQuery
widget and set the size.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
Widget makeTestableWidget({Widget child, Size size}) {
return MaterialApp(
home: MediaQuery(
data: MediaQueryData(size: size),
child: child,
),
);
}
testWidgets("tablet", (tester) async {
final testableWidget = makeTestableWidget(
child: WidgetUnderTest(),
size: Size(1024, 768),
);
...
});
testWidgets("phone", (tester) async {
final testableWidget = makeTestableWidget(
child: WidgetUnderTest(),
size: Size(375, 812),
);
...
});
}
Upvotes: 3