Skip to content
This repository has been archived by the owner on Sep 1, 2023. It is now read-only.

Commit

Permalink
Add an IdlingResource for the progress bar to make tests timing-indep…
Browse files Browse the repository at this point in the history
…endent.
  • Loading branch information
vickychijwani committed Nov 5, 2017
1 parent c776458 commit 0be587a
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import android.content.ComponentName
import android.content.Intent
import android.support.test.InstrumentationRegistry.getTargetContext
import android.support.test.espresso.Espresso.onView
import android.support.test.espresso.IdlingRegistry
import android.support.test.espresso.IdlingResource
import android.support.test.espresso.action.ViewActions.click
import android.support.test.espresso.action.ViewActions.typeText
import android.support.test.espresso.assertion.ViewAssertions.matches
Expand All @@ -16,35 +18,55 @@ import android.support.test.filters.LargeTest
import android.support.test.runner.AndroidJUnit4
import me.vickychijwani.spectre.R
import me.vickychijwani.spectre.testing.ClearPreferencesRule
import me.vickychijwani.spectre.testing.ViewNotVisibleIdlingResource
import me.vickychijwani.spectre.view.LoginActivity
import me.vickychijwani.spectre.view.PostListActivity
import org.hamcrest.CoreMatchers.containsString
import org.hamcrest.Matcher
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import kotlin.reflect.KClass


// Tests follow the Jake Wharton's Robot pattern explained here:
// Tests follow Jake Wharton's Robot pattern explained here:
// https://academy.realm.io/posts/kau-jake-wharton-testing-robots/

@RunWith(AndroidJUnit4::class) @LargeTest
class LoginTest {

private val TEST_BLOG = "10.0.2.2:2368"
private val TEST_USER = "user@example.com"
private val TEST_PWD = "randomtestpwd"

@Rule @JvmField
val mActivityRule = IntentsTestRule(LoginActivity::class.java)

@Rule @JvmField
val mPrefsRule = ClearPreferencesRule()

private lateinit var mProgressBarIdlingResource: IdlingResource

@Before
fun setup() {
mProgressBarIdlingResource = ViewNotVisibleIdlingResource(mActivityRule.activity, R.id.progress)
IdlingRegistry.getInstance().register(mProgressBarIdlingResource)
}

@After
fun teardown() {
IdlingRegistry.getInstance().unregister(mProgressBarIdlingResource)
}

@Test
fun successfulLogin() {
startLogin {
blogAddress("10.0.2.2:2368")
blogAddress(TEST_BLOG)
} connectToBlog {
email("user@example.com")
password("randomtestpwd")
email(TEST_USER)
password(TEST_PWD)
} login {
isLoggedIn()
}
Expand All @@ -62,7 +84,7 @@ class LoginTest {
@Test
fun invalidEmail() {
startLogin {
blogAddress("10.0.2.2:2368")
blogAddress(TEST_BLOG)
} connectToBlog {
email("invalid_email")
} login {
Expand All @@ -73,7 +95,7 @@ class LoginTest {
@Test
fun nonExistentUser() {
startLogin {
blogAddress("10.0.2.2:2368")
blogAddress(TEST_BLOG)
} connectToBlog {
email("nonexistent@example.com")
password("doesnt_matter")
Expand All @@ -85,9 +107,9 @@ class LoginTest {
@Test
fun wrongPassword() {
startLogin {
blogAddress("10.0.2.2:2368")
blogAddress(TEST_BLOG)
} connectToBlog {
email("user@example.com")
email(TEST_USER)
password("wrongpassword")
} login {
errorMatching("Your password is incorrect")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package me.vickychijwani.spectre.testing

import android.app.Activity
import android.os.Handler
import android.support.annotation.NonNull
import android.support.test.espresso.IdlingResource
import java.lang.ref.WeakReference

/**
* [IdlingResource] that is idle when the given [Activity] passes the given predicate.
*
* Adapted from https://gist.github.com/vaughandroid/e2fda716c7cf6853fa79
*/
open class ActivityStateIdlingResource(@NonNull activity: Activity,
private val mIdlePredicate: (Activity) -> Boolean)
: IdlingResource {

companion object {
private val IDLE_POLL_DELAY_MILLIS = 100L
}

/* Hold a weak reference, so we don't leak memory even if the resource isn't unregistered. */
private val mActivity: WeakReference<Activity> = WeakReference(activity)
private val mName: String = "IdlingResource for state of ${activity::class.java.simpleName} " +
"(@${System.identityHashCode(activity)})"

private var mResourceCallback: IdlingResource.ResourceCallback? = null

override fun getName(): String {
return mName
}

override fun isIdleNow(): Boolean {
val activity = mActivity.get()
val isIdle = if (activity != null) mIdlePredicate(activity) else true
if (isIdle) {
if (mResourceCallback != null) {
mResourceCallback!!.onTransitionToIdle()
}
} else {
/* Force a re-check of the idle state in a little while. If isIdleNow() returns false,
* Espresso only polls it every few seconds which can slow down our tests. */
Handler().postDelayed({ isIdleNow }, IDLE_POLL_DELAY_MILLIS)
}

return isIdle
}

override fun registerIdleTransitionCallback(resourceCallback: IdlingResource.ResourceCallback) {
mResourceCallback = resourceCallback
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package me.vickychijwani.spectre.testing

import android.app.Activity
import android.support.annotation.IdRes
import android.support.annotation.NonNull
import android.support.test.espresso.IdlingResource
import android.view.View

/**
* [IdlingResource] which is idle when a [View] with the given ID is NOT [View.VISIBLE]
* in the given activity.
*/
class ViewNotVisibleIdlingResource(@NonNull activity: Activity,
@IdRes private val mViewId: Int)
: ActivityStateIdlingResource(activity,
{ act ->
val view: View? = act.findViewById(mViewId)
view == null || view.visibility != View.VISIBLE
}
)
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,18 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {
}
}

// override equals and hashCode to prevent this error in e2e tests:
// IllegalArgumentException: Configurations cannot be different if used to open the same file.
// The most likely cause is that equals() and hashCode() are not overridden in the migration class
// see https://stackoverflow.com/a/36919305/504611 for more
@Override
public int hashCode() {
return 34578;
}

@Override
public boolean equals(Object obj) {
return (obj instanceof BlogDBMigration);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,18 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {
// ONLY STORES THE *METADATA* FOR ALL CONNECTED BLOGS
}

// override equals and hashCode to prevent this error in e2e tests:
// IllegalArgumentException: Configurations cannot be different if used to open the same file.
// The most likely cause is that equals() and hashCode() are not overridden in the migration class
// see https://stackoverflow.com/a/36919305/504611 for more
@Override
public int hashCode() {
return 98531;
}

@Override
public boolean equals(Object obj) {
return (obj instanceof BlogMetadataDBMigration);
}

}

0 comments on commit 0be587a

Please sign in to comment.