@@ -47,15 +47,18 @@ void main() {
4747 List <User > otherUsers = const [],
4848 List <ZulipStream > streams = const [],
4949 bool ? mandatoryTopics,
50+ int ? zulipFeatureLevel,
5051 }) async {
5152 if (narrow case ChannelNarrow (: var streamId) || TopicNarrow (: var streamId)) {
5253 assert (streams.any ((stream) => stream.streamId == streamId),
5354 'Add a channel with "streamId" the same as of $narrow .streamId to the store.' );
5455 }
5556 addTearDown (testBinding.reset);
5657 selfUser ?? = eg.selfUser;
57- final selfAccount = eg.account (user: selfUser);
58+ zulipFeatureLevel ?? = eg.futureZulipFeatureLevel;
59+ final selfAccount = eg.account (user: selfUser, zulipFeatureLevel: zulipFeatureLevel);
5860 await testBinding.globalStore.add (selfAccount, eg.initialSnapshot (
61+ zulipFeatureLevel: zulipFeatureLevel,
5962 realmMandatoryTopics: mandatoryTopics,
6063 ));
6164
@@ -327,12 +330,14 @@ void main() {
327330 Future <void > prepare (WidgetTester tester, {
328331 required Narrow narrow,
329332 bool ? mandatoryTopics,
333+ int ? zulipFeatureLevel,
330334 }) async {
331335 await prepareComposeBox (tester,
332336 narrow: narrow,
333337 otherUsers: [eg.otherUser, eg.thirdUser],
334338 streams: [channel],
335- mandatoryTopics: mandatoryTopics);
339+ mandatoryTopics: mandatoryTopics,
340+ zulipFeatureLevel: zulipFeatureLevel);
336341 }
337342
338343 /// This checks the input's configured hint text without regard to whether
@@ -356,16 +361,49 @@ void main() {
356361 group ('to ChannelNarrow, topics not mandatory' , () {
357362 final narrow = ChannelNarrow (channel.streamId);
358363
359- testWidgets ('with empty topic' , (tester) async {
364+ testWidgets ('with empty topic, topic input has focus ' , (tester) async {
360365 await prepare (tester, narrow: narrow, mandatoryTopics: false );
366+ await enterTopic (tester, narrow: narrow, topic: '' );
367+ await tester.pump ();
361368 checkComposeBoxHintTexts (tester,
362369 topicHintText: 'Topic' ,
363- contentHintText: 'Message #${channel .name } > (no topic) ' );
370+ contentHintText: 'Message #${channel .name }' );
364371 });
365372
366- testWidgets ('with non-empty but vacuous topic' , (tester) async {
373+ testWidgets ('legacy: with empty topic, topic input has focus' , (tester) async {
374+ await prepare (tester, narrow: narrow, mandatoryTopics: false ,
375+ zulipFeatureLevel: 333 ); // TODO(server-10)
376+ await enterTopic (tester, narrow: narrow, topic: '' );
377+ await tester.pump ();
378+ checkComposeBoxHintTexts (tester,
379+ topicHintText: 'Topic' ,
380+ contentHintText: 'Message #${channel .name }' );
381+ });
382+
383+ testWidgets ('with non-empty but vacuous topic, topic input has focus' , (tester) async {
367384 await prepare (tester, narrow: narrow, mandatoryTopics: false );
368- await enterTopic (tester, narrow: narrow, topic: '(no topic)' );
385+ await enterTopic (tester, narrow: narrow,
386+ topic: eg.defaultRealmEmptyTopicDisplayName);
387+ await tester.pump ();
388+ checkComposeBoxHintTexts (tester,
389+ topicHintText: 'Topic' ,
390+ contentHintText: 'Message #${channel .name }' );
391+ });
392+
393+ testWidgets ('with empty topic, content input has focus' , (tester) async {
394+ await prepare (tester, narrow: narrow, mandatoryTopics: false );
395+ await enterContent (tester, '' );
396+ await tester.pump ();
397+ checkComposeBoxHintTexts (tester,
398+ topicHintText: 'Topic' ,
399+ contentHintText: 'Message #${channel .name } > '
400+ '${eg .defaultRealmEmptyTopicDisplayName }' );
401+ }, skip: true ); // null topic names soon to be enabled
402+
403+ testWidgets ('legacy: with empty topic, content input has focus' , (tester) async {
404+ await prepare (tester, narrow: narrow, mandatoryTopics: false ,
405+ zulipFeatureLevel: 333 );
406+ await enterContent (tester, '' );
369407 await tester.pump ();
370408 checkComposeBoxHintTexts (tester,
371409 topicHintText: 'Topic' ,
@@ -392,15 +430,36 @@ void main() {
392430 contentHintText: 'Message #${channel .name }' );
393431 });
394432
395- testWidgets ('with non-empty but vacuous topic' , (tester) async {
396- await prepare (tester, narrow: narrow, mandatoryTopics: true );
397- await enterTopic (tester, narrow: narrow, topic: '(no topic)' );
398- await tester.pump ();
433+ testWidgets ('legacy: with empty topic' , (tester) async {
434+ await prepare (tester, narrow: narrow, mandatoryTopics: true ,
435+ zulipFeatureLevel: 333 ); // TODO(server-10)
399436 checkComposeBoxHintTexts (tester,
400437 topicHintText: 'Topic' ,
401438 contentHintText: 'Message #${channel .name }' );
402439 });
403440
441+ group ('with non-empty but vacuous topics' , () {
442+ testWidgets ('realm_empty_topic_display_name' , (tester) async {
443+ await prepare (tester, narrow: narrow, mandatoryTopics: true );
444+ await enterTopic (tester, narrow: narrow,
445+ topic: eg.defaultRealmEmptyTopicDisplayName);
446+ await tester.pump ();
447+ checkComposeBoxHintTexts (tester,
448+ topicHintText: 'Topic' ,
449+ contentHintText: 'Message #${channel .name }' );
450+ });
451+
452+ testWidgets ('"(no topic)"' , (tester) async {
453+ await prepare (tester, narrow: narrow, mandatoryTopics: true );
454+ await enterTopic (tester, narrow: narrow,
455+ topic: '(no topic)' );
456+ await tester.pump ();
457+ checkComposeBoxHintTexts (tester,
458+ topicHintText: 'Topic' ,
459+ contentHintText: 'Message #${channel .name }' );
460+ });
461+ });
462+
404463 testWidgets ('with non-empty topic' , (tester) async {
405464 await prepare (tester, narrow: narrow, mandatoryTopics: true );
406465 await enterTopic (tester, narrow: narrow, topic: 'new topic' );
@@ -703,6 +762,7 @@ void main() {
703762 Future <void > setupAndTapSend (WidgetTester tester, {
704763 required String topicInputText,
705764 required bool mandatoryTopics,
765+ int ? zulipFeatureLevel,
706766 }) async {
707767 TypingNotifier .debugEnable = false ;
708768 addTearDown (TypingNotifier .debugReset);
@@ -711,7 +771,8 @@ void main() {
711771 final narrow = ChannelNarrow (channel.streamId);
712772 await prepareComposeBox (tester,
713773 narrow: narrow, streams: [channel],
714- mandatoryTopics: mandatoryTopics);
774+ mandatoryTopics: mandatoryTopics,
775+ zulipFeatureLevel: zulipFeatureLevel);
715776
716777 await enterTopic (tester, narrow: narrow, topic: topicInputText);
717778 await tester.enterText (contentInputFinder, 'test content' );
@@ -726,10 +787,21 @@ void main() {
726787 expectedMessage: 'Topics are required in this organization.' );
727788 }
728789
729- testWidgets ('empty topic -> "(no topic) "' , (tester) async {
790+ testWidgets ('empty topic -> ""' , (tester) async {
730791 await setupAndTapSend (tester,
731792 topicInputText: '' ,
732793 mandatoryTopics: false );
794+ check (connection.lastRequest).isA< http.Request > ()
795+ ..method.equals ('POST' )
796+ ..url.path.equals ('/api/v1/messages' )
797+ ..bodyFields['topic' ].equals ('' );
798+ });
799+
800+ testWidgets ('legacy: empty topic -> "(no topic)"' , (tester) async {
801+ await setupAndTapSend (tester,
802+ topicInputText: '' ,
803+ mandatoryTopics: false ,
804+ zulipFeatureLevel: 333 );
733805 check (connection.lastRequest).isA< http.Request > ()
734806 ..method.equals ('POST' )
735807 ..url.path.equals ('/api/v1/messages' )
@@ -743,6 +815,13 @@ void main() {
743815 checkMessageNotSent (tester);
744816 });
745817
818+ testWidgets ('if topics are mandatory, reject `realmEmptyTopicDisplayName`' , (tester) async {
819+ await setupAndTapSend (tester,
820+ topicInputText: eg.defaultRealmEmptyTopicDisplayName,
821+ mandatoryTopics: true );
822+ checkMessageNotSent (tester);
823+ });
824+
746825 testWidgets ('if topics are mandatory, reject "(no topic)"' , (tester) async {
747826 await setupAndTapSend (tester,
748827 topicInputText: '(no topic)' ,
0 commit comments