Jordan Davies
Jordan Davies

Reputation: 10881

How to test Flutter widgets on different screen sizes?

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

Answers (10)

Sanju Bhatt
Sanju Bhatt

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

MCB
MCB

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

Ced
Ced

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

Dominik Roszkowski
Dominik Roszkowski

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

R&#233;mi Rousselet
R&#233;mi Rousselet

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

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

enter image description here

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

Pegasis
Pegasis

Reputation: 1424

There is a package called device_preview that can simulate your flutter app running on different devices.

Upvotes: 15

Mark
Mark

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

VizGhar
VizGhar

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

Jordan Davies
Jordan Davies

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

Related Questions