@@ -4,6 +4,7 @@ import 'dart:io';
4
4
5
5
import 'package:checks/checks.dart' ;
6
6
import 'package:file_picker/file_picker.dart' ;
7
+ import 'package:flutter/services.dart' ;
7
8
import 'package:flutter_checks/flutter_checks.dart' ;
8
9
import 'package:http/http.dart' as http;
9
10
import 'package:flutter/material.dart' ;
@@ -690,6 +691,106 @@ void main() {
690
691
// target platform the test is simulating.
691
692
// TODO(upstream): unskip after fix to https://github.com/flutter/flutter/issues/161073
692
693
skip: Platform .isWindows);
694
+
695
+ group ('attach from keyboard' , () {
696
+ // This is adapted from:
697
+ // https://github.com/flutter/flutter/blob/0ffc4ce00/packages/flutter/test/widgets/editable_text_test.dart#L724-L740
698
+ Future <void > insertContentFromKeyboard (WidgetTester tester, {
699
+ required List <int >? data,
700
+ required String attachedFileUrl,
701
+ required String mimeType,
702
+ }) async {
703
+ await tester.showKeyboard (contentInputFinder);
704
+ // This invokes [EditableText.performAction] on the content [TextField],
705
+ // which did not expose an API for testing.
706
+ // TODO(upstream): support a better API for testing this
707
+ await tester.binding.defaultBinaryMessenger.handlePlatformMessage (
708
+ SystemChannels .textInput.name,
709
+ SystemChannels .textInput.codec.encodeMethodCall (
710
+ MethodCall ('TextInputClient.performAction' , < dynamic > [
711
+ - 1 ,
712
+ 'TextInputAction.commitContent' ,
713
+ // This fakes data originally provided by the Flutter engine:
714
+ // https://github.com/flutter/flutter/blob/0ffc4ce00/engine/src/flutter/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java#L497-L548
715
+ {
716
+ "mimeType" : mimeType,
717
+ "data" : data,
718
+ "uri" : attachedFileUrl,
719
+ },
720
+ ])),
721
+ (ByteData ? data) {});
722
+ }
723
+
724
+ testWidgets ('success' , (tester) async {
725
+ const fileContent = [1 , 0 , 1 , 0 , 0 ];
726
+ await prepare (tester);
727
+ const uploadUrl = '/user_uploads/1/4e/m2A3MSqFnWRLUf9SaPzQ0Up_/test.gif' ;
728
+ connection.prepare (json: UploadFileResult (uri: uploadUrl).toJson ());
729
+ await insertContentFromKeyboard (tester,
730
+ data: fileContent,
731
+ attachedFileUrl:
732
+ 'content://com.zulip.android.zulipboard.provider'
733
+ '/root/com.zulip.android.zulipboard/candidate_temp/test.gif' ,
734
+ mimeType: 'image/gif' );
735
+
736
+ await tester.pump ();
737
+ check (controller! .content.text)
738
+ .equals ('see image: [Uploading test.gif…]()\n\n ' );
739
+ // (the request is checked more thoroughly in API tests)
740
+ check (connection.lastRequest! ).isA< http.MultipartRequest > ()
741
+ ..method.equals ('POST' )
742
+ ..files.single.which ((it) => it
743
+ ..field.equals ('file' )
744
+ ..length.equals (fileContent.length)
745
+ ..filename.equals ('test.gif' )
746
+ ..contentType.asString.equals ('image/gif' )
747
+ ..has <Future <List <int >>>((f) => f.finalize ().toBytes (), 'contents' )
748
+ .completes ((it) => it.deepEquals (fileContent))
749
+ );
750
+ checkAppearsLoading (tester, true );
751
+
752
+ await tester.pump (Duration .zero);
753
+ check (controller! .content.text)
754
+ .equals ('see image: [test.gif]($uploadUrl )\n\n ' );
755
+ checkAppearsLoading (tester, false );
756
+ });
757
+
758
+ testWidgets ('data is null' , (tester) async {
759
+ await prepare (tester);
760
+ await insertContentFromKeyboard (tester,
761
+ data: null ,
762
+ attachedFileUrl:
763
+ 'content://com.zulip.android.zulipboard.provider'
764
+ '/root/com.zulip.android.zulipboard/candidate_temp/test.gif' ,
765
+ mimeType: 'image/jpeg' );
766
+
767
+ await tester.pump ();
768
+ check (controller! .content.text).equals ('see image: ' );
769
+ check (connection.takeRequests ()).isEmpty ();
770
+ checkErrorDialog (tester,
771
+ expectedTitle: 'Content not inserted' ,
772
+ expectedMessage: 'The file to be inserted is empty or cannot be accessed.' );
773
+ checkAppearsLoading (tester, false );
774
+ });
775
+
776
+ testWidgets ('data is empty' , (tester) async {
777
+ await prepare (tester);
778
+ await insertContentFromKeyboard (tester,
779
+ data: [],
780
+ attachedFileUrl:
781
+ 'content://com.zulip.android.zulipboard.provider'
782
+ '/root/com.zulip.android.zulipboard/candidate_temp/test.gif' ,
783
+ mimeType: 'image/jpeg' );
784
+
785
+ await tester.pump ();
786
+ check (controller! .content.text).equals ('see image: ' );
787
+ check (connection.takeRequests ()).isEmpty ();
788
+ checkErrorDialog (tester,
789
+ expectedTitle: 'Content not inserted' ,
790
+ expectedMessage: 'The file to be inserted is empty or cannot be accessed.' );
791
+ checkAppearsLoading (tester, false );
792
+ });
793
+ });
693
794
});
694
795
695
796
group ('error banner' , () {
0 commit comments