Skip to content

Commit f59926c

Browse files
committed
Basic UI testing with a bit of syncing
1 parent e9cd923 commit f59926c

File tree

7 files changed

+236
-5
lines changed

7 files changed

+236
-5
lines changed

build.gradle

+16
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,19 @@ dependencies {
5656
androidTestCompile 'com.android.support.test.espresso:espresso-core:3.0.1'
5757
androidTestCompile 'com.android.support.test.espresso:espresso-intents:3.0.1'
5858
androidTestCompile 'com.android.support.test:runner:1.0.1'
59+
androidTestImplementation 'com.android.support.test:runner:1.0.1'
60+
androidTestUtil 'com.android.support.test:orchestrator:1.0.1'
61+
5962
}
6063

6164
def keystorePropertiesFile = rootProject.file("keystore.properties")
6265
def keystoreProperties = new Properties()
6366
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
6467

68+
def testPropertiesFile = rootProject.file("test.properties")
69+
def testProperties = new Properties()
70+
testProperties.load(new FileInputStream(testPropertiesFile))
71+
6572
android {
6673
compileSdkVersion 26
6774
buildToolsVersion "26.0.2"
@@ -75,6 +82,10 @@ android {
7582
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
7683
}
7784

85+
testOptions {
86+
execution 'ANDROID_TEST_ORCHESTRATOR'
87+
}
88+
7889
flavorDimensions "store"
7990

8091
productFlavors {
@@ -101,6 +112,11 @@ android {
101112
signingConfig signingConfigs.release
102113
minifyEnabled true
103114
}
115+
116+
debug {
117+
buildConfigField("String", "TEST_USER_ID", "\"${testProperties.testUserId}\"")
118+
buildConfigField("String", "TEST_USER_KEY_READONLY", "\"${testProperties.testUserKeyReadonly}\"")
119+
}
104120
}
105121

106122
lintOptions {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package com.gimranov.zandy.app;
2+
3+
import android.app.Instrumentation;
4+
import android.content.Intent;
5+
import android.content.SharedPreferences;
6+
import android.net.Uri;
7+
import android.preference.PreferenceManager;
8+
import android.support.test.espresso.intent.rule.IntentsTestRule;
9+
import android.support.test.filters.LargeTest;
10+
import android.support.test.runner.AndroidJUnit4;
11+
12+
import com.gimranov.zandy.app.data.Database;
13+
import com.gimranov.zandy.app.test.*;
14+
import com.gimranov.zandy.app.test.BuildConfig;
15+
16+
import org.hamcrest.BaseMatcher;
17+
import org.hamcrest.Description;
18+
import org.junit.After;
19+
import org.junit.Before;
20+
import org.junit.Rule;
21+
import org.junit.Test;
22+
import org.junit.runner.RunWith;
23+
24+
import static android.support.test.InstrumentationRegistry.getInstrumentation;
25+
import static android.support.test.InstrumentationRegistry.getTargetContext;
26+
import static android.support.test.espresso.Espresso.onView;
27+
import static android.support.test.espresso.action.ViewActions.click;
28+
import static android.support.test.espresso.assertion.ViewAssertions.matches;
29+
import static android.support.test.espresso.intent.Intents.intended;
30+
import static android.support.test.espresso.intent.matcher.ComponentNameMatchers.hasClassName;
31+
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasAction;
32+
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent;
33+
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasData;
34+
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
35+
import static android.support.test.espresso.matcher.ViewMatchers.withId;
36+
import static org.hamcrest.Matchers.allOf;
37+
import static org.hamcrest.Matchers.hasEntry;
38+
import static org.hamcrest.Matchers.not;
39+
40+
@RunWith(AndroidJUnit4.class)
41+
@LargeTest
42+
public class MainActivityLoggedInTest {
43+
@Rule
44+
public IntentsTestRule<MainActivity> activityTestRule =
45+
new IntentsTestRule<>(MainActivity.class);
46+
47+
@Before
48+
public void setUpCredentials() {
49+
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getTargetContext());
50+
preferences.edit()
51+
.putString("user_id", BuildConfig.TEST_USER_ID)
52+
.putString("user_key", BuildConfig.TEST_USER_KEY_READONLY)
53+
.commit();
54+
}
55+
56+
@After
57+
public void clearCredentials() {
58+
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getTargetContext());
59+
preferences.edit().clear().commit();
60+
}
61+
62+
@Before
63+
@After
64+
public void clearDatabase() {
65+
Database database = new Database(getTargetContext());
66+
database.resetAllData();
67+
}
68+
69+
@Test
70+
public void loginButtonDoesNotShow() {
71+
onView(withId(R.id.loginButton)).check(matches(not(isDisplayed())));
72+
}
73+
}

