@@ -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' ;
@@ -831,6 +832,106 @@ void main() {
831
832
// target platform the test is simulating.
832
833
// TODO(upstream): unskip after fix to https://github.com/flutter/flutter/issues/161073
833
834
skip: Platform .isWindows);
835
+
836
+ group ('attach from keyboard' , () {
837
+ // This is adapted from:
838
+ // https://github.com/flutter/flutter/blob/0ffc4ce00/packages/flutter/test/widgets/editable_text_test.dart#L724-L740
839
+ Future <void > insertContentFromKeyboard (WidgetTester tester, {
840
+ required List <int >? data,
841
+ required String attachedFileUrl,
842
+ required String mimeType,
843
+ }) async {
844
+ await tester.showKeyboard (contentInputFinder);
845
+ // This invokes [EditableText.performAction] on the content [TextField],
846
+ // which did not expose an API for testing.
847
+ // TODO(upstream): support a better API for testing this
848
+ await tester.binding.defaultBinaryMessenger.handlePlatformMessage (
849
+ SystemChannels .textInput.name,
850
+ SystemChannels .textInput.codec.encodeMethodCall (
851
+ MethodCall ('TextInputClient.performAction' , < dynamic > [
852
+ - 1 ,
853
+ 'TextInputAction.commitContent' ,
854
+ // This fakes data originally provided by the Flutter engine:
855
+ // https://github.com/flutter/flutter/blob/0ffc4ce00/engine/src/flutter/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java#L497-L548
856
+ {
857
+ "mimeType" : mimeType,
858
+ "data" : data,
859
+ "uri" : attachedFileUrl,
860
+ },
861
+ ])),
862
+ (ByteData ? data) {});
863
+ }
864
+
865
+ testWidgets ('success' , (tester) async {
866
+ const fileContent = [1 , 0 , 1 , 0 , 0 ];
867
+ await prepare (tester);
868
+ const uploadUrl = '/user_uploads/1/4e/m2A3MSqFnWRLUf9SaPzQ0Up_/test.gif' ;
869
+ connection.prepare (json: UploadFileResult (uri: uploadUrl).toJson ());
870
+ await insertContentFromKeyboard (tester,
871
+ data: fileContent,
872
+ attachedFileUrl:
873
+ 'content://com.zulip.android.zulipboard.provider'
874
+ '/root/com.zulip.android.zulipboard/candidate_temp/test.gif' ,
875
+ mimeType: 'image/gif' );
876
+
877
+ await tester.pump ();
878
+ check (controller! .content.text)
879
+ .equals ('see image: [Uploading test.gif…]()\n\n ' );
880
+ // (the request is checked more thoroughly in API tests)
881
+ check (connection.lastRequest! ).isA< http.MultipartRequest > ()
882
+ ..method.equals ('POST' )
883
+ ..files.single.which ((it) => it
884
+ ..field.equals ('file' )
885
+ ..length.equals (fileContent.length)
886
+ ..filename.equals ('test.gif' )
887
+ ..contentType.asString.equals ('image/gif' )
888
+ ..has <Future <List <int >>>((f) => f.finalize ().toBytes (), 'contents' )
889
+ .completes ((it) => it.deepEquals (fileContent))
890
+ );
891
+ checkAppearsLoading (tester, true );
892
+
893
+ await tester.pump (Duration .zero);
894
+ check (controller! .content.text)
895
+ .equals ('see image: [test.gif]($uploadUrl )\n\n ' );
896
+ checkAppearsLoading (tester, false );
897
+ });
898
+
899
+ testWidgets ('data is null' , (tester) async {
900
+ await prepare (tester);
901
+ await insertContentFromKeyboard (tester,
902
+ data: null ,
903
+ attachedFileUrl:
904
+ 'content://com.zulip.android.zulipboard.provider'
905
+ '/root/com.zulip.android.zulipboard/candidate_temp/test.gif' ,
906
+ mimeType: 'image/jpeg' );
907
+
908
+ await tester.pump ();
909
+ check (controller! .content.text).equals ('see image: ' );
910
+ check (connection.takeRequests ()).isEmpty ();
911
+ checkErrorDialog (tester,
912
+ expectedTitle: 'Content not inserted' ,
913
+ expectedMessage: 'The file to be inserted is empty or cannot be accessed.' );
914
+ checkAppearsLoading (tester, false );
915
+ });
916
+
917
+ testWidgets ('data is empty' , (tester) async {
918
+ await prepare (tester);
919
+ await insertContentFromKeyboard (tester,
920
+ data: [],
921
+ attachedFileUrl:
922
+ 'content://com.zulip.android.zulipboard.provider'
923
+ '/root/com.zulip.android.zulipboard/candidate_temp/test.gif' ,
924
+ mimeType: 'image/jpeg' );
925
+
926
+ await tester.pump ();
927
+ check (controller! .content.text).equals ('see image: ' );
928
+ check (connection.takeRequests ()).isEmpty ();
929
+ checkErrorDialog (tester,
930
+ expectedTitle: 'Content not inserted' ,
931
+ expectedMessage: 'The file to be inserted is empty or cannot be accessed.' );
932
+ checkAppearsLoading (tester, false );
933
+ });
934
+ });
834
935
});
835
936
836
937
group ('error banner' , () {
0 commit comments