Flutter Widget test cannot emulate different screen size properly
That is because of the font difference used by flutter test
and flutter run
.
Flutter's default font is Roboto
for Android if you did not change it other font.
- Default Android:
Roboto
font and for iOS:San Francisco
font - Customize https://flutter.dev/docs/cookbook/design/fonts
Either 1) or 2) these fonts are not available to flutter test
by default. Flutter test purposely uses a font called Ahem
which is made out of square blocks that you see on your screenshot.
This is a preview:
Ahem
font square are wayyy bigger than the normal that you are using. Therefore, it causes the RenderFlex overflow error
Solution
To achieve a near perfect emulation of your device in flutter test
you have to download the font data then load the exact font that you are using.
To load a font in widget test, you should do inside the testWidgets
function or setUp
:
final flamante = rootBundle.load('assets/fonts/Flamante-Roma-Medium.ttf'); await FontLoader('FlamanteRoma') ..addFont(flamante) ..load();
Then add this font to the ThemeData
before pumping the widget.
theme: ThemeData( fontFamily: 'FlamanteRoma', ),
The final test.dart code is:
import 'package:flutter/material.dart';import 'package:flutter/services.dart';import 'package:flutter_test/flutter_test.dart';import 'package:example/test/compare_test_size.dart';void main() { testWidgets( "Emulate real screen size", (WidgetTester tester) async { final flamante = rootBundle.load('assets/fonts/Flamante-Roma-Medium.ttf'); await FontLoader('FlamanteRoma') ..addFont(flamante) ..load(); // Adjust these to match your actual device screen specs final width = 411.4; final height = 797.7; tester.binding.window.devicePixelRatioTestValue = (2.625); tester.binding.window.textScaleFactorTestValue = (1.1); final dpi = tester.binding.window.devicePixelRatio; tester.binding.window.physicalSizeTestValue = Size(width * dpi, height * dpi); await tester.pumpWidget( MediaQuery( data: MediaQueryData(), child: MaterialApp( home: TextScaleComparaison(), theme: ThemeData( fontFamily: 'FlamanteRoma', ), ), ), ); await expectLater( find.byType(TextScaleComparaison), matchesGoldenFile("text.png"), ); }, );}
Now re generate the golden test and check the png. You will see real text, not boxes anymore:
test/test.png
And don't forget to add the same font in your main.dart
runApp( MaterialApp( home: TextScaleComparaison(), theme: ThemeData( fontFamily: 'FlamanteRoma', ), ), );
And also don't forget to update pubspec.yaml
and run flutter pub get
- family: FlamanteRoma fonts: - asset: assets/fonts/Flamante-Roma-Medium.ttf
As Curly already mentioned here, you can overwrite the tester.binding.window.textScaleFactorTestValue
with a lower value. 0.8
was working well for my used fonts, but depending on your setup, you might use even a lower value. In this way, you don't need to await the loading of your fonts in each test case.