flutter-add-integration-test

oleh flutter

Mengonfigurasi Flutter Driver untuk interaksi aplikasi dan mengonversi aksi MCP menjadi tes integrasi permanen. Gunakan saat menambahkan pengujian integrasi ke proyek,…

npx skills add https://github.com/flutter/skills --skill flutter-add-integration-test

Implementing Flutter Integration Tests

Contents

Project Setup and Dependencies

Configure the project to support integration testing and Flutter Driver extensions.

  1. Add required development dependencies to pubspec.yaml:
    flutter pub add 'dev:integration_test:{"sdk":"flutter"}'
    flutter pub add 'dev:flutter_test:{"sdk":"flutter"}'
    
  2. Enable the Flutter Driver extension in your application entry point (typically lib/main.dart or a dedicated lib/main_test.dart):
    • Import package:flutter_driver/driver_extension.dart.
    • Call enableFlutterDriverExtension(); before runApp().
  3. Add Key parameters (e.g., ValueKey('login_button')) to critical widgets in the application code to ensure reliable targeting during tests.

Interactive Exploration via MCP

Use the Dart/Flutter MCP server tools to interactively explore and manipulate the application state before writing static tests.

  • Launch: Execute launch_app with target: "lib/main_test.dart" to start the application and acquire the DTD URI.
  • Inspect: Execute get_widget_tree to discover available Keys, Text nodes, and widget Types.
  • Interact: Execute tap, enter_text, and scroll to simulate user flows.
  • Wait: Always execute waitFor or verify state with get_health when navigating or triggering animations.
  • Troubleshoot Unmounted Widgets: If a widget is not found in the tree, it may be lazily loaded in a SliverList or ListView. Execute scroll or scrollIntoView to force the widget to mount before interacting with it.

Test Authoring Guidelines

Structure integration tests using the flutter_test API paradigm.

  • Create a dedicated integration_test/ directory at the project root.
  • Name all test files using the <name>_test.dart convention.
  • Initialize the binding by calling IntegrationTestWidgetsFlutterBinding.ensureInitialized(); at the start of main().
  • Load the application UI using await tester.pumpWidget(MyApp());.
  • Trigger frames and wait for animations to complete using await tester.pumpAndSettle(); after interactions like tester.tap().
  • Assert widget visibility using expect(find.byKey(ValueKey('foo')), findsOneWidget); or findsNothing.
  • Scroll to specific off-screen widgets using await tester.scrollUntilVisible(itemFinder, 500.0, scrollable: listFinder);.

Conditional Logic for Legacy flutter_driver:

  • If maintaining or migrating legacy flutter_driver tests, use driver.waitFor(), driver.waitForAbsent(), driver.tap(), and driver.scroll() instead of the WidgetTester APIs.

Execution and Profiling

Execute tests using the flutter drive command. Require a host driver script located in test_driver/integration_test.dart that calls integrationDriver().

Conditional Execution Targets:

  • If testing on Chrome: Launch chromedriver --port=4444 in a separate terminal, then run: flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart -d chrome
  • If testing headless web: Run with -d web-server.
  • If testing on Android (Local): Run flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart.
  • If testing on Firebase Test Lab (Android):
    1. Build debug APK: flutter build apk --debug
    2. Build test APK: ./gradlew app:assembleAndroidTest
    3. Upload both APKs to the Firebase Test Lab console.

Workflow: End-to-End Integration Testing

Copy and follow this checklist to implement and verify integration tests.

  • Task Progress: Setup
    • Add integration_test and flutter_test to pubspec.yaml.
    • Inject enableFlutterDriverExtension() into the app entry point.
    • Assign ValueKeys to target widgets.
  • Task Progress: Exploration
    • Run launch_app via MCP.
    • Map the widget tree using get_widget_tree.
    • Validate interaction paths using MCP tools (tap, enter_text).
  • Task Progress: Authoring
    • Create integration_test/app_test.dart.
    • Write test cases using WidgetTester APIs.
    • Create test_driver/integration_test.dart with integrationDriver().
  • Task Progress: Execution & Feedback Loop
    • Run flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart.
    • Feedback Loop: Review test output -> If PumpAndSettleTimedOutException occurs, check for infinite animations -> If widget not found, add scrollUntilVisible -> Re-run test until passing.

