- Getting Started
- Code Review
- Platforms
- Configuration
- CI integrations
- Web Projects
- Developer Tools
- Get Notified
- API
This guide shows how to integrate Flutter golden tests with Screenshotbot for automated visual regression testing in CI/CD.
Instead of storing golden test images in your repository, this approach generates them during CI and uploads them to Screenshotbot for comparison and management. This keeps your repository clean while providing powerful visual testing capabilities.
See the complete working example here.
If you don't already have golden tests in your Flutter project, here's a simple golden test to get you started. If you already have golden tests, you can skip this step.
Create golden tests in your Flutter project using matchesGoldenFile():
testWidgets('MyHomePage golden test', (WidgetTester tester) async { await tester.pumpWidget(const MyApp()); await tester.pumpAndSettle(); await expectLater( find.byType(MyApp), matchesGoldenFile('goldens/home_page.png'), ); });
Add test/goldens to your .gitignore to prevent committing generated images. From this point onwards, the plan is to have all screenshots to be stored in Screenshotbot rather than in your git repository.
Make sure to rm -rf test/goldens to remove existing goldens too.
In your CI config:
If you run flutter test locally with the above setup, the tests would fail since the golden images aren't present.
To ensure golden tests work seamlessly in both local development and CI, configure your tests to always generate/update golden files instead of comparing against existing ones.
Create test/flutter_test_config.dart:
import 'dart:async'; import 'dart:io'; import 'dart:typed_data'; import 'package:flutter_test/flutter_test.dart'; class AlwaysUpdateGoldenFileComparator extends LocalFileComparator { AlwaysUpdateGoldenFileComparator(Uri testFile) : super(testFile); @override Future<bool> compare(Uint8List imageBytes, Uri golden) async { // Ensure the golden file goes in test/goldens final Uri testGoldensUri = Uri.parse('test/goldens/'); final String goldenPath = golden.path; // Remove 'goldens/' prefix if present and rebuild the path final String fileName = goldenPath.startsWith('goldens/') ? goldenPath.substring('goldens/'.length) : goldenPath; final Uri finalGoldenUri = testGoldensUri.resolve(fileName); final File goldenFile = File.fromUri(finalGoldenUri); await goldenFile.parent.create(recursive: true); await goldenFile.writeAsBytes(imageBytes); return true; // Always pass } @override Future<void> update(Uri golden, Uint8List imageBytes) async { // This method is called when --update-goldens is used // Use the same logic as compare() to ensure consistent paths await compare(imageBytes, golden); } } Future< void > testExecutable(FutureOr<void> Function() testMain) async { // Set up always-update golden file comparator for all tests goldenFileComparator = AlwaysUpdateGoldenFileComparator(Uri.parse('test/')); // Run the tests return testMain(); }
At this point, you will get email notifications each time your screenshots change.
You can then integrate with your Code Review platform of you choice (for example, GitHub), to get build statuses.
Sign up or contact us.