Unit tests are great for logic, and widget tests are perfect for individual components, but neither tells you if your app actually works when a user taps a button and navigates through three screens. That’s where integration testing comes in. In this guide, I’m going to walk you through writing flutter integration tests step by step so you can stop worrying about critical regressions in your production builds.

In my experience, the biggest hurdle isn’t writing the test code—it’s the setup. Whether you are migrating from a Detox React Native testing tutorial approach or starting fresh with Dart, the mental model is the same: simulate a real user interaction in a real environment.

Prerequisites

Step 1: Adding the Integration Test Dependency

Integration tests are now supported by a first-party package. You don’t need external third-party frameworks for basic E2E flow. First, add the integration_test package to your pubspec.yaml under dev_dependencies:

dev_dependencies:
  flutter_test:
    sdk: flutter
  integration_test:
    sdk: flutter

After adding this, run flutter pub get in your terminal to fetch the package.

Step 2: Creating the Test Directory Structure

Integration tests live outside the standard test/ folder because they are compiled into the app itself. You need to create a new top-level directory called integration_test/. Inside this folder, create a file named app_test.dart.

Your directory should look like this:
/my_flutter_app/integration_test/app_test.dart

Step 3: Writing Your First Integration Test

Now we get to the core of writing flutter integration tests step by step. We need to initialize the integration test driver and then write a test that interacts with the UI. Here is a complete example of a login flow test:

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:my_app/main.dart' as app;

void main() {
  // 1. Initialize the integration test driver
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();

  group('End-to-End Login Flow', () {
    testWidgets('User can login successfully', (WidgetTester tester) async {
      // 2. Start the app
      app.main();
      await tester.pumpAndSettle();

      // 3. Find elements and enter text
      await tester.enterText(find.byKey(const Key('email_field')), 'test@ajmani.dev');
      await tester.enterText(find.byKey(const Key('password_field')), 'password123');

      // 4. Tap the login button
      await tester.tap(find.byType(ElevatedButton));
      
      // 5. Wait for the transition to the home screen
      await tester.pumpAndSettle();

      // 6. Verify the home screen is visible
      expect(find.text('Welcome Home'), findsOneWidget);
    });
  });
}

As shown in the image below, the key is to use pumpAndSettle(). Unlike widget tests, integration tests deal with real animations and network delays, so you must wait for the UI to stabilize.

Visual representation of the Flutter Integration Test flow showing app launch, interaction, and verification
Visual representation of the Flutter Integration Test flow showing app launch, interaction, and verification

Step 4: Running the Tests

You cannot run integration tests using the standard flutter test command. You must use the flutter drive command or the newer flutter test integration_test command.

Run this in your terminal:

flutter test integration_test/app_test.dart

If you are targeting a specific device, use flutter test integration_test/app_test.dart -d <DEVICE_ID>. I highly recommend testing on a physical device to catch performance stutters that emulators often miss.

Pro Tips for Robust Integration Tests

Troubleshooting Common Issues

Issue Likely Cause Solution
Test times out Network request taking too long Increase timeout or mock the API response.
Widget not found Animation still running Add another await tester.pumpAndSettle().
App crashes on start Missing IntegrationTestWidgetsFlutterBinding Ensure the binding is initialized at the top of main().

What’s Next?

Now that you’ve mastered writing flutter integration tests step by step, the next step is to implement a testing pyramid. Balance your project with 70% unit tests, 20% widget tests, and 10% integration tests. This ensures your pipeline remains fast while still providing high confidence in your releases.