skills/flutter-integration-tests/SKILL.md
Author reliable Flutter integration tests that run with `flutter test -d flutter-tester`, especially in apps using GetX navigation and rinf-style async bridges. Use this when creating or editing `integration_test/*.dart` and avoiding deadlocks matters. [skill-hash:9c7d2f1]
npx skillsauth add robertmsale/.codex flutter-integration-testsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use this skill when authoring or editing integration_test/*.dart for Flutter apps that:
flutter test, not flutter driveflutter-testerRun a single integration test file with:
flutter test \
--dart-define=TEST_BASE_URL=http://localhost:<PORT> \
-d flutter-tester \
integration_test/<test_file>.dart
Rules:
--dart-define=... over prefixing the command with env vars.TEST_BASE_URL.Keep three categories separate:
Get.toNamed(...)goToRoute(...)tester.tap(...)tester.enterText(...)tester.drag(...)tester.pump(...)Most deadlocks happen when category 2 is awaited like category 1.
Do not await Get.toNamed(...) or a route helper that forwards that future unless the test explicitly needs the pop result.
Bad:
await goToRoute(AppRoutes.settings);
Good:
goToRoute(AppRoutes.settings);
await tester.pump();
await _pumpUntil(
tester,
condition: () => Get.currentRoute == AppRoutes.settings,
timeout: const Duration(seconds: 2),
reason: 'settings route did not open',
);
Why:
Get.toNamed(...) resolves when the pushed route is popped, not when it appears.tester.runAsync(...)Use tester.runAsync(...) only for external async work that does not depend on pumping frames.
Good uses:
Bad uses:
pumpAndSettle()Use explicit bounded waits for:
Avoid defaulting to pumpAndSettle() in apps with:
await tester.runAsync(() async {
await ensureBridgeInitialized();
await configureConnectionSettings();
await loginAsTestUser();
});
await tester.pumpWidget(const MyApp());
await tester.pump();
goToRoute(detailRoute);
await tester.pump();
await _pumpUntil(
tester,
condition: () => Get.currentRoute == detailRoute,
timeout: const Duration(seconds: 2),
reason: 'detail route did not open',
);
await tester.tap(find.text('Save'));
await tester.pump();
await _pumpUntil(
tester,
condition: () => find.text('Saved').evaluate().isNotEmpty,
timeout: const Duration(seconds: 2),
reason: 'save confirmation did not appear',
);
If a future may only complete while the app keeps processing frames, use a helper that pumps while waiting, such as the repo's pumpUntilDone(...) / pumpUntilValue(...) style helpers.
If the repo has helpers like goToRoute(...), inspect what they return.
If they forward Get.toNamed(...), treat them as push-result futures:
Only await them when asserting the pop result.
For apps with rinf-style runtime setup:
If a future depends on bridge messages or UI-driven listeners, a naked await may deadlock. Use a helper that keeps pumping the test loop.
If signals change, rinf gen needs to run in order to generate the bindings. These must be committed to source control if they change.
Changes to rust code require cargo build inside the <flutter project root>/native/hub before running tests so the
Reset state aggressively between tests.
Typical expectations:
setUpGet.reset() in setUp or tearDown as the repo pattern requiresAttach cleanup close to allocation with addTearDown(...) when the test creates one-off controllers or scopes.
If a test hangs, check these first:
await goToRoute(...) or await Get.toNamed(...)tester.runAsync(...)await on a future that needs pumping to completepumpAndSettle() on a screen with ongoing timers/streamsflutter test -d flutter-tester, not flutter drive.--dart-define=... instead of prefixing env vars.tester.runAsync(...).tester.runAsync(...).Before finishing a new integration test, scan for:
await goToRoute(await Get.toNamed(tester.runAsync(() async { ... navigation ... })pumpAndSettle() in shell/bootstrap-heavy flowsIf any of those are present, the test likely needs restructuring.
development
Use this when QA is piloting product goals, golden paths, simulator flows, or workflow-scale usability for a real user persona.
development
Use for orchestrating or executing screenshot-driven Flutter redesign work where workers generate reference images, capture atomic Design Lab Bun/WebView proof when available, run visual design review, and implement only after visual approval. [skill-hash:2c4d9f0]
content-media
Ran into a sandbox issue, approval request, or privileged-exec rejection? Use this skill immediately for the sanctioned resolution path. [skill-hash:b8f4a20]
development
Use this when a designer needs to pilot an ad-hoc iOS simulator directly, launch Flutter from their own worktree in tmux, or trigger hot reload without the broker/device-harness path.