snaptest 0.2.1 copy "snaptest: ^0.2.1" to clipboard
snaptest: ^0.2.1 copied to clipboard

Snap photos in your widget tests.

Snaptest #

Code Coverage melos lints by lintervention

See what your widgets look like during testing.

Title banner

Snaptest is simple: call snap() in any widget test to save a screenshot of what's currently on screen. Perfect for debugging, documentation, and visual regression testing.

Installation #

dart pub add dev:snaptest

Create a flutter_test_config.dart file in your test/ directory to ensure consistent font rendering:

import 'dart:async';
import 'package:snaptest/snaptest.dart';

Future<void> testExecutable(FutureOr<void> Function() testMain) async {
  // Load fonts before all tests to prevent side effects
  await loadFontsAndIcons();

  // Optional: Set global settings for all tests
  SnaptestSettings.global = SnaptestSettings(
    devices: [
      Devices.ios.iPhone16Pro,
    ],
  );

  await testMain();
}

Why this matters: Flutter can't unload fonts once loaded, so without this setup, your snap() calls might influence your test layout later and produce different results depending on test execution order.

The Basics πŸš€ #

Just call snap() to see your screen #

Add one line to any widget test to see what it looks like:

import 'package:flutter_test/flutter_test.dart';
import 'package:snaptest/snaptest.dart';

testWidgets('My widget test', (tester) async {
  await tester.pumpWidget(const MaterialApp(home: MyPage()));
  
  // That's it! Screenshot saved to .snaptest/
  await snap();
});

The screenshot gets saved as a PNG file in .snaptest/ using your test name. Great for debugging failing tests or documenting what your widgets actually look like.

Configure your .gitignore #

**/.snaptest/     # Screenshots (usually not committed)

Level Up: Real Rendering πŸ“± #

By default, snaptest creates simplified screenshots (blocked text, no images/shadows) for consistency. But you can enable real rendering to see exactly what users see:

testWidgets('Real rendering example', (tester) async {
  await tester.pumpWidget(const MaterialApp(home: MyPage()));
  
  await snap(
    settings: SnaptestSettings.rendered([
      Devices.ios.iPhone16Pro,
      Devices.android.samsungGalaxyS20,
    ]),
  );
});

This creates beautiful screenshots with:

  • βœ… Real text rendering
  • βœ… Actual images
  • βœ… Shadows and effects
  • βœ… Device frames around the content
  • βœ… Multiple device sizes
  • βœ… Multiple orientations (portrait and landscape)

Perfect for documentation, design reviews, or showing stakeholders what the app actually looks like.

Level Up: Golden File Testing 🎯 #

Want automated visual regression testing? Enable golden comparison to catch unintended UI changes:

testWidgets('Golden comparison test', (tester) async {
  await tester.pumpWidget(const MaterialApp(home: LoginScreen()));
  
  await snap(
    matchToGolden: true,
    settings: SnaptestSettings.rendered([Devices.ios.iPhone16Pro]),
  );
});

This does both:

  1. Saves a beautiful screenshot with real rendering and device frames to .snaptest/
  2. Compares against golden files to fail the test if UI changes unexpectedly

When golden tests fail due to intentional changes, update them:

flutter test --update-goldens

All the Options πŸ› οΈ #

Multiple screenshots per test #

testWidgets('User flow', (tester) async {
  await tester.pumpWidget(const MaterialApp(home: MyPage()));
  await snap('initial_state');
  
  await tester.tap(find.byType(FloatingActionButton));
  await tester.pumpAndSettle();
  await snap('after_tap');
});

Capture specific widgets #

await snap(from: find.byKey(const Key('my-card')));

Global settings for all tests #

void main() {
  setUpAll(() {
    SnaptestSettings.global = SnaptestSettings.rendered([
      Devices.ios.iPhone16Pro,
    ]);
  });
  
  // All snap() calls now use iPhone 16 Pro with real rendering
}

