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.
New to POD authentication? Read Understanding POD Authentication first to learn why OAuth, DPoP, and browser automation are necessary.
Documentation index: See README.md for complete documentation navigation.
# Extract auth data (first time only)
dart run integration_test/tools/generate_auth_data.dart
# Run all tests quickly
make qtest
# Run specific test
make workflows/pod_favorites_real_test.qtest
End-to-end tests that run the complete application and verify functionality:
Basic Tests:
app_test.dart - Smoke test for app initializationapp_hive_test.dart - Hive storage initialization testWorkflow Tests:
workflows/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:
Steps:
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:
await tester.pumpWidget(...);
await tester.pumpAndSettle(const Duration(seconds: 5));
await tester.pump(interact); // 0s in qtest, 5s in itest
Example from pod_favorites_real_test.dart:
await tester.pumpWidget(...);
await tester.pumpAndSettle(const Duration(seconds: 5));
await Future.delayed(delay); // Allow styling to load
await tester.pump();
await tester.pump(interact);
This ensures tests work reliably in both quick (INTERACT=0) and
interactive (INTERACT>0) modes.
Component-level tests for individual widgets, services, and state
management in test/ directory.
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
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', (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/tools/generate_auth_data.dart
What it does:
test_credentials.jsoncomplete_auth_data.jsonRequirements:
For visual login or when automation fails:
flutter run integration_test/tools/generate_auth_data.dart -d linux
Steps:
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.jsoninteract 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/tools/generate_auth_data.dart
# Extract auth data (manual)
flutter run integration_test/tools/generate_auth_data.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