fix(test): fix _zOrderIndex race by syncing focus before field/screen transitions

RawAutocomplete's OverlayPortalController.hide() was called twice:
once when focus left the To field and again when ComposeScreen was popped,
triggering the _zOrderIndex assertion in overlay.dart.

Fix by:
1. pump() after entering the To field so the overlay has a frame to close
   before the Subject field takes focus.
2. unfocus() + pump() before tapping Send so the overlay is already hidden
   when the screen pops, preventing a second hide() on unmount.

Remove the _zOrderIndex string-filter from FlutterError.onError — the
root cause is fixed rather than suppressed.

Fixes #79

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Thomas SharedInbox
2026-05-14 23:06:57 +02:00
co-authored by Claude Sonnet 4.6
parent ebff60a4d4
commit 9ed85e1c51
+8 -5
View File
@@ -167,11 +167,6 @@ void main() {
// DEFUNCT/DISPOSED: keyboard-dismiss or teardown layout errors on
// Android/Linux that have no effect on real functionality.
if (msg.contains('DEFUNCT') || msg.contains('DISPOSED')) return;
// _zOrderIndex: OverlayPortalController.hide() is called twice during
// rapid navigation in tests (once on focus loss, once on widget unmount).
// overlay.dart itself notes this should not happen during rebuilds;
// it's a Flutter framework race that only reproduces in headless tests.
if (msg.contains('_zOrderIndex')) return;
bindingError?.call(details);
};
addTearDown(() => FlutterError.onError = bindingError);
@@ -269,6 +264,10 @@ void main() {
find.widgetWithText(TextFormField, 'To'),
userEmail,
);
// Pump so RawAutocomplete's OverlayPortal has a frame to close before
// focus moves to the next field — prevents the double hide() race that
// triggers the _zOrderIndex assertion in overlay.dart.
await tester.pump();
await tester.enterText(
find.widgetWithText(TextFormField, 'Subject'),
subject,
@@ -278,6 +277,10 @@ void main() {
await tester.ensureVisible(bodyField);
await tester.enterText(bodyField, 'Hello from integration test!');
// Unfocus before sending so the autocomplete overlay closes cleanly
// before ComposeScreen is popped, avoiding a second hide() on unmount.
FocusManager.instance.primaryFocus?.unfocus();
await tester.pump();
_log('send email');
await tester.tap(find.byIcon(Icons.send));
// Wait for ComposeScreen to pop back to EmailListScreen after send.