1
+ import 'package:checks/checks.dart' ;
2
+ import 'package:test/scaffolding.dart' ;
3
+ import 'package:zulip/api/model/events.dart' ;
4
+ import 'package:zulip/api/model/model.dart' ;
5
+ import 'package:zulip/api/route/messages.dart' ;
6
+ import 'package:zulip/model/message_list.dart' ;
7
+ import 'package:zulip/model/narrow.dart' ;
8
+ import 'package:zulip/model/store.dart' ;
9
+ import '../api/fake_api.dart' ;
10
+ import '../api/model/model_checks.dart' ;
11
+ import '../model/binding.dart' ;
12
+ import '../model/test_store.dart' ;
13
+ import '../example_data.dart' as eg;
14
+
15
+ const int userId = 1 ;
16
+ const int streamId = 2 ;
17
+
18
+ Future <PerAccountStore > setupStore (ZulipStream stream) async {
19
+ addTearDown (TestZulipBinding .instance.reset);
20
+
21
+ await TestZulipBinding .instance.globalStore.add (eg.selfAccount, eg.initialSnapshot ());
22
+
23
+ final store = await TestZulipBinding .instance.globalStore.perAccount (eg.selfAccount.id);
24
+ store.addUser (eg.user (userId: userId));
25
+ store.addStream (stream);
26
+
27
+ return store;
28
+ }
29
+
30
+ Future <MessageListView > messageListViewWithMessages (List <Message > messages, PerAccountStore store, Narrow narrow) async {
31
+ final messageList = MessageListView .init (store: store, narrow: narrow);
32
+
33
+ final connection = store.connection as FakeApiConnection ;
34
+
35
+ connection.prepare (json: GetMessagesResult (
36
+ anchor: messages.first.id,
37
+ foundNewest: true ,
38
+ foundOldest: true ,
39
+ foundAnchor: true ,
40
+ historyLimited: false ,
41
+ messages: messages,
42
+ ).toJson ());
43
+
44
+ await messageList.fetch ();
45
+
46
+ check (messageList.messages.length).equals (messages.length);
47
+
48
+ return messageList;
49
+ }
50
+
51
+ void main () async {
52
+ TestZulipBinding .ensureInitialized ();
53
+
54
+ const narrow = StreamNarrow (streamId);
55
+ final stream = eg.stream (streamId: streamId);
56
+
57
+ group ('update message tests' , () {
58
+
59
+ test ('find message in message list returns index of message' , () async {
60
+ final store = await setupStore (stream);
61
+
62
+ final m1 = eg.streamMessage (id: 792 , stream: stream);
63
+ final m2 = eg.streamMessage (id: 793 , stream: stream);
64
+ final m3 = eg.streamMessage (id: 794 , stream: stream);
65
+
66
+ final messageList = await messageListViewWithMessages ([m1, m2, m3], store, narrow);
67
+
68
+ var idx = messageList.findMessageWithId (793 );
69
+ check (idx).equals (1 );
70
+
71
+ idx = messageList.findMessageWithId (999 );
72
+ check (idx).equals (- 1 );
73
+ });
74
+
75
+ test ('update events are correctly applied to message when it is in the stream' , () async {
76
+ final store = await setupStore (stream);
77
+
78
+ const oldContent = "<p>Hello, world</p>" ;
79
+ const newContent = "<p>Hello, edited</p>" ;
80
+ const newTimestamp = 99999 ;
81
+
82
+ List <String > oldFlags = [];
83
+ List <String > newFlags = ["starred" ];
84
+
85
+ final mockMessage = eg.streamMessage (id: 243 , stream: stream, content: oldContent, flags: oldFlags);
86
+ final messageList = await messageListViewWithMessages ([mockMessage], store, narrow);
87
+
88
+ final updateEvent = UpdateMessageEvent (
89
+ id: 1 ,
90
+ messageId: mockMessage.id,
91
+ messageIds: [mockMessage.id],
92
+ flags: newFlags,
93
+ renderedContent: newContent,
94
+ editTimestamp: newTimestamp,
95
+ isMeMessage: true ,
96
+ userId: userId
97
+ );
98
+
99
+ final message = messageList.messages[0 ];
100
+ check (message)
101
+ ..content.equals (oldContent)
102
+ ..flags.deepEquals (oldFlags)
103
+ ..isMeMessage.equals (false );
104
+
105
+ var listenersNotified = false ;
106
+
107
+ messageList.addListener (() { listenersNotified = true ; });
108
+ messageList.maybeUpdateMessage (updateEvent);
109
+
110
+ final updatedMessage = messageList.messages[0 ];
111
+ check (updatedMessage).identicalTo (message);
112
+ check (listenersNotified).equals (true );
113
+
114
+ check (message)
115
+ ..content.equals (newContent)
116
+ ..lastEditTimestamp.equals (newTimestamp)
117
+ ..flags.equals (newFlags)
118
+ ..isMeMessage.equals (true );
119
+ });
120
+
121
+ test ('update event is ignored when message is not in the message list' , () async {
122
+ final store = await setupStore (stream);
123
+
124
+ const oldContent = "<p>Hello, world</p>" ;
125
+ const newContent = "<p>Hello, edited</p>" ;
126
+ const newTimestamp = 99999 ;
127
+
128
+ final mockMessage = eg.streamMessage (id: 243 , stream: stream, content: oldContent);
129
+ final messageList = await messageListViewWithMessages ([mockMessage], store, narrow);
130
+
131
+ final updateEvent = UpdateMessageEvent (
132
+ id: 1 ,
133
+ messageId: 972 ,
134
+ messageIds: [972 ],
135
+ flags: mockMessage.flags,
136
+ renderedContent: newContent,
137
+ editTimestamp: newTimestamp,
138
+ userId: userId,
139
+ );
140
+
141
+ final message = messageList.messages[0 ];
142
+ check (message).content.equals (oldContent);
143
+
144
+ var listenersNotified = false ;
145
+
146
+ messageList.addListener (() { listenersNotified = true ; });
147
+ messageList.maybeUpdateMessage (updateEvent);
148
+
149
+ check (listenersNotified).equals (false );
150
+ check (message).content.equals (oldContent);
151
+
152
+ });
153
+ test ('rendering-only update does not change timestamp' , () async {
154
+ final store = await setupStore (stream);
155
+
156
+ const oldContent = "<p>Hello, world</p>" ;
157
+ const newContent = "<p>Hello, world</p> <div>Some link preview</div>" ;
158
+ const newTimestamp = 99999 ;
159
+
160
+ final mockMessage = eg.streamMessage (id: 972 , stream: stream, content: oldContent);
161
+ final messageList = await messageListViewWithMessages ([mockMessage], store, narrow);
162
+
163
+ final updateEvent = UpdateMessageEvent (
164
+ id: 1 ,
165
+ messageId: 972 ,
166
+ messageIds: [972 ],
167
+ flags: mockMessage.flags,
168
+ renderedContent: newContent,
169
+ editTimestamp: newTimestamp,
170
+ renderingOnly: true ,
171
+ userId: null ,
172
+ );
173
+
174
+ final message = messageList.messages[0 ];
175
+ messageList.maybeUpdateMessage (updateEvent);
176
+ check (message)
177
+ ..content.equals (newContent)
178
+ ..lastEditTimestamp.isNull ();
179
+ });
180
+
181
+ test ('rendering-only update does not change timestamp (for old server versions)' , () async {
182
+ final store = await setupStore (stream);
183
+
184
+ const oldContent = "<p>Hello, world</p>" ;
185
+ const newContent = "<p>Hello, world</p> <div>Some link preview</div>" ;
186
+ const newTimestamp = 99999 ;
187
+
188
+ final mockMessage = eg.streamMessage (id: 972 , stream: stream, content: oldContent);
189
+ final messageList = await messageListViewWithMessages ([mockMessage], store, narrow);
190
+
191
+ final updateEvent = UpdateMessageEvent (
192
+ id: 1 ,
193
+ messageId: 972 ,
194
+ messageIds: [972 ],
195
+ flags: mockMessage.flags,
196
+ renderedContent: newContent,
197
+ editTimestamp: newTimestamp,
198
+ userId: null ,
199
+ );
200
+
201
+ final message = messageList.messages[0 ];
202
+ messageList.maybeUpdateMessage (updateEvent);
203
+ check (message)
204
+ ..content.equals (newContent)
205
+ ..lastEditTimestamp.isNull ();
206
+ });
207
+
208
+
209
+ });
210
+ }
0 commit comments