Or create a flutter_test_config.dart file to set the global settings, as described in the Installation section.

Dedicated screenshot tests with snapTest #

For tests specifically designed for screenshots, use snapTest instead of testWidgets. It automatically:

  • Adds the snaptest tag for easy filtering
  • Applies custom settings for the entire test
import 'package:flutter/material.dart';
import 'package:snaptest/snaptest.dart';

snapTest('Login screen looks correct', (tester) async {
  await tester.pumpWidget(const MaterialApp(home: LoginScreen()));
  await snap(); // Uses the settings from snapTest
});

snapTest(
  'Multi-device homepage',
  (tester) async {
    await tester.pumpWidget(const MaterialApp(home: HomePage()));
    await snap('initial');
    
    await tester.tap(find.byIcon(Icons.menu));
    await tester.pumpAndSettle();
    await snap('menu_open');
  },
  settings: SnaptestSettings.rendered([
    Devices.ios.iPhone16Pro,
    Devices.android.samsungGalaxyS20,
  ]),
);

Run only screenshot tests:

flutter test --tags snaptest

Or exclude them from regular test runs:

flutter test --exclude-tags snaptest

Test multiple orientations #

testWidgets('Responsive design test', (tester) async {
  await tester.pumpWidget(const MaterialApp(home: MyPage()));
  
  await snap(
    settings: SnaptestSettings.rendered(
      devices: [Devices.ios.iPhone16Pro],
      orientations: {
        Orientation.portrait,
        Orientation.landscape,
      },
    ),
  );
});

This automatically creates separate screenshots for each orientation:

  • my_page_iPhone16Pro_portrait.png
  • my_page_iPhone16Pro_landscape.png

All snap() parameters #

await snap(
  name: 'custom_name',           // Custom filename
  from: find.byKey(key),         // Specific widget to capture
  settings: SnaptestSettings(),  // Override global settings
  goldenPrefix: 'goldens/',      // Golden files directory (default: 'goldens/')
  matchToGolden: true,           // Enable golden file comparison
);

Settings Reference πŸ“‹ #

SnaptestSettings options: #

  • devices: List of devices to test on (default: [WidgetTesterDevice()])
  • orientations: Set of orientations to test (default: {Orientation.portrait})
  • blockText: Whether to block text rendering for consistency (default: true)
  • renderImages: Whether to render actual images (default: false)
  • renderShadows: Whether to render shadows (default: false)
  • includeDeviceFrame: Whether to include device frame around content (default: false)
  • pathPrefix: Directory where screenshots are saved (default: '.snaptest/')

Convenience constructors: #

  • SnaptestSettings(): Default settings - blocked text, no images/shadows/frames
  • SnaptestSettings.rendered(devices): Real rendering - actual text, images, shadows, and device frames

Helper Scripts πŸ”§ #

Clean all screenshots:

dart run snaptest:clean

Clean screenshots from a custom directory:

dart run snaptest:clean my_custom_dir

Assemble screenshots into a single directory:

dart run snaptest:assemble

Assemble screenshots from a custom directory:

dart run snaptest:assemble my_custom_dir

Custom Screenshot Directories #

You can customize where screenshots are saved by setting the pathPrefix in your settings:

testWidgets('Custom directory example', (tester) async {
  await tester.pumpWidget(const MaterialApp(home: MyPage()));
  
  await snap(
    settings: SnaptestSettings(
      pathPrefix: 'my_screenshots/',
      // ... other settings
    ),
  );
});

The helper scripts will work with any custom directory name you specify.

Font Limitations ⚠️ #

Due to Flutter's test environment limitations:

  • iOS system fonts are replaced with Roboto for consistency
  • Google Fonts only work if bundled as local assets (not fetched remotely)
  • Custom fonts must be included in your pubspec.yaml

This ensures consistent screenshots across environments, but may differ slightly from your actual app.