1
+ package fr .free .nrw .commons ;
2
+
3
+ import android .Manifest ;
4
+ import android .app .Activity ;
5
+ import android .app .Instrumentation .ActivityResult ;
6
+ import android .content .Context ;
7
+ import android .content .ContextWrapper ;
8
+ import android .content .Intent ;
9
+ import android .graphics .Bitmap ;
10
+ import android .net .Uri ;
11
+ import android .os .Environment ;
12
+ import android .view .autofill .AutofillManager ;
13
+
14
+ import org .junit .Before ;
15
+ import org .junit .Rule ;
16
+ import org .junit .Test ;
17
+ import org .junit .runner .RunWith ;
18
+
19
+ import java .io .File ;
20
+ import java .io .FileOutputStream ;
21
+ import java .io .IOException ;
22
+ import java .text .SimpleDateFormat ;
23
+ import java .util .Date ;
24
+ import java .util .Random ;
25
+
26
+ import androidx .test .espresso .NoMatchingViewException ;
27
+ import androidx .test .espresso .intent .rule .IntentsTestRule ;
28
+ import androidx .test .filters .LargeTest ;
29
+ import androidx .test .platform .app .InstrumentationRegistry ;
30
+ import androidx .test .rule .ActivityTestRule ;
31
+ import androidx .test .rule .GrantPermissionRule ;
32
+ import androidx .test .runner .AndroidJUnit4 ;
33
+ import fr .free .nrw .commons .auth .LoginActivity ;
34
+ import fr .free .nrw .commons .utils .ConfigUtils ;
35
+ import timber .log .Timber ;
36
+
37
+ import static androidx .test .espresso .Espresso .onView ;
38
+ import static androidx .test .espresso .action .ViewActions .clearText ;
39
+ import static androidx .test .espresso .action .ViewActions .click ;
40
+ import static androidx .test .espresso .action .ViewActions .replaceText ;
41
+ import static androidx .test .espresso .action .ViewActions .typeText ;
42
+ import static androidx .test .espresso .assertion .ViewAssertions .matches ;
43
+ import static androidx .test .espresso .intent .Intents .intended ;
44
+ import static androidx .test .espresso .intent .Intents .intending ;
45
+ import static androidx .test .espresso .intent .matcher .IntentMatchers .hasAction ;
46
+ import static androidx .test .espresso .intent .matcher .IntentMatchers .hasType ;
47
+ import static androidx .test .espresso .matcher .ViewMatchers .isDisplayed ;
48
+ import static androidx .test .espresso .matcher .ViewMatchers .withId ;
49
+ import static androidx .test .espresso .matcher .ViewMatchers .withParent ;
50
+ import static androidx .test .espresso .matcher .ViewMatchers .withText ;
51
+ import static org .hamcrest .core .AllOf .allOf ;
52
+
53
+ @ LargeTest
54
+ @ RunWith (AndroidJUnit4 .class )
55
+ public class UploadTest {
56
+ @ Rule
57
+ public GrantPermissionRule permissionRule = GrantPermissionRule .grant (Manifest .permission .WRITE_EXTERNAL_STORAGE ,
58
+ Manifest .permission .ACCESS_FINE_LOCATION );
59
+
60
+ @ Rule
61
+ public ActivityTestRule activityRule = new IntentsTestRule <>(LoginActivity .class );
62
+
63
+ @ Before
64
+ public void setup () {
65
+
66
+ saveToInternalStorage ();
67
+ }
68
+
69
+ private void saveToInternalStorage () {
70
+ Bitmap bitmapImage = getRandomBitmap ();
71
+ Context applicationContext = InstrumentationRegistry .getInstrumentation ().getTargetContext ().getApplicationContext ();
72
+ ContextWrapper cw = new ContextWrapper (applicationContext );
73
+ // path to /data/data/yourapp/app_data/imageDir
74
+ File mypath = new File (Environment .getExternalStorageDirectory (), "image.jpg" );
75
+
76
+ Timber .d ("Filepath: %s" , mypath .getPath ());
77
+
78
+ Timber .d ("Absolute Filepath: %s" , mypath .getAbsolutePath ());
79
+
80
+ FileOutputStream fos = null ;
81
+ try {
82
+ fos = new FileOutputStream (mypath );
83
+ // Use the compress method on the BitMap object to write image to the OutputStream
84
+ bitmapImage .compress (Bitmap .CompressFormat .JPEG , 100 , fos );
85
+ } catch (Exception e ) {
86
+ e .printStackTrace ();
87
+ } finally {
88
+ try {
89
+ if (fos != null ) {
90
+ fos .close ();
91
+ }
92
+ } catch (IOException e ) {
93
+ e .printStackTrace ();
94
+ }
95
+ }
96
+ }
97
+
98
+ private Bitmap getRandomBitmap () {
99
+ Random random = new Random ();
100
+ Bitmap bitmap = Bitmap .createBitmap (200 , 200 , Bitmap .Config .ARGB_8888 );
101
+ bitmap .eraseColor (random .nextInt (255 ));
102
+ return bitmap ;
103
+ }
104
+
105
+ private void getToMainActivity () {
106
+ try {
107
+ //Skip tutorial
108
+ onView (withId (R .id .finishTutorialButton ))
109
+ .perform (click ());
110
+
111
+ //Perform Login
112
+ onView (withId (R .id .loginUsername ))
113
+ .perform (clearText (), typeText (BuildConfig .TEST_USERNAME ));
114
+ onView (withId (R .id .loginPassword ))
115
+ .perform (clearText (), typeText (BuildConfig .TEST_PASSWORD ));
116
+ onView (withId (R .id .loginButton ))
117
+ .perform (click ());
118
+ } catch (NoMatchingViewException ignored ) {
119
+ }
120
+ }
121
+
122
+ @ Test
123
+ public void uploadTest () {
124
+ if (!ConfigUtils .isBetaFlavour ()) {
125
+ throw new Error ("This test should only be run in Beta!" );
126
+ }
127
+
128
+ getToMainActivity ();
129
+
130
+ // Uri to return by our mock gallery selector
131
+ // Requires file 'image.jpg' to be placed at root of file structure
132
+ Uri imageUri = Uri .parse ("file://mnt/sdcard/image.jpg" );
133
+
134
+ // Build a result to return from the Camera app
135
+ Intent intent = new Intent ();
136
+ intent .setData (imageUri );
137
+ ActivityResult result = new ActivityResult (Activity .RESULT_OK , intent );
138
+
139
+ // Stub out the File picker. When an intent is sent to the File picker, this tells
140
+ // Espresso to respond with the ActivityResult we just created
141
+ intending (allOf (hasAction (Intent .ACTION_GET_CONTENT ), hasType ("image/*" ))).respondWith (result );
142
+
143
+ // Open FAB
144
+ onView (allOf (withId (R .id .fab_plus ), isDisplayed ()))
145
+ .perform (click ());
146
+
147
+ // Click gallery
148
+ onView (allOf (withId (R .id .fab_gallery ), isDisplayed ()))
149
+ .perform (click ());
150
+
151
+ // Validate that an intent to get an image is sent
152
+ intended (allOf (hasAction (Intent .ACTION_GET_CONTENT ), hasType ("image/*" )));
153
+
154
+ // Create filename with the current time (to prevent overwrites)
155
+ SimpleDateFormat dateFormat = new SimpleDateFormat ("yyMMdd-hhmmss" );
156
+ String commonsFileName = "MobileTest " + dateFormat .format (new Date ());
157
+
158
+ // Try to dismiss the error, if there is one (probably about duplicate files on Commons)
159
+ try {
160
+ onView (withText ("Yes" ))
161
+ .check (matches (isDisplayed ()))
162
+ .perform (click ());
163
+ } catch (NoMatchingViewException ignored ) {}
164
+
165
+ onView (allOf (withId (R .id .description_item_edit_text ), withParent (withParent (withId (R .id .image_title_container )))))
166
+ .perform (replaceText (commonsFileName ));
167
+
168
+ onView (withId (R .id .bottom_card_next ))
169
+ .perform (click ());
170
+
171
+ try {
172
+ Thread .sleep (500 );
173
+ } catch (InterruptedException e ) {
174
+ e .printStackTrace ();
175
+ }
176
+
177
+ onView (withId (R .id .category_search ))
178
+ .perform (replaceText ("Uploaded with Mobile/Android Tests" ));
179
+
180
+ try {
181
+ Thread .sleep (3000 );
182
+ } catch (InterruptedException e ) {
183
+ e .printStackTrace ();
184
+ }
185
+
186
+ onView (withParent (withId (R .id .categories )))
187
+ .perform (click ());
188
+
189
+ onView (withId (R .id .category_next ))
190
+ .perform (click ());
191
+
192
+ try {
193
+ Thread .sleep (500 );
194
+ } catch (InterruptedException e ) {
195
+ e .printStackTrace ();
196
+ }
197
+
198
+ onView (withId (R .id .submit ))
199
+ .perform (click ());
200
+
201
+ try {
202
+ Thread .sleep (10000 );
203
+ } catch (InterruptedException e ) {
204
+ e .printStackTrace ();
205
+ }
206
+
207
+ String fileUrl = "https://commons.wikimedia.beta.wmflabs.org/wiki/File:" +
208
+ commonsFileName .replace (' ' , '_' ) + ".jpg" ;
209
+ Timber .i ("File should be uploaded to " + fileUrl );
210
+ }
211
+ }
0 commit comments