com um clique
e2e-test
// Run and debug Flutter E2E integration tests that exercise the real app against a local Docker backend (no mocks). Use when running E2E tests, debugging failures, or working on the local harness.
// Run and debug Flutter E2E integration tests that exercise the real app against a local Docker backend (no mocks). Use when running E2E tests, debugging failures, or working on the local harness.
Review all uncommitted changes before pushing. Checks for dead code, stale comments, CLAUDE.md rule violations, unused imports, and inconsistencies introduced during the current session. Invoke with /review-before-commit.
Fix ArgoCD ExternalSecret deployment failing with "namespace X is not permitted in project Y". Use when: (1) ExternalSecret shows OutOfSync in ArgoCD but won't sync, (2) ArgoCD application status shows "namespace X is not permitted in project 'infrastructure'", (3) ExternalSecret targets a namespace managed by a different ArgoCD project, (4) Using apps-of-apps pattern with separate infrastructure and application projects.
Art direction for any content — reads text, PDF, Word, HTML, PPT, then proposes 2-3 creative directions with photography style, mood, and visual language. After selection, generates AI image prompts and visual briefs section-by-section. Use when the user shares content and needs visual direction, image sourcing, or creative direction for any material.
Fix "Null check operator used on a null value" errors when an object is set to null during an async await. Use when: (1) Object reference is nullified while awaiting, (2) Code accesses object with ! after await returns, (3) Cancel/dispose operations run concurrently with async operations on same object. Solution: capture local reference before await.
Add custom metadata headers (x-amz-meta-*) to AWS v4 signed requests for GCS S3-compatible API. Use when: (1) Adding custom metadata to GCS uploads via S3 API, (2) Getting signature mismatch errors after adding new headers, (3) x-amz-meta-* headers being ignored or causing 403 errors. Custom headers MUST be included in canonical headers and signed headers list.
Fix password/secret authentication failures caused by trailing newlines when creating Google Cloud secrets (or similar) with bash here-strings. Use when: (1) Password authentication fails with correct password, (2) Secret created with `<<< "value"` syntax, (3) Error like "password authentication failed" or "invalid token" despite correct value. Bash here-strings (`<<<`) add a trailing newline that corrupts secrets.
| name | e2e-test |
| description | Run and debug Flutter E2E integration tests that exercise the real app against a local Docker backend (no mocks). Use when running E2E tests, debugging failures, or working on the local harness. |
| author | Claude Code |
| version | 1.1.0 |
Goal: run the real app against a real local backend, end-to-end.
OAuth, relay subscriptions, and media uploads all hit local Docker
services — no mocks anywhere. Tests live in
mobile/integration_test/, backend in local_stack/.
Two terminals, from mobile/:
# Terminal 1 — emulator
mise run emulator
# Terminal 2 — tests
mise run e2e_test # All auth tests
mise run e2e_test integration_test/auth/auth_journey_test.dart # Single test
e2e_test brings up the Docker stack, runs patrol, captures a
merged docker+logcat+app timeline at test_reports/*.jsonl, and
prints the native test XML path + failure excerpts when the APK
fails to install. Never call patrol test directly — you'll
lose the timeline and the diagnostics.
| Service | Port | Purpose |
|---|---|---|
| Keycast | 43000 | OAuth + NIP-46 signer |
| FunnelCake Relay | 47777 | Nostr relay |
| FunnelCake API | 43001 | REST API |
| Blossom | 43003 | Media server |
| Postgres | 15432 | Keycast DB |
mise run local_up # Start (auto-runs local_setup on fresh worktrees)
mise run local_up_cached # Same, but reuse cached images (offline / rate-limited)
mise run local_down # Stop
mise run local_reset # Wipe data + restart
mise run local_status # Health
If local_up fails only at e2e-seed and the services your test
actually needs are healthy (auth tests don't need the indexer),
bypass the seed:
bash ../local_stack/profile.sh integration_test/<your_test>.dart
mise run emulator # Normal launch (auto-detects DISPLAY)
mise run emulator_headless # Offscreen, no window
mise run emulator_wipe # -wipe-data (storage exhausted)
Override AVD: AVD_NAME=<name> mise run emulator. Always uses
-gpu host — swiftshader can't render media_kit frames.
Skip the per-run reinstall with PATROL_NO_UNINSTALL=true mise run e2e_test ... when iterating fast and the APK hasn't changed.
Stale-state debugging cost is yours.
Buffer auth-flow logs: adb logcat -G 16M (default 256 KB rotates
mid-flow).
pumpAndSettle hangs because of persistent polling timers. Use
launchAppGuarded (from test_setup.dart) with error suppression
and a manual pump loop:
final originalOnError = suppressSetStateErrors();
final originalErrorBuilder = saveErrorWidgetBuilder();
launchAppGuarded(app.main);
for (var i = 0; i < 60; i++) {
await tester.pump(const Duration(milliseconds: 250));
if (find.text('Welcome').evaluate().isNotEmpty) break;
}
restoreErrorWidgetBuilder(originalErrorBuilder);
restoreErrorHandler(originalOnError);
drainAsyncErrors(tester);
UI navigates before publish/upload completes. Poll the relay:
for (var i = 0; i < 120; i++) {
await tester.pump(const Duration(milliseconds: 500));
events = await queryRelay(filter);
if (events.isNotEmpty) break;
}
New bottom sheets may cover the target widget:
for (var i = 0; i < 20; i++) {
await tester.pump(const Duration(milliseconds: 250));
final gotIt = find.text('Got it!');
if (gotIt.evaluate().isNotEmpty) {
await tester.tap(gotIt);
break;
}
}
Patrol bundles every file in a target dir into one APK. When file B
runs, file A shows up as "not requested" [E] markers in logcat.
Trust only the final ✅/❌ lines.
Providers using requireIdentity (or similar non-nullable getters)
crash during cold start and Riverpod caches the error forever. Use
the nullable accessor (currentIdentity) and handle null.
TextField in an overlay/transition without Scaffold needs:
Material(color: Colors.transparent, child: TextField(...))
integration_test/helpers/:
test_setup.dart — launchAppGuarded, error suppression, async-error drainnavigation_helpers.dart — register, login, tap tabs, wait for widgetsrelay_helpers.dart — publish/query Nostr eventsdb_helpers.dart — Postgres (verification tokens, refresh tokens)http_helpers.dart — Keycast API (verify email, forgot password)constants.dart — ports + appPackage# Service logs
docker compose -f local_stack/docker-compose.yml logs keycast --tail=50
docker compose -f local_stack/docker-compose.yml logs blossom | grep -v 'path=/'
# Auth trace
adb logcat -d | grep 'flutter.*\[AUTH\]' | grep -v 'Router redirect'
# Last merged timeline
ls mobile/test_reports/*.jsonl
If patrol reports Total: 0 with Gradle exit 1, the runner
auto-prints the native test XML path + failure excerpts — that's
an APK install failure, not a missing test. Free space with
adb shell pm trim-caches 1G or mise run emulator_wipe.