Examples

Standard Integration Test (integration_test/app_test.dart)

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';

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();

  group('End-to-end test', () {
    testWidgets('tap on the floating action button, verify counter', (tester) async {
      // Load app widget.
      await tester.pumpWidget(const MyApp());

      // Verify the counter starts at 0.
      expect(find.text('0'), findsOneWidget);

      // Find the floating action button to tap on.
      final fab = find.byKey(const ValueKey('increment'));

      // Emulate a tap on the floating action button.
      await tester.tap(fab);

      // Trigger a frame and wait for animations.
      await tester.pumpAndSettle();

      // Verify the counter increments by 1.
      expect(find.text('1'), findsOneWidget);
    });
  });
}

Host Driver Script (test_driver/integration_test.dart)

import 'package:integration_test/integration_test_driver.dart';

Future<void> main() => integrationDriver();

Performance Profiling Driver Script (test_driver/perf_driver.dart)

Use this driver script if you wrap your test actions in binding.traceAction() to capture performance metrics.

import 'package:flutter_driver/flutter_driver.dart' as driver;
import 'package:integration_test/integration_test_driver.dart';

Future<void> main() {
  return integrationDriver(
    responseDataCallback: (data) async {
      if (data != null) {
        final timeline = driver.Timeline.fromJson(
          data['scrolling_timeline'] as Map<String, dynamic>,
        );

        final summary = driver.TimelineSummary.summarize(timeline);

        await summary.writeTimelineToFile(
          'scrolling_timeline',
          pretty: true,
          includeSummary: true,
        );
      }
    },
  );
}

Lebih banyak skill dari flutter

dart-modern-features
flutter
Untuk menemukan kandidat untuk modernisasi:
flutter-fix-layout-issues
flutter
Memperbaiki kesalahan tata letak Flutter (overflow, batasan tak terbatas) menggunakan Dart dan alat Flutter MCP. Gunakan saat menangani "RenderFlex overflowed", "Vertical…
adding-release-notes
flutter
Menambahkan deskripsi perubahan yang terlihat oleh pengguna ke catatan rilis DevTools. Gunakan saat mendokumentasikan perbaikan, perbaikan bug, atau fitur baru di file NEXT_RELEASE_NOTES.md.
reviewing-devtools-prs
flutter
Alur kerja peninjauan PR khusus repositori DevTools yang menerapkan pedoman gaya DevTools dan pola peninjauan umum. Gunakan saat meninjau pull request di…
dart-use-primary-constructors
flutter
Bantu pengguna menulis konstruktor utama yang benar secara sintaksis dan semantik dalam Dart, serta migrasi/menggunakan sintaks konstruktor baru, sintaks titik koma badan kosong,…
code-documentation
flutter
Panduan untuk menulis dokumentasi kode yang efektif, termasuk docstrings, JSDoc, dartdoc, dan komentar implementasi. Gunakan keterampilan ini saat menulis kode baru, menambahkan…
api-review
flutter
Meninjau kode yang ditentukan terhadap pedoman API Design kanonik. Gunakan skill ini saat pengguna meminta tinjauan API atau untuk memeriksa kode terhadap desain API…
flutter-accessibility
flutter
Menerapkan standar aksesibilitas WCAG 2 dan EN 301 549 serta tata letak adaptif di aplikasi Flutter. Memberlakukan anotasi semantik, ukuran target ketuk (minimal 48x48 dp), dan rasio kontras teks (4,5:1 untuk teks kecil, 3:1 untuk teks besar) di platform seluler, web, dan desktop. Menyediakan logika keputusan untuk inisialisasi semantik web, pembungkusan widget interaktif, peralihan tata letak berdasarkan ukuran layar, serta penanganan input keyboard/mouse. Mencakup manajemen traversal fokus melalui FocusTraversalGroup dan...