diff --git a/test/helpers/widget_harness.dart b/test/helpers/widget_harness.dart index 345c426d..bdd09e98 100644 --- a/test/helpers/widget_harness.dart +++ b/test/helpers/widget_harness.dart @@ -1,5 +1,6 @@ import 'package:clide/kernel/kernel.dart'; import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; import 'kernel_fixture.dart'; @@ -33,3 +34,23 @@ Widget harness(KernelFixture fixture, Widget child) { ), ); } + +/// Settle async-driven UI in a widget test WITHOUT the two patterns that have +/// repeatedly wedged this suite: +/// +/// - **Never `pumpAndSettle()`** — it loops until the frame queue is quiescent, +/// so a perpetual animation or overlapping async loads hang it for its +/// ~10-minute default timeout (which wedged the pre-push gate). +/// - **Never `await Future.delayed(Duration.zero)`** — inside the fake-async +/// `testWidgets` zone a real timer never fires unless fake time is advanced, +/// so that line wedges the test until timeout (and even defeats `--timeout`). +/// +/// Instead: pump one frame (draining the microtask queue — broadcast-stream and +/// async-IPC deliveries resolve here), then advance a tiny fake-time tick to +/// flush any follow-up `setState`. Bounded by construction — it cannot hang. +/// Use this after publishing a message / triggering a load in a reader/panel +/// widget test, in place of `pumpAndSettle`. +Future pumpAsync(WidgetTester tester) async { + await tester.pump(); + await tester.pump(const Duration(milliseconds: 20)); +}