Fixing the boxes in screenshot tests in Flutter
There are many packages to make screenshot tests in Flutter. I've been using the first-party Flutter tool. See https://api.flutter.dev/flutter/flutter_test/matchesGoldenFile.html.
Basic usage
As explained, it's pretty straightforward. You write your expectation as:
await expectLater(find.byType(MyWidget), matchesGoldenFile('goldens/my_widget.png'));
Then you generate the golden by running flutter test --update-goldens
.
To run your test and check with the goldens, simply run flutter test
. If there is a difference between the golden and the test screenshot, it'll output the golden, test screenshot and the diff in test/failures/
.
Rendering text
One issue though is that all the text is represented by boxes.
This is actually a feature (no really) of Flutter. As explained at https://api.flutter.dev/flutter/flutter_test/GoldenFileComparator-class.html#including-fonts, they do this because each platform will have its own Font, and so the screenshots would inevitably be slightly different based on which platform the tests are run.
To make it render proper text, here's what to do:
- Download Roboto from https://fonts.google.com/specimen/Roboto.
- Create a subfolder assets/fonts.
- Extract Roboto.zip and move Robot-Regular.ttf to assets/fonts.
- In pubspec.yaml, add the following:
flutter:
assets:
- assets/fonts/
- In your unit test, before expecting the goldens, load the Font:
final font = rootBundle.load('assets/fonts/Roboto-Regular.ttf');
final fontLoader = FontLoader('Roboto')..addFont(font);
await fontLoader.load();
- Update the goldens:
flutter test --update-goldens
.
In this screenshot you can see that everything, except for the Korean text, renders correctly. That's because the Roboto font I downloaded does not include Korean characters. To work around this, one can download NotoSans from Google Fonts, but still load it as the "Roboto" family. Then it'll use the NotoSans font for the screenshot test.
On a real device, I guess the Roboto font on the system includes Asian characters, which is why it works there.