@@ -3,6 +3,7 @@ import 'dart:convert';
3
3
4
4
import 'package:checks/checks.dart' ;
5
5
import 'package:file_picker/file_picker.dart' ;
6
+ import 'package:flutter/services.dart' ;
6
7
import 'package:flutter_checks/flutter_checks.dart' ;
7
8
import 'package:http/http.dart' as http;
8
9
import 'package:flutter/material.dart' ;
@@ -575,6 +576,113 @@ void main() {
575
576
576
577
// TODO test what happens when capturing/uploading fails
577
578
});
579
+
580
+ group ('attach from keyboard' , () {
581
+ Future <void > insertContentFromKeyboard (WidgetTester tester, {
582
+ required List <int > data,
583
+ required String attachedFileUrl,
584
+ required String mimeType,
585
+ }) async {
586
+ // Setup adapted from:
587
+ // https://github.com/flutter/flutter/blob/0ffc4ce00ea7bb912e379adf39354644eab2c17e/packages/flutter/test/widgets/editable_text_test.dart#L724-L740
588
+ // This is later used to invoke [EditableText]'s implementation of
589
+ // [TextInputClient.performAction] on the content [TextField],
590
+ // which did not expose an API accessible during testing.
591
+ final ByteData ? messageBytes = const JSONMessageCodec ().encodeMessage ({
592
+ 'args' : [
593
+ - 1 ,
594
+ 'TextInputAction.commitContent' ,
595
+ {
596
+ "mimeType" : mimeType,
597
+ "data" : data,
598
+ "uri" : attachedFileUrl,
599
+ },
600
+ ],
601
+ 'method' : 'TextInputClient.performAction' ,
602
+ });
603
+ await tester.binding.defaultBinaryMessenger.handlePlatformMessage (
604
+ 'flutter/textinput' ,
605
+ messageBytes,
606
+ (ByteData ? _) {},
607
+ );
608
+ }
609
+
610
+ testWidgets ('empty file' , (tester) async {
611
+ await prepare (tester);
612
+ await insertContentFromKeyboard (tester,
613
+ data: [],
614
+ attachedFileUrl:
615
+ 'content://com.samsung.android.zulipboard.provider'
616
+ '/root/com.zulip.android.zulipboard/candidate_temp/test.gif' ,
617
+ mimeType: 'image/jpeg' );
618
+
619
+ await tester.pump ();
620
+ check (controller! .content.text)
621
+ .equals ('see image: ' );
622
+ check (connection.takeRequests ()).isEmpty ();
623
+ checkAppearsLoading (tester, false );
624
+ });
625
+
626
+ final fileContent = [1 , 0 , 1 , 0 , 0 ];
627
+
628
+ testWidgets ('no name' , (tester) async {
629
+ await prepare (tester);
630
+ const uploadUrl = '/user_uploads/1/4e/m2A3MSqFnWRLUf9SaPzQ0Up_/file' ;
631
+ connection.prepare (json: UploadFileResult (uri: uploadUrl).toJson ());
632
+ await insertContentFromKeyboard (tester,
633
+ data: fileContent,
634
+ attachedFileUrl: 'content://com.zulip.android.zulipboard.provider' ,
635
+ mimeType: 'image/jpeg' );
636
+
637
+ await tester.pump ();
638
+ check (controller! .content.text)
639
+ .equals ('see image: [Uploading file…]()\n\n ' );
640
+ check (connection.lastRequest! ).isA< http.MultipartRequest > ()
641
+ ..method.equals ('POST' )
642
+ ..files.single.which ((it) => it
643
+ ..field.equals ('file' )
644
+ ..length.equals (fileContent.length)
645
+ ..filename.equals ('file' )
646
+ ..contentType.asString.equals ('image/jpeg' )
647
+ ..has <Future <List <int >>>((f) => f.finalize ().toBytes (), 'contents' )
648
+ .completes ((it) => it.deepEquals (fileContent))
649
+ );
650
+
651
+ await tester.pump (Duration .zero);
652
+ check (controller! .content.text)
653
+ .equals ('see image: [file]($uploadUrl )\n\n ' );
654
+ });
655
+
656
+ testWidgets ('name' , (tester) async {
657
+ await prepare (tester);
658
+ const uploadUrl = '/user_uploads/1/4e/m2A3MSqFnWRLUf9SaPzQ0Up_/test.gif' ;
659
+ connection.prepare (json: UploadFileResult (uri: uploadUrl).toJson ());
660
+ await insertContentFromKeyboard (tester,
661
+ data: fileContent,
662
+ attachedFileUrl:
663
+ 'content://com.samsung.android.zulipboard.provider'
664
+ '/root/com.zulip.android.zulipboard/candidate_temp/test.gif' ,
665
+ mimeType: 'image/gif' );
666
+
667
+ await tester.pump ();
668
+ check (controller! .content.text)
669
+ .equals ('see image: [Uploading test.gif…]()\n\n ' );
670
+ check (connection.lastRequest! ).isA< http.MultipartRequest > ()
671
+ ..method.equals ('POST' )
672
+ ..files.single.which ((it) => it
673
+ ..field.equals ('file' )
674
+ ..length.equals (fileContent.length)
675
+ ..filename.equals ('test.gif' )
676
+ ..contentType.asString.equals ('image/gif' )
677
+ ..has <Future <List <int >>>((f) => f.finalize ().toBytes (), 'contents' )
678
+ .completes ((it) => it.deepEquals (fileContent))
679
+ );
680
+
681
+ await tester.pump (Duration .zero);
682
+ check (controller! .content.text)
683
+ .equals ('see image: [test.gif]($uploadUrl )\n\n ' );
684
+ });
685
+ });
578
686
});
579
687
580
688
group ('error banner' , () {
0 commit comments