Do you see the difference? — Flutter Snapshot test

TL;DR Flutter provides a reliable and easy way to test custom widgets and painters using snapshot/golden files testing.

The Issue with Testing Custom Painted Widgets

Widget tests are an amazing way to verify if your Widgets are working correctly. Unfortunately, they don’t work so well when you just paint your own widgets with CustomPainter .

Golden Files/Snapshots to the rescue!

Golden files are just snapshots (PNGs) that are created from a widget and compared when testing.

‘nuff said —Show me the Code!

Let’s test the following widget:

class MyWidget extends StatelessWidget {
const MyWidget(this.radius, {Key key}) : super(key: key);

final double radius;

@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8),
child: Container(
decoration: BoxDecoration(
border: Border.all(
width: 12,
color: Color(0xFF01579B),
),
borderRadius: BorderRadius.all(Radius.circular(radius)),
),
child: FlutterLogo(),
),
);
}
}

The testing code would look like this:

testWidgets('Golden file testing', (tester) async {
// RepaintBoundary is needed to optimize the png
await tester.pumpWidget(RepaintBoundary(child: MyWidget(0)));

await tester.pumpAndSettle();

await expectLater(
find.byType(RepaintBoundary),
matchesGoldenFile('golden-file.png'),
);
});

Next, you need to first create the golden files with the command

flutter test --update-goldens

It will create a png that will be used for testing — make sure you commit that png to your version control.


And that’s all!. To verify if the test works properly just change the radius to anything greater than 0:

await tester.pumpWidget(RepaintBoundary(child: MyWidget(10)));

And run the test with flutter test .


When not to use Golden Files Testing

Those tests should be used sporadically because

  • when they fail you need to manually compare the pngs (I use imagemagick)
  • they take much more space on your version control system
  • changing even a single pixel will make the tests to fail

You can find the entire example plus png’s size optimization in this gist.