src/androidTest/java/com/gimranov/zandy/app/MainActivityTest.java renamed to src/androidTest/java/com/gimranov/zandy/app/MainActivityLoggedOutTest.java

+25-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package com.gimranov.zandy.app;
22

3+
import android.content.Intent;
4+
import android.net.Uri;
35
import android.support.test.espresso.intent.rule.IntentsTestRule;
46
import android.support.test.filters.LargeTest;
57
import android.support.test.runner.AndroidJUnit4;
68

9+
import org.hamcrest.BaseMatcher;
10+
import org.hamcrest.Description;
711
import org.junit.Rule;
812
import org.junit.Test;
913
import org.junit.runner.RunWith;
@@ -13,13 +17,16 @@
1317
import static android.support.test.espresso.assertion.ViewAssertions.matches;
1418
import static android.support.test.espresso.intent.Intents.intended;
1519
import static android.support.test.espresso.intent.matcher.ComponentNameMatchers.hasClassName;
20+
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasAction;
1621
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent;
22+
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasData;
1723
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
1824
import static android.support.test.espresso.matcher.ViewMatchers.withId;
25+
import static org.hamcrest.Matchers.allOf;
1926

2027
@RunWith(AndroidJUnit4.class)
2128
@LargeTest
22-
public class MainActivityTest {
29+
public class MainActivityLoggedOutTest {
2330
@Rule
2431
public IntentsTestRule<MainActivity> activityTestRule =
2532
new IntentsTestRule<>(MainActivity.class);
@@ -29,6 +36,23 @@ public void loginButtonShowsOnLaunch() {
2936
onView(withId(R.id.loginButton)).check(matches(isDisplayed()));
3037
}
3138

39+
@Test
40+
public void loginButtonLaunchesOauth() throws Exception {
41+
onView(withId(R.id.loginButton)).perform(click());
42+
Thread.sleep(1000);
43+
intended(allOf(hasAction(Intent.ACTION_VIEW), hasData(new BaseMatcher<Uri>() {
44+
@Override
45+
public boolean matches(Object item) {
46+
return ((Uri) item).getHost().contains("zotero.org");
47+
}
48+
49+
@Override
50+
public void describeTo(Description description) {
51+
description.appendText("should have host zotero.org");
52+
}
53+
})));
54+
}
55+
3256
@Test
3357
public void viewCollectionsLaunchesActivity() throws Exception {
3458
onView(withId(R.id.collectionButton)).perform(click());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package com.gimranov.zandy.app;
2+
3+
4+
import android.content.SharedPreferences;
5+
import android.preference.PreferenceManager;
6+
import android.support.test.espresso.ViewInteraction;
7+
import android.support.test.rule.ActivityTestRule;
8+
import android.support.test.runner.AndroidJUnit4;
9+
import android.test.suitebuilder.annotation.LargeTest;
10+
import android.view.View;
11+
import android.view.ViewGroup;
12+
import android.view.ViewParent;
13+
14+
import com.gimranov.zandy.app.data.Database;
15+
16+
import org.hamcrest.Description;
17+
import org.hamcrest.Matcher;
18+
import org.hamcrest.TypeSafeMatcher;
19+
import org.junit.After;
20+
import org.junit.Before;
21+
import org.junit.Rule;
22+
import org.junit.Test;
23+
import org.junit.runner.RunWith;
24+
25+
import static android.support.test.InstrumentationRegistry.getTargetContext;
26+
import static android.support.test.espresso.Espresso.onView;
27+
import static android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu;
28+
import static android.support.test.espresso.action.ViewActions.click;
29+
import static android.support.test.espresso.assertion.ViewAssertions.matches;
30+
import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
31+
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
32+
import static android.support.test.espresso.matcher.ViewMatchers.withClassName;
33+
import static android.support.test.espresso.matcher.ViewMatchers.withId;
34+
import static android.support.test.espresso.matcher.ViewMatchers.withText;
35+
import static org.hamcrest.Matchers.allOf;
36+
import static org.hamcrest.Matchers.is;
37+
import static org.hamcrest.Matchers.not;
38+
39+
@LargeTest
40+
@RunWith(AndroidJUnit4.class)
41+
public class SyncTest {
42+
43+
@Rule
44+
public ActivityTestRule<MainActivity> mActivityTestRule = new ActivityTestRule<>(MainActivity.class);
45+
46+
@Before
47+
public void setUpCredentials() {
48+
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getTargetContext());
49+
preferences.edit()
50+
.putString("user_id", BuildConfig.TEST_USER_ID)
51+
.putString("user_key", BuildConfig.TEST_USER_KEY_READONLY)
52+
.commit();
53+
}
54+
55+
@After
56+
public void clearCredentials() {
57+
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getTargetContext());
58+
preferences.edit().clear().commit();
59+
}
60+
61+
@Before
62+
@After
63+
public void clearDatabase() {
64+
Database database = new Database(getTargetContext());
65+
database.resetAllData();
66+
}
67+
68+
@Test
69+
public void syncTest() {
70+
openActionBarOverflowOrOptionsMenu(getTargetContext());
71+
72+
ViewInteraction textView = onView(
73+
allOf(withId(android.R.id.title), withText(R.string.menu_sync),
74+
childAtPosition(
75+
childAtPosition(
76+
withClassName(is("com.android.internal.view.menu.ListMenuItemView")),
77+
0),
78+
0),
79+
isDisplayed()));
80+
textView.perform(click());
81+
82+
onView(withText(R.string.sync_started))
83+
.inRoot(withDecorView(not(is(mActivityTestRule.getActivity().getWindow().getDecorView()))))
84+
.check(matches(isDisplayed()));
85+
86+
ViewInteraction button2 = onView(
87+
allOf(withId(R.id.itemButton), withText(R.string.view_items),
88+
childAtPosition(
89+
allOf(withId(R.id.main),
90+
childAtPosition(
91+
withId(android.R.id.content),
92+
0)),
93+
1),
94+
isDisplayed()));
95+
button2.perform(click());
96+
}
97+
98+
private static Matcher<View> childAtPosition(
99+
final Matcher<View> parentMatcher, final int position) {
100+
101+
return new TypeSafeMatcher<View>() {
102+
@Override
103+
public void describeTo(Description description) {
104+
description.appendText("Child at position " + position + " in parent ");
105+
parentMatcher.describeTo(description);
106+
}
107+
108+
@Override
109+
public boolean matchesSafely(View view) {
110+
ViewParent parent = view.getParent();
111+
return parent instanceof ViewGroup && parentMatcher.matches(parent)
112+
&& view.equals(((ViewGroup) parent).getChildAt(position));
113+
}
114+
};
115+
}
116+
}

src/main/java/com/gimranov/zandy/app/MainActivity.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ private void toastError(final String message) {
233233
runOnUiThread(new Runnable() {
234234
@Override
235235
public void run() {
236-
Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG);
236+
Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();
237237
}
238238
});
239239
}

src/main/java/com/gimranov/zandy/app/data/ItemAdapter.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ public void notifyDataSetChanged() {
5454

5555
@Override
5656
public void bindView(View view, Context context, Cursor cursor) {
57-
TextView tvTitle = (TextView) view.findViewById(R.id.item_title);
58-
ImageView tvType = (ImageView) view.findViewById(R.id.item_type);
59-
TextView tvSummary = (TextView) view.findViewById(R.id.item_summary);
57+
TextView tvTitle = view.findViewById(R.id.item_title);
58+
ImageView tvType = view.findViewById(R.id.item_type);
59+
TextView tvSummary = view.findViewById(R.id.item_summary);
6060

6161
if (cursor == null) {
6262
Log.e(TAG, "cursor is null in bindView");

test.properties

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
testUserId=<dummy>
2+
testUserKeyReadonly=<dummy>

0 commit comments

Comments
 (0)