diff --git a/lib/widgets/autocomplete.dart b/lib/widgets/autocomplete.dart index 7b5284ef43..d0d604efab 100644 --- a/lib/widgets/autocomplete.dart +++ b/lib/widgets/autocomplete.dart @@ -501,20 +501,12 @@ class TopicAutocomplete extends AutocompleteField w is InlineIcon && w.icon == ZulipIcons.check))).findsOne(); + check(find.descendant(of: itemFinder, + matching: find.textContaining('✔', findRichText: true))).findsNothing(); + }); + testWidgets('autocomplete to realmEmptyTopicDisplayName sets topic to empty string', (tester) async { final topic = eg.getChannelTopicsEntry(name: ''); final topicInputFinder = await setupToTopicInput(tester, topics: [topic], diff --git a/test/widgets/message_list_test.dart b/test/widgets/message_list_test.dart index 92c3d2c3e7..ab12d45e99 100644 --- a/test/widgets/message_list_test.dart +++ b/test/widgets/message_list_test.dart @@ -35,6 +35,7 @@ import 'package:zulip/widgets/image.dart'; import 'package:zulip/widgets/message_list.dart'; import 'package:zulip/widgets/page.dart'; import 'package:zulip/widgets/store.dart'; +import 'package:zulip/widgets/text.dart'; import 'package:zulip/widgets/channel_colors.dart'; import 'package:zulip/widgets/theme.dart'; import 'package:zulip/widgets/topic_list.dart'; @@ -251,6 +252,22 @@ void main() { channel.name, eg.defaultRealmEmptyTopicDisplayName); }); + testWidgets('show resolved-topic check icon in topic narrow', (tester) async { + final channel = eg.stream(); + await setupMessageListPage(tester, + narrow: eg.topicNarrow(channel.streamId, '✔ some topic'), + subscriptions: [eg.subscription(channel)], + messages: [eg.streamMessage(stream: channel, topic: '✔ some topic')]); + final appBarFinder = find.byType(MessageListAppBarTitle); + check(find.descendant(of: appBarFinder, + matching: find.byWidgetPredicate( + (w) => w is InlineIcon && w.icon == ZulipIcons.check))).findsOne(); + check(find.descendant(of: appBarFinder, + matching: find.textContaining('some topic', findRichText: true))).findsOne(); + check(find.descendant(of: appBarFinder, + matching: find.textContaining('✔', findRichText: true))).findsNothing(); + }); + void testChannelIconInChannelRow(IconData expectedIcon, { required bool isWebPublic, required bool inviteOnly, @@ -1799,6 +1816,23 @@ void main() { check(findInMessageList(eg.defaultRealmEmptyTopicDisplayName)).single; }); + testWidgets('show resolved-topic check icon', (tester) async { + final message = eg.streamMessage( + stream: stream, topic: '✔ some topic'); + await setupMessageListPage(tester, + narrow: const CombinedFeedNarrow(), + messages: [message], subscriptions: [eg.subscription(stream)]); + await tester.pump(); + final headerFinder = find.byType(StreamMessageRecipientHeader); + check(find.descendant(of: headerFinder, + matching: find.byWidgetPredicate( + (w) => w is InlineIcon && w.icon == ZulipIcons.check))).findsOne(); + check(find.descendant(of: headerFinder, + matching: find.textContaining('some topic', findRichText: true))).findsOne(); + check(find.descendant(of: headerFinder, + matching: find.textContaining('✔', findRichText: true))).findsNothing(); + }); + testWidgets('show topic visibility icon when followed', (tester) async { await setupMessageListPage(tester, narrow: const CombinedFeedNarrow(), diff --git a/test/widgets/text_test.dart b/test/widgets/text_test.dart index d76eb48023..824b24debf 100644 --- a/test/widgets/text_test.dart +++ b/test/widgets/text_test.dart @@ -3,8 +3,11 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_checks/flutter_checks.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:zulip/api/model/model.dart'; +import 'package:zulip/widgets/icons.dart'; import 'package:zulip/widgets/text.dart'; +import '../example_data.dart' as eg; import '../flutter_checks.dart'; import '../model/binding.dart'; import 'test_app.dart'; @@ -420,6 +423,101 @@ void main() { testLocalizedTextBaseline(const Locale('und'), TextBaseline.alphabetic); }); + group('topicLabelSpan', () { + Future prepareWidget(WidgetTester tester, { + required TopicName topic, + String? realmEmptyTopicDisplayName, + }) async { + addTearDown(testBinding.reset); + await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot( + realmEmptyTopicDisplayName: realmEmptyTopicDisplayName)); + + await tester.pumpWidget(TestZulipApp(accountId: eg.selfAccount.id, + child: Builder(builder: (context) => Text.rich( + topicLabelSpan( + context: context, + topic: topic, + fontSize: 17, + color: Colors.black))))); + await tester.pump(); // global store + await tester.pump(); // per-account store + } + + Finder findCheckIcon() => find.byWidgetPredicate( + (w) => w is InlineIcon && w.icon == ZulipIcons.check); + + testWidgets('resolved topic shows checkmark and strips prefix', (tester) async { + await prepareWidget(tester, topic: eg.t('✔ some topic')); + check(findCheckIcon()).findsOne(); + check(find.textContaining('some topic', findRichText: true)).findsOne(); + check(find.textContaining('✔', findRichText: true)).findsNothing(); + }); + + testWidgets('unresolved topic shows no checkmark', (tester) async { + await prepareWidget(tester, topic: eg.t('some topic')); + check(findCheckIcon()).findsNothing(); + check(find.textContaining('some topic', findRichText: true)).findsOne(); + }); + + testWidgets('empty topic shows italic placeholder', (tester) async { + await prepareWidget(tester, topic: eg.t(''), + realmEmptyTopicDisplayName: 'general chat'); + check(find.textContaining('general chat', findRichText: true)).findsOne(); + + FontStyle? italicFontStyle; + final richText = tester.widget( + find.textContaining('general chat', findRichText: true)); + richText.text.visitChildren((span) { + if (span is TextSpan && span.text == 'general chat') { + italicFontStyle = span.style?.fontStyle; + return false; + } + return true; + }); + check(italicFontStyle).equals(FontStyle.italic); + }); + }); + + group('channelTopicLabelSpan', () { + final channel = eg.stream(); + + Future prepareWidget(WidgetTester tester, { + required TopicName topic, + }) async { + addTearDown(testBinding.reset); + await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot( + streams: [channel], + subscriptions: [eg.subscription(channel)])); + + await tester.pumpWidget(TestZulipApp(accountId: eg.selfAccount.id, + child: Builder(builder: (context) => Text.rich( + channelTopicLabelSpan( + context: context, + channelId: channel.streamId, + topic: topic, + fontSize: 17, + color: Colors.black))))); + await tester.pump(); // global store + await tester.pump(); // per-account store + } + + Finder findCheckIcon() => find.byWidgetPredicate( + (w) => w is InlineIcon && w.icon == ZulipIcons.check); + + testWidgets('resolved topic shows checkmark and strips prefix', (tester) async { + await prepareWidget(tester, topic: eg.t('✔ some topic')); + check(findCheckIcon()).findsOne(); + check(find.textContaining('some topic', findRichText: true)).findsOne(); + check(find.textContaining('✔', findRichText: true)).findsNothing(); + }); + + testWidgets('unresolved topic shows no checkmark', (tester) async { + await prepareWidget(tester, topic: eg.t('some topic')); + check(findCheckIcon()).findsNothing(); + check(find.textContaining('some topic', findRichText: true)).findsOne(); + }); + }); + group('TextWithLink', () { testWidgets('responds correctly to taps', (tester) async { int calls = 0;