From 998913e86862db5196670d93ca686daa5815fce6 Mon Sep 17 00:00:00 2001 From: Chris Bobbe Date: Thu, 13 Nov 2025 14:38:40 -0800 Subject: [PATCH 1/3] msglist test [nfc]: Fix some test descriptions In all of these tests, the message list's narrow is a ChannelNarrow, and all of the deleted messages are in that channel. The tests aren't about whether or not the deleted messages are in the message list's narrow; really they're about whether or not the deleted messages are present in the MessageListView model. --- test/model/message_list_test.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/model/message_list_test.dart b/test/model/message_list_test.dart index c773c2feaf..e3ef152d36 100644 --- a/test/model/message_list_test.dart +++ b/test/model/message_list_test.dart @@ -1337,7 +1337,7 @@ void main() { final stream = eg.stream(); final messages = List.generate(30, (i) => eg.streamMessage(stream: stream)); - test('in narrow', () async { + test('all deleted messages are in the msglist', () async { await prepare(narrow: ChannelNarrow(stream.streamId)); await prepareMessages(foundOldest: true, messages: messages); @@ -1347,7 +1347,7 @@ void main() { check(model).messages.length.equals(20); }); - test('not all in narrow', () async { + test('some deleted messages are in the msglist, some not', () async { await prepare(narrow: ChannelNarrow(stream.streamId)); await prepareMessages(foundOldest: true, messages: messages.sublist(5)); @@ -1357,7 +1357,7 @@ void main() { check(model).messages.length.equals(20); }); - test('not in narrow', () async { + test('none of the deleted messages are in the msglist', () async { await prepare(narrow: ChannelNarrow(stream.streamId)); await prepareMessages(foundOldest: true, messages: messages.sublist(5)); @@ -1367,7 +1367,7 @@ void main() { check(model).messages.length.equals(25); }); - test('complete message deletion', () async { + test('deleted messages are exactly those in the msglist', () async { await prepare(narrow: ChannelNarrow(stream.streamId)); await prepareMessages(foundOldest: true, messages: messages.sublist(0, 25)); @@ -1377,7 +1377,7 @@ void main() { check(model).messages.length.equals(0); }); - test('non-consecutive message deletion', () async { + test('deleted messages are present non-consecutively in the msglist', () async { await prepare(narrow: ChannelNarrow(stream.streamId)); await prepareMessages(foundOldest: true, messages: messages); final messagesToDelete = messages.sublist(2, 5) + messages.sublist(10, 15); From 84713766992f3c489f421a9f25a397d2c460209f Mon Sep 17 00:00:00 2001 From: Chris Bobbe Date: Thu, 13 Nov 2025 14:11:56 -0800 Subject: [PATCH 2/3] msglist test: Switch some model tests to use subscribed channels Before this, in all the tests touched here, we were exercising the message list with a channel that isn't actually in the PerAccountStore. When we don't pass `stream` to the `prepare` function, the function adds a *different* channel to the store, with a corresponding Subscription, having streamId eg.defaultStreamMessageStreamId. The normal, boring setup, which is suitable for all these tests, is to exercise the message list in a known, subscribed channel. Provide that setup by passing the same `stream` object to `prepare` that we use to create messages and narrows. --- test/model/message_list_test.dart | 42 +++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/test/model/message_list_test.dart b/test/model/message_list_test.dart index e3ef152d36..7a75647d9d 100644 --- a/test/model/message_list_test.dart +++ b/test/model/message_list_test.dart @@ -359,7 +359,7 @@ void main() { test('ignore [OutboxMessage]s outside narrow or with `hidden: true`', () => awaitFakeAsync((async) async { final stream = eg.stream(); final otherStream = eg.stream(); - await prepare(narrow: ChannelNarrow(stream.streamId)); + await prepare(narrow: ChannelNarrow(stream.streamId), stream: stream); await store.setUserTopic(stream, 'muted', UserTopicVisibilityPolicy.muted); await prepareOutboxMessagesTo([ StreamDestination(stream.streamId, eg.t('topic')), @@ -731,7 +731,7 @@ void main() { group('MessageEvent', () { test('in narrow', () async { final stream = eg.stream(); - await prepare(narrow: ChannelNarrow(stream.streamId)); + await prepare(narrow: ChannelNarrow(stream.streamId), stream: stream); await prepareMessages(foundOldest: true, messages: List.generate(30, (i) => eg.streamMessage(stream: stream))); @@ -743,7 +743,7 @@ void main() { test('not in narrow', () async { final stream = eg.stream(); - await prepare(narrow: ChannelNarrow(stream.streamId)); + await prepare(narrow: ChannelNarrow(stream.streamId), stream: stream); await prepareMessages(foundOldest: true, messages: List.generate(30, (i) => eg.streamMessage(stream: stream))); @@ -756,7 +756,7 @@ void main() { test('while in mid-history', () async { final stream = eg.stream(); - await prepare(narrow: ChannelNarrow(stream.streamId), + await prepare(narrow: ChannelNarrow(stream.streamId), stream: stream, anchor: NumericAnchor(1000)); await prepareMessages(foundOldest: true, foundNewest: false, messages: List.generate(30, (i) => eg.streamMessage(id: 1000 + i, stream: stream))); @@ -769,7 +769,7 @@ void main() { test('before fetch', () async { final stream = eg.stream(); - await prepare(narrow: ChannelNarrow(stream.streamId)); + await prepare(narrow: ChannelNarrow(stream.streamId), stream: stream); await store.addMessage(eg.streamMessage(stream: stream)); checkNotNotified(); check(model).fetched.isFalse(); @@ -777,7 +777,7 @@ void main() { test('when there are outbox messages', () => awaitFakeAsync((async) async { final stream = eg.stream(); - await prepare(narrow: ChannelNarrow(stream.streamId)); + await prepare(narrow: ChannelNarrow(stream.streamId), stream: stream); await prepareMessages(foundOldest: true, messages: List.generate(30, (i) => eg.streamMessage(stream: stream))); @@ -797,7 +797,7 @@ void main() { test('from another client (localMessageId present but unrecognized)', () => awaitFakeAsync((async) async { final stream = eg.stream(); - await prepare(narrow: eg.topicNarrow(stream.streamId, 'topic')); + await prepare(narrow: eg.topicNarrow(stream.streamId, 'topic'), stream: stream); await prepareMessages(foundOldest: true, messages: List.generate(30, (i) => eg.streamMessage(stream: stream, topic: 'topic'))); @@ -820,7 +820,7 @@ void main() { test('for an OutboxMessage in the narrow', () => awaitFakeAsync((async) async { final stream = eg.stream(); - await prepare(narrow: ChannelNarrow(stream.streamId)); + await prepare(narrow: ChannelNarrow(stream.streamId), stream: stream); await prepareMessages(foundOldest: true, messages: List.generate(30, (i) => eg.streamMessage(stream: stream))); @@ -846,7 +846,7 @@ void main() { test('for an OutboxMessage outside the narrow', () => awaitFakeAsync((async) async { final stream = eg.stream(); - await prepare(narrow: eg.topicNarrow(stream.streamId, 'topic')); + await prepare(narrow: eg.topicNarrow(stream.streamId, 'topic'), stream: stream); await prepareMessages(foundOldest: true, messages: List.generate(30, (i) => eg.streamMessage(stream: stream, topic: 'topic'))); @@ -897,7 +897,7 @@ void main() { })); test('before fetch', () => awaitFakeAsync((async) async { - await prepare(narrow: ChannelNarrow(stream.streamId)); + await prepare(narrow: ChannelNarrow(stream.streamId), stream: stream); await prepareOutboxMessages(count: 5, stream: stream); check(model) ..fetched.isFalse() @@ -1338,7 +1338,7 @@ void main() { final messages = List.generate(30, (i) => eg.streamMessage(stream: stream)); test('all deleted messages are in the msglist', () async { - await prepare(narrow: ChannelNarrow(stream.streamId)); + await prepare(narrow: ChannelNarrow(stream.streamId), stream: stream); await prepareMessages(foundOldest: true, messages: messages); check(model).messages.length.equals(30); @@ -1348,7 +1348,7 @@ void main() { }); test('some deleted messages are in the msglist, some not', () async { - await prepare(narrow: ChannelNarrow(stream.streamId)); + await prepare(narrow: ChannelNarrow(stream.streamId), stream: stream); await prepareMessages(foundOldest: true, messages: messages.sublist(5)); check(model).messages.length.equals(25); @@ -1358,7 +1358,7 @@ void main() { }); test('none of the deleted messages are in the msglist', () async { - await prepare(narrow: ChannelNarrow(stream.streamId)); + await prepare(narrow: ChannelNarrow(stream.streamId), stream: stream); await prepareMessages(foundOldest: true, messages: messages.sublist(5)); check(model).messages.length.equals(25); @@ -1368,7 +1368,7 @@ void main() { }); test('deleted messages are exactly those in the msglist', () async { - await prepare(narrow: ChannelNarrow(stream.streamId)); + await prepare(narrow: ChannelNarrow(stream.streamId), stream: stream); await prepareMessages(foundOldest: true, messages: messages.sublist(0, 25)); check(model).messages.length.equals(25); @@ -1378,7 +1378,7 @@ void main() { }); test('deleted messages are present non-consecutively in the msglist', () async { - await prepare(narrow: ChannelNarrow(stream.streamId)); + await prepare(narrow: ChannelNarrow(stream.streamId), stream: stream); await prepareMessages(foundOldest: true, messages: messages); final messagesToDelete = messages.sublist(2, 5) + messages.sublist(10, 15); @@ -1502,7 +1502,7 @@ void main() { test('message absent', () async { final stream = eg.stream(); final narrow = ChannelNarrow(stream.streamId); - await prepare(narrow: narrow); + await prepare(narrow: narrow, stream: stream); final messagesInNarrow = List.generate(10, (i) => eg.streamMessage(id: 10 + i, stream: stream)); @@ -2214,7 +2214,7 @@ void main() { test('reassemble', () async { final stream = eg.stream(); - await prepare(narrow: ChannelNarrow(stream.streamId)); + await prepare(narrow: ChannelNarrow(stream.streamId), stream: stream); await prepareMessages(foundOldest: true, messages: List.generate(30, (i) => eg.streamMessage(stream: stream))); await store.addMessage(eg.streamMessage(stream: stream)); @@ -2721,7 +2721,7 @@ void main() { group('handle content parsing into subclasses of ZulipMessageContent', () { test('ZulipContent', () async { final stream = eg.stream(); - await prepare(narrow: ChannelNarrow(stream.streamId)); + await prepare(narrow: ChannelNarrow(stream.streamId), stream: stream); await prepareMessages(foundOldest: true, messages: []); await store.addMessage(eg.streamMessage(stream: stream)); @@ -2735,7 +2735,7 @@ void main() { test('PollContent', () async { final stream = eg.stream(); - await prepare(narrow: ChannelNarrow(stream.streamId)); + await prepare(narrow: ChannelNarrow(stream.streamId), stream: stream); await prepareMessages(foundOldest: true, messages: []); await store.addMessage(eg.streamMessage( @@ -2759,7 +2759,7 @@ void main() { final stream = eg.stream(); final message = eg.streamMessage(stream: stream, topic: 'topic', timestamp: eg.utcTimestamp(clock.daysAgo(1))); - await prepare(narrow: ChannelNarrow(stream.streamId)); + await prepare(narrow: ChannelNarrow(stream.streamId), stream: stream); await prepareMessages(foundOldest: true, messages: [message]); // `findItemWithMessageId` uses binary search. Set up just enough @@ -2782,7 +2782,7 @@ void main() { final stream = eg.stream(); final message = eg.streamMessage(stream: stream, topic: 'topic', timestamp: eg.utcTimestamp(clock.now())); - await prepare(narrow: ChannelNarrow(stream.streamId)); + await prepare(narrow: ChannelNarrow(stream.streamId), stream: stream); await prepareMessages(foundOldest: true, messages: [message]); // `findItemWithMessageId` uses binary search. Set up just enough From ba79306eff644f935290b423e53092df01ed4090 Mon Sep 17 00:00:00 2001 From: Chris Bobbe Date: Thu, 13 Nov 2025 12:37:00 -0800 Subject: [PATCH 3/3] message test: Use known, subscribed channel in sendMessage smoke test This is the boring, common case that makes sense to exercise here. --- test/model/message_test.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/model/message_test.dart b/test/model/message_test.dart index 96d95c0c04..31c24c0c0e 100644 --- a/test/model/message_test.dart +++ b/test/model/message_test.dart @@ -126,10 +126,13 @@ void main() { group('sendMessage', () { test('smoke', () async { + final stream = eg.stream(); + final subscription = eg.subscription(stream); final store = eg.store(initialSnapshot: eg.initialSnapshot( queueId: 'fb67bf8a-c031-47cc-84cf-ed80accacda8')); + await store.addStream(stream); + await store.addSubscription(subscription); final connection = store.connection as FakeApiConnection; - final stream = eg.stream(); connection.prepare(json: SendMessageResult(id: 12345).toJson()); await store.sendMessage( destination: StreamDestination(stream.streamId, eg.t('world')),