golden_test 2.0.1
golden_test: ^2.0.1 copied to clipboard
A utility Flutter plugin for writing golden tests that streamlines adding golden tests to your project
golden_test #
golden_test is a lightweight, zero-dependency, opinionated wrapper around Flutter's golden testing APIs that dramatically reduces boilerplate while adding first-class support for themes, locales, and multiple devices. It focuses on real-world UI scenarios, making golden tests easier to write, scale, and maintain compared to lower-level solutions.
Introduction #
When a UI change is detected, golden_test generates a visual diff so you can instantly see what changed:
Left: original golden — Center: diff overlay — Right: updated golden (via Image Diff Android Studio plugin)
Supported Features:
- Multiple device support
- Dark mode support
- Localized Goldens
AI Agent Skills #
If you write code with an AI agent, this package ships three
Agent Skills that teach it to use
golden_test properly — how to wire up flutter_test_config.dart, what to
cover for a component versus a screen, and how to read a failing golden.
Install them into your project with:
dart run skills@ get
That scans your dependencies, offers the skills it finds, and installs the
ones you pick into .agents/skills/. Re-run it after upgrading the package
to pick up changes.
| Skill | Use it for |
|---|---|
golden_test-setup |
One-time setup: the dependency and a flutter_test_config.dart wired to your app's real themes, locales and fonts. Run this first. |
golden_test-widget |
Goldens for widgets and design-system components in isolation. |
golden_test-route |
Goldens for full screens — every state a screen can render. |
They cover more than the mechanics: which test axes are worth their cost, how to derive edge cases from branches in your own formatting code, when a failing golden is an app bug rather than a stale image, and when not to write a golden at all.
Agents that read skills from a different directory can use the files
directly — they're plain Markdown under
skills/
in this repository, and copying a skill folder into wherever your agent
looks works just as well.
Quick Start #
1. Add the package
dart pub add golden_test --dev
2. Write your first golden test
import 'package:flutter_test/flutter_test.dart';
import 'package:golden_test/golden_test.dart';
void main() {
goldenTest(
name: 'My widget',
builder: (_) => const MyWidget(),
);
}
3. Generate the golden file
flutter test --update-goldens
Your first golden image will be generated automatically.
Going further
Add per-test locale, device, and theme overrides (these can also be configured globally — see Localized Goldens, Device Configuration, and Setup Theme):
goldenTest(
name: 'ExampleScreen',
builder: (_) => const ExampleScreen(),
supportMultipleDevices: true,
supportedLocales: [
Locale('en'),
Locale('es'),
],
supportedDevices: [Device.iphone15Pro(), Device.ipadPro12()],
);
This single call automatically generates golden files across all configured devices, themes, and languages:
| English | Spanish | |
|---|---|---|
| Light iPhone 15 Pro | ![]() |
![]() |
| Dark iPhone 15 Pro | ![]() |
![]() |
| Light iPad Pro 12 | ![]() |
![]() |
| Dark iPad Pro 12 | ![]() |
![]() |
Device Configuration #
The package provides a flexible three-level device configuration system that allows you to set defaults globally, enable multi-device testing, and override settings per test.
Configuration Levels (Priority Order)
- Per-test override (highest priority): Explicitly specify devices for a specific test
- Multi-device mode: Enable testing across multiple devices
- Global default (lowest priority): Set a default device for all tests
Default Single Device
By default, tests run on iPhone 15 Pro. You can change the global default device for all tests:
goldenTestDefaultDevices = [Device.pixel9ProXL()]; // Your desired target device/devices
Now all tests automatically use this device without any additional parameters:
goldenTest(
name: 'Example Page',
builder: (_) => ExamplePage(),
); // Runs on Pixel 9 Pro XL
Multi-Device Testing
Configure a separate list of devices for comprehensive multi-device testing:
goldenTestSupportedDevices = [
Device.iphone15Pro(),
Device.pixel9ProXL(),
Device.ipadPro12(),
];
Enable multi-device testing per test:
goldenTest(
name: 'Example Page',
supportMultipleDevices: true,
builder: (_) => ExamplePage(),
); // Runs on all 3 devices
Or enable it globally for all tests:
goldenTestSupportMultipleDevices = true;
Per-Test Override
Override device configuration for specific tests (ignores all global settings):
goldenTest(
name: 'Example Page',
supportedDevices: [Device.browser()],
builder: (_) => ExamplePage(),
); // Runs only on browser device
Supported Devices
The following devices are configured for testing, but you can always create your custom one using the Device class.
Device.noInsets() - a baseline device without insets
Device.iphone15Pro() - simulates the iPhone 15 Pro
Device.pixel9ProXL() - simulates the Pixel 9 Pro XL
Device.ipadPro12() - simulates the iPad Pro 12
Device.browser() - simulates a generic web browser
Localized Goldens #
Golden tests support multiple locales to verify the app's appearance and behavior across different languages. The list of supported locales and localization delegates can be modified based on the app's specific needs.
By default plugin is set to support en_US locales. To add more locales supported for all tests modify the goldenTestSupportedLocales list i.e:
goldenTestSupportedLocales = [
const Locale('pl'),
const Locale('en'),
];
or specify locales in specific tests you want to run it for multiple locales.
goldenTest(
name: 'Example Page',
builder: (_) => ExamplePage(),
supportedLocales: [
const Locale('pl'),
const Locale('en'),
],
);
Localization Delegates
To support additional localizations, add your app's delegates to the goldenTestLocalizationsDelegates list:
goldenTestLocalizationsDelegates = [YourAppLocalizations.delegate];
GlobalMaterialLocalizations, GlobalWidgetsLocalizations and GlobalCupertinoLocalizations are added for you, so there is no need to list them or import them. Delegates you provide are resolved first, so you can still override any of them.
or per specific test:
goldenTest(
name: 'Example Page',
builder: (_) => ExamplePage(),
supportedLocales: [
const Locale('pl'),
const Locale('en'),
],
localizationsDelegates: [YourAppLocalizations.delegate],
);
Using intl
If your project supports localization using the intl package and your default locales are not en_US or you want to support multiple localizations you need to provide addtional configuration especially for intl. It's because intl has hardcoded system locales (Intl.systemLocales) to en_US while it's need to be changed per test. You can do it adding this code to your flutter config file:
globalSetup = (locale) async => Intl.defaultLocale = locale.languageCode;
Custom fonts
If your project support any custom font you need to register it and load it for all of its associated assets into the Flutter engine, making the font available to the current application. Every font family need to be loaded once per font loader.
Example code:
Future<void> setupFonts() async {
TestWidgetsFlutterBinding.ensureInitialized();
await (FontLoader('Roboto')..addFont(rootBundle.load('assets/fonts/Roboto-Regular.ttf'))).load();
}
If your project use Google Fonts package you need to find .otf or .ttr file for the font you're using and provide it directly as a asset into your application.
Setup Theme #
To setup themes for you app you need to set them using the configuration:
goldenTestThemeInTests = yourThemeData;
goldenTestDarkThemeInTests = yourThemeDataDark;
If theme is not set it will use basic ThemeData() set in default configuration.
Dark Theme #
Golden Test allows you to run tests for both light and dark modes, enabling visual testing of your app across different theme settings. By default tests run for both themes. To disable dark mode tests, modify the goldenTestSupportedThemes list:
goldenTestSupportedThemes = [Brightness.light]
You can also configure each test you run to specify supported themes:
goldenTest(
name: 'Example Page',
builder: (_) => ExamplePage(),
supportedThemes: [Brightness.light, Brightness.dark],
);
Text Scale (Accessibility) #
Golden tests support multiple text scale factors to catch layout regressions at large accessibility font sizes. The list of supported scales can be modified globally or per test. By default tests run at 1.0 only (goldenTestSupportedTextScales = [1.0]).
To add text-scale coverage for all tests:
goldenTestSupportedTextScales = [1.0, 2.0];
Or specify scales for a specific test:
goldenTest(
name: 'Example Page',
builder: (_) => ExamplePage(),
supportedTextScales: [1.0, 2.0],
);
Platform presets
Use [AndroidFontScale] / [IosDynamicTypeScale] .value, [androidAccessibilityTextScalePresets], [iosAccessibilityTextScalePresets], or any custom double value:
goldenTest(
name: 'Example Page',
builder: (_) => ExamplePage(),
supportedTextScales: [
1.0,
1.5,
AndroidFontScale.extraLarge.value,
...iosAccessibilityTextScalePresets,
],
);
Global Setup Callback #
The globalSetup callback allows you to define project-specific configurations, such as disabling animations or setting a default locale for tests.
globalSetup = (_) async => duringTestExecution = true;
Network Image Stub #
Widgets that load images over the network (Image.network, FadeInImage with a NetworkImage, DecoratedBox with a NetworkImage) would otherwise time out or produce flaky goldens, since there's no real network during tests. By default, Golden Test intercepts these requests and resolves them with a placeholder image, so goldens stay deterministic.
The placeholder is deliberately visible rather than transparent or 1×1. An app that handles image load failures gracefully renders an empty box or nothing at all, so a golden taken without stubbing is indistinguishable from a layout that never had an image — the placeholder marks the spot and shows how much space the image takes.
This covers every widget that paints through a NetworkImage. Other dart:io HTTP traffic is left alone — flutter_test's own mock client keeps answering those requests with a 400, so a repository call fired from the widget tree behaves exactly as it did before.
Disable this globally if needed:
goldenTestStubNetworkImages = false;
Set that if you already stub network images yourself. Golden Test installs its stub before each test body runs, so a debugNetworkImageHttpClientProvider or HttpOverrides assigned in flutter_test_config.dart would otherwise be superseded. Stubs installed inside globalSetup or a test's setup run after Golden Test's and still take precedence, so those need no change.
Or override the stub image:
goldenTestNetworkImageStubPng = myPlaceholderPngBytes;
CachedNetworkImage support #
The cached_network_image package doesn't go through NetworkImage, so the stub above doesn't cover it — it fetches through flutter_cache_manager, which relies on SQLite and path_provider, neither of which work inside Flutter's fake-async test zone. A CachedNetworkImage in a golden test doesn't fail, it hangs, until the run times out as did not complete.
Fixing that means depending on cached_network_image and flutter_cache_manager. Golden Test has no dependencies of its own and isn't going to add three for a package most projects don't use, so the support lives in a companion package instead:
dev_dependencies:
golden_test: ^2.0.0
golden_test_cached_network_image: ^1.0.0
// flutter_test_config.dart
import 'package:golden_test_cached_network_image/golden_test_cached_network_image.dart';
Future<void> testExecutable(FutureOr<void> Function() testMain) async {
...
setupGoldenTestCachedNetworkImage();
return testMain();
}
Every CachedNetworkImage then resolves to the same placeholder as Image.network. See golden_test_cached_network_image for the custom-cache-manager hook and the full list of caveats.
Other image loaders #
Any package that loads images through its own machinery — a cache manager, a custom ImageProvider, a bespoke HTTP client — is out of reach of the NetworkImage stub, and registers itself the same way golden_test_cached_network_image does:
goldenTestImageLoaderSetups.add(() {
SomePackage.imageLoader = MyInMemoryLoader();
});
Each callback runs once per test, before the widget is built, so build fresh instances inside it rather than capturing one. It's a list, so several packages can register without clobbering each other.
Golden File Organization #
Golden Test allows you to organize golden files into custom subdirectories per test, which is particularly useful when managing golden tests across multiple apps or design systems.
Custom Subdirectory #
By default, golden files are stored in the goldens directory with the following structure:
goldens/
├── en/
│ ├── light/
│ │ └── MyWidget.png
│ └── dark/
│ └── MyWidget.png
You can add a custom subdirectory after goldens by using the subdirectory parameter:
goldenTest(
name: 'Example Page',
builder: (_) => ExamplePage(),
subdirectory: 'app1',
);
This will create golden files in:
goldens/
├── app1/
│ ├── en/
│ │ ├── light/
│ │ │ └── Example Page.png
│ │ └── dark/
│ │ └── Example Page.png
This is useful for scenarios like:
- Managing multiple apps with different design tokens:
goldenTest( name: 'Button', builder: (_) => MyButton(), subdirectory: 'app1', ); - Organizing by feature or design system:
goldenTest( name: 'Component', builder: (_) => MyComponent(), subdirectory: 'design_system/v2', ); - Separating different test suites:
goldenTest( name: 'Legacy Widget', builder: (_) => LegacyWidget(), subdirectory: 'legacy', );
Difference Tolerance #
Difference tolerance for golden tests can help manage acceptable visual differences between the reference images and the current UI output. This is particularly useful for allowing small variations, such as those caused by anti-aliasing or minor platform rendering differences.
Example - to achieve tolerance of 0.01% call:
goldenTestDifferenceTolerance(0.01);







