I would like introduce you a simple manual about how take screenshot during integration tests in Flutter.
From Flutter 2.5.0 you can take screenshot in your integration tests by very simple way.
First if you didn't setup integration tests yet, setup it by this manual: https://flutter.dev/docs/cookbook/testing/integration/introduction
When you have already it, you can continue by this way:
1) Replace your test_driver/integration_test.dart by this code:
import 'dart:io';
import 'package:integration_test/integration_test_driver_extended.dart';
Future<void> main() async {
try {
await integrationDriver(
onScreenshot: (String screenshotName, List<int> screenshotBytes) async {
final File image = await File('screenshots/$screenshotName.png').create(recursive: true);
image.writeAsBytesSync(screenshotBytes);
return true;
},
);
} catch (e) {
print('Error occured: $e');
}
}
It add onScreenshot event handler into your integration tests and after take your screenshot it will save it into screenshots directory in your project. (This directory will be created when doesn't exists.)
2) Go into your integration_test/app_test.dart and add:
final binding = IntegrationTestWidgetsFlutterBinding();
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
This must be before all your testWidgets when tests are initialized.
3) Into your test add:
await binding.takeScreenshot('test-screenshot');
If you run your tests on Android device, you must also add convertFlutterSurfaceToImage()
function before takeScreenshot()
because there must be converted a Flutter surface into image:
await binding.convertFlutterSurfaceToImage();
await tester.pumpAndSettle();
await binding.takeScreenshot('test-screenshot');
For iOS or web you don't need this convert function.
4) You can create a simple helper function for take screenshot in various devices:
import 'dart:io';
import 'package:flutter/foundation.dart' show kIsWeb;
takeScreenshot(tester, binding) async {
if (kIsWeb) {
await binding.takeScreenshot('test-screenshot');
return;
} else if (Platform.isAndroid) {
await binding.convertFlutterSurfaceToImage();
await tester.pumpAndSettle();
}
await binding.takeScreenshot('test-screenshot');
}
So your tests can finally looks like this:
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:example_integration_test_screenshot/main.dart';
import 'helper.dart';
void main() {
group('Test App', () {
final binding = IntegrationTestWidgetsFlutterBinding();
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('Test with take screenshot', (tester) async {
await tester.pumpWidget(MyApp());
await tester.pumpAndSettle();
await tester.tap(find.byIcon(Icons.add));
await tester.tap(find.byIcon(Icons.add));
await tester.tap(find.byIcon(Icons.add));
await tester.pumpAndSettle();
await takeScreenshot(tester, binding);
});
});
}
Conclusion
So that is all. After run of your tests you can see a generated screenshot in screenshots/test-screenshot.png
file:
I hope that this article was useful and you can support me by ❤️ or some comments below. 🙂
Top comments (7)
Having created a sample project following instructions here.
The integration test works, and produces a screenshot. However, adding a directory named
example
to the project, makes everything fail. This is only, and very specifically the directory namedexample
.I reported this in detail in github.com/flutter/flutter/issues/... .
But I am wondering if anyone else is having an issue with this.
This may seem innocent, but it prevents library packages to include examples, which by dart convention should be in directory named
example
.What command do you use to run these tests? I'm running as
flutter test integration_test
but it doesn't work, the onScreenshot callback is not called at allok. I fixed by using
drive
insteadtest
command:flutter drive --driver=test_driver/integration_driver.dart --target=integration_test/app_test.dart
How to fix it?
Error: The argument type 'Future Function(String, List)' can't be assigned to the parameter type 'Future Function(String, List, [Map?])?'.
Just add an optional parameter:
You can now pass an optional list of arguments when taking a screenshot. They must be json serializable.
this will only work for a single image.
the function revertFlutterImage is missing to make multiple images.
see: github.com/flutter/flutter/issues/...
Any complete source code to see how to take screenshots for a full project ?
Would this work to take screenshots to upload to App Store Connect or Google Play ?