This guide explains how to write, run, and debug end-to-end (E2E) integration tests for the MovieStar application. The testing framework supports both quick automated testing and interactive visual testing.
integration_test/)End-to-end tests that run the complete application and verify functionality:
app_test.dart, app_hive_test.dart - Smoke tests for app initializationworkflows/pod_favorites_real_test.dart - Full user workflows with POD authenticationworkflows/visual_login_test.dart - Manual visual inspection of UIAll integration tests follow a consistent pattern to ensure UI is fully rendered before testing:
await tester.pumpAndSettle() - Wait for animations and microtasksawait Future.delayed(delay) - Allow styling/theming to load (2s)await tester.pump(interact) - Interactive delay for manual reviewExample from app_hive_test.dart (lines 79-85):
await tester.pumpWidget(...);
await tester.pumpAndSettle(const Duration(seconds: 5)); // Initial render
await tester.pump(interact); // Visual inspection (0s in qtest, 5s in itest)
Example from pod_favorites_real_test.dart (lines 94-101):
await tester.pumpWidget(...);
await tester.pumpAndSettle(const Duration(seconds: 5)); // Initial render
await Future.delayed(delay); // Allow styling to load (2s)
await tester.pump(); // Apply styling
await tester.pump(interact); // Visual inspection
This ensures tests work reliably in both quick (INTERACT=0) and interactive (INTERACT>0) modes.
test/)Component-level tests for individual widgets, services, and state management.
⚠️ IMPORTANT: Do not use flutter test integration_test/ (batch mode) on desktop platforms - it fails due to a Flutter framework limitation. Use make qtest instead, which runs tests individually.
Run all tests quickly without visual interaction:
# Run all integration tests (recommended)
make qtest
# Run specific test
make workflows/pod_favorites_real_test.qtest
Features:
INTERACT=0 - No delays, runs as fast as possible--reporter failures-only - Only shows failuresqtest_YYYYMMDDHHMMSS.txtRun tests with visual interaction delays:
# Run specific test interactively
make workflows/pod_favorites_real_test.itest
# Or use flutter test with INTERACT parameter
flutter test integration_test/workflows/pod_favorites_real_test.dart -d linux --dart-define=INTERACT=5
Features:
INTERACT=5 - 5 second delay between major steps# Quick (0s interact)
flutter test integration_test/app_test.dart -d linux --dart-define=INTERACT=0
# Visual review (2s interact)
flutter test integration_test/app_test.dart -d linux --dart-define=INTERACT=2
# Slow/development (5-10s interact)
flutter test integration_test/app_test.dart -d linux --dart-define=INTERACT=10
All tests should use the interact delay from utils/delays.dart:
import '../utils/delays.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('my test', (WidgetTester tester) async {
// Initialize app
app.main();
await tester.pumpAndSettle();
// Interactive delay - allows visual inspection when INTERACT > 0
await tester.pump(interact);
// Continue with test assertions
expect(find.text('Movie Star'), findsWidgets);
});
}
Key Points:
interact for visual review during development/debuggingdelay (2s) for required timing (animations, async operations)hack (10s) for workarounds that need fixing (mark with TODO)INTERACT=0 - never rely on interact for functionality/// Brief description of what this test verifies.
///
/// Copyright (C) 2025, Software Innovation Institute, ANU.
library;
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:moviestar/main.dart' as app;
import '../utils/delays.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('descriptive test name', (WidgetTester tester) async {
// 1. Setup
app.main();
await tester.pumpAndSettle();
await tester.pump(interact);
// 2. Actions
// ... perform user actions ...
// 3. Assertions
expect(/* condition */, /* matcher */);
});
}
The solidpod package requires complete authentication data including:
Legacy token injection (basic access_token/id_token only) will fail with:
OpenIdException(invalid_grant): grant request is invalid
Uses browser automation with Puppeteer:
dart run integration_test/utils/extract_tokens.dart
What it does:
integration_test/fixtures/test_credentials.jsonintegration_test/fixtures/complete_auth_data.jsonRequirements:
For visual login or when automation fails:
flutter run integration_test/utils/extract_complete_auth.dart -d linux
Steps:
integration_test/fixtures/complete_auth_data.jsonCreate integration_test/fixtures/test_credentials.json:
{
"username": "your-pod-username",
"password": "your-pod-password",
"securityKey": "your-security-key",
"podUrl": "https://pods.dev.solidcommunity.au/your-pod/",
"issuer": "https://pods.dev.solidcommunity.au"
}
Security Note: This file is git-ignored. Never commit credentials to version control.
Tests can automatically regenerate expired tokens:
await CredentialInjector.injectFullAuth(autoRegenerateOnFailure: true);
This will:
complete_auth_data.jsonProblem: flutter test doesn’t find any tests
Solution: Test files MUST end with _test.dart suffix:
# Correct
integration_test/app_test.dart
integration_test/workflows/pod_favorites_real_test.dart
# Wrong - will not be discovered
integration_test/app.dart
integration_test/workflows/pod_favorites_real.dart
Problem:
AuthDataManager => _getTokenResponse() failed: OpenIdException(invalid_grant)
Causes:
Solutions:
# Re-extract complete auth data
dart run integration_test/utils/extract_tokens.dart
# Or enable auto-regeneration in test
await CredentialInjector.injectFullAuth(autoRegenerateOnFailure: true);
Problem: UI appears unstyled or test runs too fast
Solution: Use interact delay pattern, not hardcoded delays:
// ❌ Wrong - hardcoded delay
await Future.delayed(const Duration(seconds: 2));
// ✅ Correct - interact delay
import '../utils/delays.dart';
await tester.pump(interact);
Run with INTERACT > 0 to see visual rendering:
flutter test integration_test/app_test.dart -d linux --dart-define=INTERACT=5
Problem: Test works interactively but fails in qtest mode
Root Cause: Test is relying on interact delay for functionality (timing issue)
Solution:
await tester.pumpAndSettle() to wait for animations/futuresdelay (2s) for required timinghack if it’s a workaround// For required async operations
await tester.pumpAndSettle();
await Future.delayed(delay); // Required 2s for network/animation
// For workarounds that need fixing
await Future.delayed(hack); // TODO: Fix R script async architecture
Problem: extract_tokens.dart fails with timeout or login errors
Debug Steps:
dart run integration_test/utils/extract_tokens.dart --no-headless
cat integration_test/fixtures/test_credentials.json
curl https://pods.dev.solidcommunity.au/.well-known/openid-configuration
which google-chrome chromium-browser chromium
Problem:
No desktop device found. Please ensure you have the correct desktop platform enabled.
Solution:
# Check available devices
flutter devices
# Enable Linux desktop (if on Linux)
flutter config --enable-linux-desktop
# Or use specific device ID
flutter test integration_test/app_test.dart --device-id linux
Problem:
When running flutter test integration_test/, the first test passes but subsequent tests fail with:
Error waiting for a debug connection: The log reader stopped unexpectedly, or never started.
Failed to load "...": Unable to start the app on the device.
Root Cause: This is a known limitation of Flutter’s integration testing framework on desktop platforms (Windows, Linux, macOS). The Flutter test runner has issues properly cleaning up and restarting the app between tests when running in batch mode. Only the first test succeeds; subsequent tests fail because the test runner cannot establish a debug connection to the app.
This is NOT related to the MovieStar codebase or POD authentication - it’s a fundamental Flutter framework issue tracked in the Flutter repository.
Solution: Run Tests Individually The recommended approach is to run each integration test individually:
# Run each test separately
flutter test integration_test/app_hive_test.dart -d <platform>
flutter test integration_test/app_test.dart -d <platform>
flutter test integration_test/workflows/pod_favorites_real_test.dart -d <platform> --dart-define=INTERACT=0
flutter test integration_test/workflows/visual_login_test.dart -d <platform> --dart-define=INTERACT=0
# Example for Windows
flutter test integration_test/app_hive_test.dart -d windows
flutter test integration_test/app_test.dart -d windows
flutter test integration_test/workflows/pod_favorites_real_test.dart -d windows --dart-define=INTERACT=0
flutter test integration_test/workflows/visual_login_test.dart -d windows --dart-define=INTERACT=0
AUTO_REGENERATE Flag:
The pod_favorites_real_test.dart supports automatic token regeneration when run individually. To disable this feature (e.g., for CI/CD where you want to ensure fresh tokens are pre-generated):
# Disable auto-regeneration for POD test
flutter test integration_test/workflows/pod_favorites_real_test.dart -d <platform> --dart-define=INTERACT=0 --dart-define=AUTO_REGENERATE=false
By default, auto-regeneration is enabled for individual test runs, providing a better developer experience.
Note: Batch testing (flutter test integration_test/) is currently not reliable on desktop platforms due to Flutter framework limitations. Individual test execution is the recommended approach until Flutter addresses this issue.
interact delays for visual inspection, never hardcode delays for functionalityINTERACT=0 - qtest mode is the standardhack delays with TODO comments# Run all tests quickly
make qtest.all
# Run specific test quickly
make workflows/pod_favorites_real_test.qtest
# Run specific test interactively
make workflows/pod_favorites_real_test.itest
# Extract auth data (automated)
dart run integration_test/utils/extract_tokens.dart
# Extract auth data (manual)
flutter run integration_test/utils/extract_complete_auth.dart -d linux
# Run with custom INTERACT
flutter test integration_test/app_test.dart -d linux --dart-define=INTERACT=5
# Check test discovery
flutter test --list