1
+ import 'dart:async' ;
1
2
import 'dart:convert' ;
2
3
3
4
import 'package:checks/checks.dart' ;
@@ -15,13 +16,16 @@ import 'package:zulip/model/localizations.dart';
15
16
import 'package:zulip/model/narrow.dart' ;
16
17
import 'package:zulip/model/store.dart' ;
17
18
import 'package:zulip/model/typing_status.dart' ;
19
+ import 'package:zulip/widgets/app.dart' ;
18
20
import 'package:zulip/widgets/compose_box.dart' ;
21
+ import 'package:zulip/widgets/page.dart' ;
19
22
20
23
import '../api/fake_api.dart' ;
21
24
import '../example_data.dart' as eg;
22
25
import '../flutter_checks.dart' ;
23
26
import '../model/binding.dart' ;
24
27
import '../model/test_store.dart' ;
28
+ import '../model/typing_status_test.dart' ;
25
29
import '../stdlib_checks.dart' ;
26
30
import 'dialog_checks.dart' ;
27
31
import 'test_app.dart' ;
@@ -216,6 +220,149 @@ void main() {
216
220
});
217
221
});
218
222
223
+ group ('ComposeBox typing notices' , () {
224
+ const narrow = TopicNarrow (123 , 'some topic' );
225
+
226
+ void checkTypingRequest (TypingOp op, SendableNarrow narrow) =>
227
+ checkSetTypingStatusRequests (connection.takeRequests (), [(op, narrow)]);
228
+
229
+ Future <void > checkStartTyping (WidgetTester tester, SendableNarrow narrow) async {
230
+ connection.prepare (json: {});
231
+ await tester.enterText (contentInputFinder, 'hello world' );
232
+ checkTypingRequest (TypingOp .start, narrow);
233
+ }
234
+
235
+ testWidgets ('smoke TopicNarrow' , (tester) async {
236
+ await prepareComposeBox (tester, narrow: narrow);
237
+
238
+ await checkStartTyping (tester, narrow);
239
+
240
+ connection.prepare (json: {});
241
+ await tester.pump (store.typingNotifier.typingStoppedWaitPeriod);
242
+ checkTypingRequest (TypingOp .stop, narrow);
243
+ });
244
+
245
+ testWidgets ('smoke DmNarrow' , (tester) async {
246
+ final narrow = DmNarrow .withUsers (
247
+ [eg.otherUser.userId], selfUserId: eg.selfUser.userId);
248
+ await prepareComposeBox (tester, narrow: narrow);
249
+
250
+ await checkStartTyping (tester, narrow);
251
+
252
+ connection.prepare (json: {});
253
+ await tester.pump (store.typingNotifier.typingStoppedWaitPeriod);
254
+ checkTypingRequest (TypingOp .stop, narrow);
255
+ });
256
+
257
+ testWidgets ('smoke ChannelNarrow' , (tester) async {
258
+ const narrow = ChannelNarrow (123 );
259
+ final destinationNarrow = TopicNarrow (narrow.streamId, 'test topic' );
260
+ await prepareComposeBox (
261
+ tester, narrow: narrow, topic: destinationNarrow.topic);
262
+
263
+ await checkStartTyping (tester, destinationNarrow);
264
+
265
+ connection.prepare (json: {});
266
+ await tester.pump (store.typingNotifier.typingStoppedWaitPeriod);
267
+ checkTypingRequest (TypingOp .stop, destinationNarrow);
268
+ });
269
+
270
+ testWidgets ('clearing text sends a "typing stopped" notice' , (tester) async {
271
+ await prepareComposeBox (tester, narrow: narrow);
272
+
273
+ await checkStartTyping (tester, narrow);
274
+
275
+ connection.prepare (json: {});
276
+ await tester.enterText (contentInputFinder, '' );
277
+ checkTypingRequest (TypingOp .stop, narrow);
278
+ });
279
+
280
+ testWidgets ('hitting send button sends a "typing stopped" notice' , (tester) async {
281
+ await prepareComposeBox (tester, narrow: narrow);
282
+
283
+ await checkStartTyping (tester, narrow);
284
+
285
+ connection.prepare (json: {});
286
+ connection.prepare (json: SendMessageResult (id: 123 ).toJson ());
287
+ await tester.tap (find.byIcon (Icons .send));
288
+ await tester.pump (Duration .zero);
289
+ final requests = connection.takeRequests ();
290
+ checkSetTypingStatusRequests ([requests.first], [(TypingOp .stop, narrow)]);
291
+ check (requests).length.equals (2 );
292
+ });
293
+
294
+ Future <void > prepareComposeBoxWithNavigation (WidgetTester tester) async {
295
+ addTearDown (testBinding.reset);
296
+ await testBinding.globalStore.add (eg.selfAccount, eg.initialSnapshot ());
297
+
298
+ store = await testBinding.globalStore.perAccount (eg.selfAccount.id);
299
+ connection = store.connection as FakeApiConnection ;
300
+
301
+ await tester.pumpWidget (const ZulipApp ());
302
+ await tester.pump ();
303
+ final navigator = await ZulipApp .navigator;
304
+ unawaited (navigator.push (MaterialAccountWidgetRoute (
305
+ accountId: eg.selfAccount.id, page: const ComposeBox (narrow: narrow))));
306
+ await tester.pumpAndSettle ();
307
+ }
308
+
309
+ testWidgets ('navigating away sends a "typing stopped" notice' , (tester) async {
310
+ await prepareComposeBoxWithNavigation (tester);
311
+
312
+ await checkStartTyping (tester, narrow);
313
+
314
+ connection.prepare (json: {});
315
+ (await ZulipApp .navigator).pop ();
316
+ await tester.pump (Duration .zero);
317
+ checkTypingRequest (TypingOp .stop, narrow);
318
+ });
319
+
320
+ testWidgets ('for content input, unfocusing sends a "typing stopped" notice '
321
+ 'and refocusing sends a "typing started" notice' , (tester) async {
322
+ const narrow = ChannelNarrow (123 );
323
+ final destinationNarrow = TopicNarrow (narrow.streamId, 'test topic' );
324
+ await prepareComposeBox (
325
+ tester, narrow: narrow, topic: destinationNarrow.topic);
326
+
327
+ await checkStartTyping (tester, destinationNarrow);
328
+
329
+ connection.prepare (json: {});
330
+ FocusManager .instance.primaryFocus! .unfocus ();
331
+ await tester.pump (Duration .zero);
332
+ checkTypingRequest (TypingOp .stop, destinationNarrow);
333
+
334
+ connection.prepare (json: {});
335
+ await tester.tap (contentInputFinder);
336
+ checkTypingRequest (TypingOp .start, destinationNarrow);
337
+
338
+ // Ensures that a "typing stopped" notice is sent when the test ends.
339
+ connection.prepare (json: {});
340
+ await tester.pump (store.typingNotifier.typingStoppedWaitPeriod);
341
+ checkTypingRequest (TypingOp .stop, destinationNarrow);
342
+ });
343
+
344
+ testWidgets ('selection change sends a "typing started" notice' , (tester) async {
345
+ final controllerKey = await prepareComposeBox (tester, narrow: narrow);
346
+ final composeBoxController = controllerKey.currentState! ;
347
+
348
+ await checkStartTyping (tester, narrow);
349
+
350
+ connection.prepare (json: {});
351
+ await tester.pump (store.typingNotifier.typingStoppedWaitPeriod);
352
+ checkTypingRequest (TypingOp .stop, narrow);
353
+
354
+ connection.prepare (json: {});
355
+ composeBoxController.contentController.selection =
356
+ const TextSelection (baseOffset: 0 , extentOffset: 2 );
357
+ checkTypingRequest (TypingOp .start, narrow);
358
+
359
+ // Ensures that a "typing stopped" notice is sent when the test ends.
360
+ connection.prepare (json: {});
361
+ await tester.pump (store.typingNotifier.typingStoppedWaitPeriod);
362
+ checkTypingRequest (TypingOp .stop, narrow);
363
+ });
364
+ });
365
+
219
366
group ('message-send request response' , () {
220
367
Future <void > setupAndTapSend (WidgetTester tester, {
221
368
required void Function (int messageId) prepareResponse,
0 commit comments