DEV Community

Martin Jablečník
Martin Jablečník

Posted on

Take screenshot during Flutter integration tests

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');
  }
}
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

This must be before all your testWidgets when tests are initialized.

3) Into your test add:

await binding.takeScreenshot('test-screenshot');
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode

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');
}
Enter fullscreen mode Exit fullscreen mode

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);
    });
  });
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

So that is all. After run of your tests you can see a generated screenshot in screenshots/test-screenshot.png file:
Screenshot

I hope that this article was useful and you can support me by ❤️ or some comments below. 🙂

Top comments (7)

Collapse
 
mzimmerm profile image
Milan Zimmermann

Having created a sample project following instructions here.

  flutter drive --driver=test_driver/integration_test.dart --target=integration_test/screenshot_test.dart
Enter fullscreen mode Exit fullscreen mode

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 named example.

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.

Collapse
 
alexrintt profile image
Alex Rintt

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 all

Collapse
 
alexrintt profile image
Alex Rintt • Edited

ok. I fixed by using drive instead test command: flutter drive --driver=test_driver/integration_driver.dart --target=integration_test/app_test.dart

Collapse
 
tankun profile image
tan

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?])?'.

  • 'Future' is from 'dart:async'.
  • 'List' is from 'dart:core'.
  • 'Map' is from 'dart:core'.
  • 'Object' is from 'dart:core'. onScreenshot: (String screenshotName, List screenshotBytes) async {
Collapse
 
ordinarydev profile image
Ivan

Just add an optional parameter:

onScreenshot: (String screenshotName, List<int> screenshotBytes, [Map<String, Object?>? args]) async {}
Enter fullscreen mode Exit fullscreen mode

You can now pass an optional list of arguments when taking a screenshot. They must be json serializable.

Collapse
 
hansbak_98 profile image
Hans Bakker

this will only work for a single image.
the function revertFlutterImage is missing to make multiple images.
see: github.com/flutter/flutter/issues/...

Collapse
 
isdoiaba profile image
Isidor

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 ?