From 63f76e94ec59793bbfb098b922e8ad4f1da35809 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). This ensures test stability when transition timings change. --- test/widgets/emoji_reaction_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/widgets/emoji_reaction_test.dart b/test/widgets/emoji_reaction_test.dart index d50b7c8d7b..f0a66fa85a 100644 --- a/test/widgets/emoji_reaction_test.dart +++ b/test/widgets/emoji_reaction_test.dart @@ -434,7 +434,7 @@ void main() { // 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)); + await transitionDurationObserver.pumpPastTransition(tester); await store.handleEvent(RealmEmojiUpdateEvent(id: 1, realmEmoji: { '1': eg.realmEmojiItem(emojiCode: '1', emojiName: 'buzzing'), From cf6be3e2d7e9c0ef3ae8c1beb339567f74740502 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). This ensures test stability when transition timings change. additionally added pumpAndSettle to wait for snackbar to show. attached TransitionDurationObserver through navigatorObservers in test widgets to dynamically track transition durations. Prepares tests for replacement of static pump durations. --- test/widgets/action_sheet_test.dart | 30 ++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/test/widgets/action_sheet_test.dart b/test/widgets/action_sheet_test.dart index 621f759f28..f71a80bda0 100644 --- a/test/widgets/action_sheet_test.dart +++ b/test/widgets/action_sheet_test.dart @@ -140,7 +140,7 @@ Future setupToMessageActionSheet(WidgetTester tester, { // 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)); + 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 { @@ -739,7 +745,7 @@ void main() { await tester.longPress(find.text(topic)); // sheet appears onscreen; default duration of bottom-sheet enter animation - await tester.pump(const Duration(milliseconds: 250)); + await transitionDurationObserver.pumpPastTransition(tester); } Future showFromAppBar(WidgetTester tester, { @@ -766,7 +772,7 @@ void main() { 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)); + await transitionDurationObserver.pumpPastTransition(tester); } Future showFromRecipientHeader(WidgetTester tester, { @@ -785,7 +791,7 @@ void main() { 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)); + 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 transitionDurationObserver.pumpPastTransition(tester); + // …pump for snackbar to show + await tester.pumpAndSettle(); final snackbar = tester.widget(find.byType(SnackBar)); check(snackbar.behavior).equals(SnackBarBehavior.floating); @@ -2283,7 +2291,7 @@ 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)); + await transitionDurationObserver.pumpPastTransition(tester); check(find.byType(BottomSheet)).findsOne(); checkButtonIsPresent(expected); From e05fc952bad294ec3b67d2ffbc1899ba823a48ae 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 Added TransitionDurationObserver initialization inside prepareComposeBox setup,every test that calls prepareComposeBox now automatically attaches an observer to the widget tree.Replaced hardcoded transition delays with dynamic duration handling via transitionDurationObserver.pumpPastTransition(tester). This ensures test stability when transition timings change. --- test/widgets/compose_box_test.dart | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/widgets/compose_box_test.dart b/test/widgets/compose_box_test.dart index 15a0a7f81e..6d360dbc59 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(); @@ -1719,7 +1722,7 @@ void main() { 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)); + 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();