Skip to content

Commit c5500b1

Browse files
committed
msglist test: Write tests for the rest of MessageListView
For the more recently-added functionality, we'd written tests along the way. But we didn't have tests for the logic we built earlier, which is some of the most core functionality. Add tests for all that logic too.
1 parent 047c2ba commit c5500b1

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed

test/model/message_list_test.dart

+128
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
import 'dart:convert';
2+
13
import 'package:checks/checks.dart';
4+
import 'package:http/http.dart' as http;
25
import 'package:test/scaffolding.dart';
36
import 'package:zulip/api/model/events.dart';
47
import 'package:zulip/api/model/model.dart';
8+
import 'package:zulip/api/model/narrow.dart';
59
import 'package:zulip/api/route/messages.dart';
610
import 'package:zulip/model/content.dart';
711
import 'package:zulip/model/message_list.dart';
@@ -11,6 +15,7 @@ import 'package:zulip/model/store.dart';
1115
import '../api/fake_api.dart';
1216
import '../api/model/model_checks.dart';
1317
import '../example_data.dart' as eg;
18+
import '../stdlib_checks.dart';
1419
import 'content_checks.dart';
1520

1621
void main() async {
@@ -58,6 +63,106 @@ void main() async {
5863
checkNotifiedOnce();
5964
}
6065

66+
void checkLastRequest({
67+
required ApiNarrow narrow,
68+
required String anchor,
69+
bool? includeAnchor,
70+
required int numBefore,
71+
required int numAfter,
72+
}) {
73+
check(connection.lastRequest).isA<http.Request>()
74+
..method.equals('GET')
75+
..url.path.equals('/api/v1/messages')
76+
..url.queryParameters.deepEquals({
77+
'narrow': jsonEncode(narrow),
78+
'anchor': anchor,
79+
if (includeAnchor != null) 'include_anchor': includeAnchor.toString(),
80+
'num_before': numBefore.toString(),
81+
'num_after': numAfter.toString(),
82+
});
83+
}
84+
85+
test('fetch', () async {
86+
const narrow = AllMessagesNarrow();
87+
prepare(narrow: narrow);
88+
connection.prepare(json: newestResult(
89+
foundOldest: false,
90+
messages: List.generate(100, (i) => eg.streamMessage(id: 1000 + i)),
91+
).toJson());
92+
final fetchFuture = model.fetch();
93+
check(model).fetched.isFalse();
94+
checkInvariants(model);
95+
96+
checkNotNotified();
97+
await fetchFuture;
98+
checkNotifiedOnce();
99+
check(model).messages.length.equals(100);
100+
checkLastRequest(
101+
narrow: narrow.apiEncode(),
102+
anchor: 'newest',
103+
numBefore: 100,
104+
numAfter: 10,
105+
);
106+
});
107+
108+
test('fetch, short history', () async {
109+
prepare();
110+
connection.prepare(json: newestResult(
111+
foundOldest: true,
112+
messages: List.generate(30, (i) => eg.streamMessage(id: 1000 + i)),
113+
).toJson());
114+
await model.fetch();
115+
checkNotifiedOnce();
116+
check(model).messages.length.equals(30);
117+
});
118+
119+
test('fetch, no messages found', () async {
120+
prepare();
121+
connection.prepare(json: newestResult(
122+
foundOldest: true,
123+
messages: [],
124+
).toJson());
125+
await model.fetch();
126+
checkNotifiedOnce();
127+
check(model)
128+
..fetched.isTrue()
129+
..messages.isEmpty();
130+
});
131+
132+
test('maybeAddMessage', () async {
133+
final stream = eg.stream();
134+
prepare(narrow: StreamNarrow(stream.streamId));
135+
await prepareMessages(foundOldest: true, messages:
136+
List.generate(30, (i) => eg.streamMessage(id: 1000 + i, stream: stream)));
137+
138+
check(model).messages.length.equals(30);
139+
model.maybeAddMessage(eg.streamMessage(id: 1100, stream: stream));
140+
checkNotifiedOnce();
141+
check(model).messages.length.equals(31);
142+
});
143+
144+
test('maybeAddMessage, not in narrow', () async {
145+
final stream = eg.stream(streamId: 123);
146+
prepare(narrow: StreamNarrow(stream.streamId));
147+
await prepareMessages(foundOldest: true, messages:
148+
List.generate(30, (i) => eg.streamMessage(id: 1000 + i, stream: stream)));
149+
150+
check(model).messages.length.equals(30);
151+
final otherStream = eg.stream(streamId: 234);
152+
model.maybeAddMessage(eg.streamMessage(id: 1100, stream: otherStream));
153+
checkNotNotified();
154+
check(model).messages.length.equals(30);
155+
});
156+
157+
test('maybeAddMessage, before fetch', () async {
158+
final stream = eg.stream();
159+
prepare(narrow: StreamNarrow(stream.streamId));
160+
model.maybeAddMessage(eg.streamMessage(id: 1100, stream: stream));
161+
checkNotNotified();
162+
check(model).fetched.isFalse();
163+
checkInvariants(model);
164+
});
165+
61166
test('findMessageWithId', () async {
62167
prepare();
63168
await prepareMessages(foundOldest: true, messages: [
@@ -254,6 +359,29 @@ void main() async {
254359
});
255360
});
256361
});
362+
363+
test('reassemble', () async {
364+
final stream = eg.stream();
365+
prepare(narrow: StreamNarrow(stream.streamId));
366+
await prepareMessages(foundOldest: true, messages:
367+
List.generate(30, (i) => eg.streamMessage(id: 1000 + i, stream: stream)));
368+
model.maybeAddMessage(eg.streamMessage(id: 1100, stream: stream));
369+
checkNotifiedOnce();
370+
check(model).messages.length.equals(31);
371+
372+
// Mess with model.contents, to simulate it having come from
373+
// a previous version of the code.
374+
final correctContent = parseContent(model.messages[0].content);
375+
model.contents[0] = const ZulipContent(nodes: [
376+
ParagraphNode(links: null, nodes: [TextNode('something outdated')])
377+
]);
378+
check(model.contents[0]).not(it()..equalsNode(correctContent));
379+
380+
model.reassemble();
381+
checkNotifiedOnce();
382+
check(model).messages.length.equals(31);
383+
check(model.contents[0]).equalsNode(correctContent);
384+
});
257385
}
258386

259387
void checkInvariants(MessageListView model) {

0 commit comments

Comments
 (0)