From 8bbc189bbd7bf8cdf8e65ea180621bab1555f9b6 Mon Sep 17 00:00:00 2001 From: MdSaifAliMolla <145194907+MdSaifAliMolla@users.noreply.github.com> Date: Fri, 31 Oct 2025 11:57:42 +0530 Subject: [PATCH 1/3] test: Use transitionDurationObserver in emoji_reaction_test Replaces hardcoded transition delays with dynamic duration handling via transitionDurationObserver.pumpPastTransition(tester). --- test/widgets/emoji_reaction_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/widgets/emoji_reaction_test.dart b/test/widgets/emoji_reaction_test.dart index d50b7c8d7b..f53ca50688 100644 --- a/test/widgets/emoji_reaction_test.dart +++ b/test/widgets/emoji_reaction_test.dart @@ -433,8 +433,8 @@ void main() { await tester.pumpAndSettle(); // request the message action sheet await tester.longPress(find.byType(MessageContent)); - // sheet appears onscreen; default duration of bottom-sheet enter animation - await tester.pump(const Duration(milliseconds: 250)); + // sheet appears onscreen + await transitionDurationObserver.pumpPastTransition(tester); await store.handleEvent(RealmEmojiUpdateEvent(id: 1, realmEmoji: { '1': eg.realmEmojiItem(emojiCode: '1', emojiName: 'buzzing'), From 2101dfd83cead6c01e71cce7ca42a9f570c31cc1 Mon Sep 17 00:00:00 2001 From: MdSaifAliMolla <145194907+MdSaifAliMolla@users.noreply.github.com> Date: Fri, 31 Oct 2025 12:07:35 +0530 Subject: [PATCH 2/3] test: Use transitionDurationObserver in action_sheet_test Replaces hardcoded transition delays with dynamic duration handling via transitionDurationObserver.pumpPastTransition(tester). Attaches TransitionDurationObserver through navigatorObservers in test widgets to dynamically track transition durations. --- test/widgets/action_sheet_test.dart | 40 +++++++++++++++++------------ 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/test/widgets/action_sheet_test.dart b/test/widgets/action_sheet_test.dart index 621f759f28..5c65180c82 100644 --- a/test/widgets/action_sheet_test.dart +++ b/test/widgets/action_sheet_test.dart @@ -139,8 +139,8 @@ Future setupToMessageActionSheet(WidgetTester tester, { // the long-press might land where no child hit-tests as true, // like if it's in padding around a Paragraph. await tester.longPress(find.byType(MessageContent), warnIfMissed: false); - // sheet appears onscreen; default duration of bottom-sheet enter animation - await tester.pump(const Duration(milliseconds: 250)); + // sheet appears onscreen + await transitionDurationObserver.pumpPastTransition(tester); // Check the action sheet did in fact open, so we don't defeat any tests that // use simple `find.byIcon`-style checks to test presence/absence of a button. check(find.byType(BottomSheet)).findsOne(); @@ -199,11 +199,13 @@ void main() { check(find.byType(InboxPageBody)).findsOne(); await tester.longPress(find.text(someChannel.name).hitTestable()); - await tester.pump(const Duration(milliseconds: 250)); + await transitionDurationObserver.pumpPastTransition(tester); } Future showFromSubscriptionList(WidgetTester tester) async { + transitionDurationObserver = TransitionDurationObserver(); await tester.pumpWidget(TestZulipApp(accountId: eg.selfAccount.id, + navigatorObservers: [transitionDurationObserver], child: const HomePage())); await tester.pump(); await tester.tap(find.byIcon(ZulipIcons.hash_italic)); @@ -211,7 +213,7 @@ void main() { check(find.byType(SubscriptionListPageBody)).findsOne(); await tester.longPress(find.text(someChannel.name).hitTestable()); - await tester.pump(const Duration(milliseconds: 250)); + await transitionDurationObserver.pumpPastTransition(tester); } Future showFromMsglistAppBar(WidgetTester tester, { @@ -219,6 +221,7 @@ void main() { required Narrow narrow, }) async { channel ??= someChannel; + transitionDurationObserver = TransitionDurationObserver(); connection.prepare(json: eg.newestGetMessagesResult( foundOldest: true, messages: []).toJson()); @@ -229,6 +232,7 @@ void main() { } await tester.pumpWidget(TestZulipApp( accountId: eg.selfAccount.id, + navigatorObservers: [transitionDurationObserver], child: MessageListPage( initNarrow: narrow))); await tester.pumpAndSettle(); @@ -236,24 +240,26 @@ void main() { await tester.longPress(find.descendant( of: find.byType(ZulipAppBar), matching: find.text(channel.name))); - await tester.pump(const Duration(milliseconds: 250)); + await transitionDurationObserver.pumpPastTransition(tester); } Future showFromRecipientHeader(WidgetTester tester, { StreamMessage? message, }) async { message ??= someMessage; + transitionDurationObserver = TransitionDurationObserver(); connection.prepare(json: eg.newestGetMessagesResult( foundOldest: true, messages: [message]).toJson()); await tester.pumpWidget(TestZulipApp(accountId: eg.selfAccount.id, + navigatorObservers: [transitionDurationObserver], child: const MessageListPage(initNarrow: CombinedFeedNarrow()))); await tester.pumpAndSettle(); await tester.longPress(find.descendant( of: find.byType(RecipientHeader), matching: find.text(message.displayRecipient ?? ''))); - await tester.pump(const Duration(milliseconds: 250)); + await transitionDurationObserver.pumpPastTransition(tester); } Future showFromTopicListAppBar(WidgetTester tester, {int? streamId}) async { @@ -738,8 +744,8 @@ void main() { check(find.byType(InboxPageBody)).findsOne(); await tester.longPress(find.text(topic)); - // sheet appears onscreen; default duration of bottom-sheet enter animation - await tester.pump(const Duration(milliseconds: 250)); + // sheet appears onscreen + await transitionDurationObserver.pumpPastTransition(tester); } Future showFromAppBar(WidgetTester tester, { @@ -765,8 +771,8 @@ void main() { matching: find.text( effectiveTopic.displayName ?? eg.defaultRealmEmptyTopicDisplayName)); await tester.longPress(topicRow); - // sheet appears onscreen; default duration of bottom-sheet enter animation - await tester.pump(const Duration(milliseconds: 250)); + // sheet appears onscreen + await transitionDurationObserver.pumpPastTransition(tester); } Future showFromRecipientHeader(WidgetTester tester, { @@ -784,8 +790,8 @@ void main() { await tester.longPress(find.descendant( of: find.byType(RecipientHeader), matching: find.text(effectiveMessage.topic.displayName!))); - // sheet appears onscreen; default duration of bottom-sheet enter animation - await tester.pump(const Duration(milliseconds: 250)); + // sheet appears onscreen + await transitionDurationObserver.pumpPastTransition(tester); } final actionSheetFinder = find.byType(BottomSheet); @@ -2049,9 +2055,11 @@ void main() { delay: const Duration(milliseconds: 500)); await tapCopyMessageTextButton(tester); // … and pump a frame to finish the NavigationState.pop animation… - await tester.pump(const Duration(milliseconds: 250)); + await transitionDurationObserver.pumpPastTransition(tester); // … before the request finishes. This is the repro condition for #732. - await tester.pump(const Duration(milliseconds: 250)); + await tester.pump(Duration(milliseconds: 500)); + // … pump for snackbar to show; default duration of snackbar enter animation + await tester.pump(Duration(milliseconds: 250)); final snackbar = tester.widget(find.byType(SnackBar)); check(snackbar.behavior).equals(SnackBarBehavior.floating); @@ -2282,8 +2290,8 @@ void main() { // See comment in setupToMessageActionSheet about warnIfMissed: false await tester.longPress(find.byType(MessageContent), warnIfMissed: false); - // sheet appears onscreen; default duration of bottom-sheet enter animation - await tester.pump(const Duration(milliseconds: 250)); + // sheet appears onscreen + await transitionDurationObserver.pumpPastTransition(tester); check(find.byType(BottomSheet)).findsOne(); checkButtonIsPresent(expected); From 6cbfe0bdddea57c5e807f6a76960a4cf15a5867a Mon Sep 17 00:00:00 2001 From: MdSaifAliMolla <145194907+MdSaifAliMolla@users.noreply.github.com> Date: Fri, 31 Oct 2025 12:21:21 +0530 Subject: [PATCH 3/3] test: Use TransitionDurationObserver in compose_box_test Adds TransitionDurationObserver initialization inside the prepareComposeBox setup. Every test that calls prepareComposeBox now automatically attaches an observer to the widget tree. Replaces hardcoded transition delays with dynamic duration handling via transitionDurationObserver.pumpPastTransition(tester). --- test/widgets/compose_box_test.dart | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/test/widgets/compose_box_test.dart b/test/widgets/compose_box_test.dart index 15a0a7f81e..fd9a6357d2 100644 --- a/test/widgets/compose_box_test.dart +++ b/test/widgets/compose_box_test.dart @@ -50,6 +50,7 @@ void main() { late PerAccountStore store; late FakeApiConnection connection; late ComposeBoxState state; + late TransitionDurationObserver transitionDurationObserver; // Caution: when testing edit-message UI, this will often be stale; // read state.controller instead. @@ -96,6 +97,7 @@ void main() { store = await testBinding.globalStore.perAccount(selfAccount.id); connection = store.connection as FakeApiConnection; + transitionDurationObserver = TransitionDurationObserver(); connection.prepare(json: eg.newestGetMessagesResult(foundOldest: true, messages: messages).toJson()); @@ -104,6 +106,7 @@ void main() { connection.prepare(json: GetStreamTopicsResult(topics: []).toJson()); } await tester.pumpWidget(TestZulipApp(accountId: selfAccount.id, + navigatorObservers: [transitionDurationObserver], child: MessageListPage(initNarrow: narrow))); await tester.pumpAndSettle(); connection.takeRequests(); @@ -1718,8 +1721,8 @@ void main() { }) async { await tester.longPress(find.byWidgetPredicate((widget) => widget is MessageWithPossibleSender && widget.item.message.id == messageId)); - // sheet appears onscreen; default duration of bottom-sheet enter animation - await tester.pump(const Duration(milliseconds: 250)); + // sheet appears onscreen + await transitionDurationObserver.pumpPastTransition(tester); final findEditButton = find.descendant( of: find.byType(BottomSheet), matching: find.byIcon(ZulipIcons.edit, skipOffstage: false)); @@ -1875,7 +1878,7 @@ void main() { await startEditInteractionFromActionSheet(tester, messageId: messageToEdit.id, originalRawContent: 'message to edit', delay: Duration.zero); - await tester.pump(const Duration(milliseconds: 250)); // bottom-sheet animation + await transitionDurationObserver.pumpPastTransition(tester); // bottom-sheet animation await tester.tap(failedMessageFinder); await tester.pump(); @@ -1899,7 +1902,7 @@ void main() { await startEditInteractionFromActionSheet(tester, messageId: messageToEdit.id, originalRawContent: 'message to edit', delay: Duration.zero); - await tester.pump(const Duration(milliseconds: 250)); // bottom-sheet animation + await transitionDurationObserver.pumpPastTransition(tester); // bottom-sheet animation await tester.tap(failedMessageFinder); await tester.pump();