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. 🙂

Discussion (3)

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
lakscastro profile image
Laks Castro

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
lakscastro profile image
Laks Castro • Edited on

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