-
Notifications
You must be signed in to change notification settings - Fork 0
Example UI test implementation #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
lauriskr
wants to merge
8
commits into
develop
Choose a base branch
from
example/ui-tests
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
211e125
Add hilt UI tests with a custom Idler implementation to wrap an Idlin…
lauriskr 4ff91e1
Clean up TestSchedulerProvider impl
lauriskr 7a208c2
Remove closeKeyboard calls from LoginActivityTest and fix unit tests'…
lauriskr 9a40ef0
Merge branch 'feature/deps-update' of github.com:LabMobi/project-crea…
lauriskr c4a1f5b
Merge branch 'develop' of github.com:LabMobi/project-creator-android …
lauriskr 573c05b
Update Idler implementation with a new interface
lauriskr f43edf8
Add isDialog() check to UI test that checks that a dialog with text i…
lauriskr a60c097
Merge branch 'develop' of github.com:LabMobi/project-creator-android …
lauriskr File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
project/app-common/src/main/java/mobi/lab/sample/app/common/di/IdlerModule.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package mobi.lab.sample.app.common.di | ||
|
||
import dagger.Module | ||
import dagger.Provides | ||
import dagger.hilt.InstallIn | ||
import dagger.hilt.components.SingletonComponent | ||
import mobi.lab.sample.app.common.test.Idler | ||
import mobi.lab.sample.app.common.test.NoOpIdler | ||
import javax.inject.Singleton | ||
|
||
@Module | ||
@InstallIn(SingletonComponent::class) | ||
object IdlerModule { | ||
|
||
@Provides | ||
@Singleton | ||
internal fun provideIdler(): Idler = NoOpIdler() | ||
} |
46 changes: 46 additions & 0 deletions
46
project/app-common/src/main/java/mobi/lab/sample/app/common/test/Idler.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package mobi.lab.sample.app.common.test | ||
|
||
interface Idler { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe one-lin comment on how to use the Idler? Eg: |
||
/** | ||
* Create a new [IdlerToken]. This does not mark the token as busy | ||
* | ||
* @return new [IdlerToken] | ||
*/ | ||
fun token(): IdlerToken | ||
|
||
/** | ||
* Create a new [IdlerToken] and mark it as busy. | ||
* | ||
* @return new [IdlerToken] | ||
*/ | ||
fun busy(): IdlerToken | ||
|
||
/** | ||
* Create a new [IdlerToken] from the given key and mark it as busy. | ||
* | ||
* @param key Any object to use as a value for the token. | ||
* @return new [IdlerToken] using the key | ||
*/ | ||
fun busy(key: Any): IdlerToken | ||
|
||
/** | ||
* Mark the [IdlerToken] as busy. | ||
* | ||
* @param token [IdlerToken] | ||
*/ | ||
fun busy(token: IdlerToken) | ||
|
||
/** | ||
* Mark work identified by key as done. | ||
* | ||
* @param key Any object that identifies the work | ||
*/ | ||
fun done(key: Any) | ||
|
||
/** | ||
* Mark work identified by token as done. | ||
* | ||
* @param token [IdlerToken] | ||
*/ | ||
fun done(token: IdlerToken) | ||
} |
3 changes: 3 additions & 0 deletions
3
project/app-common/src/main/java/mobi/lab/sample/app/common/test/IdlerToken.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package mobi.lab.sample.app.common.test | ||
|
||
data class IdlerToken(val key: Any) |
28 changes: 28 additions & 0 deletions
28
project/app-common/src/main/java/mobi/lab/sample/app/common/test/NoOpIdler.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package mobi.lab.sample.app.common.test | ||
|
||
class NoOpIdler : Idler { | ||
|
||
override fun token(): IdlerToken { | ||
return IdlerToken(Any()) | ||
} | ||
|
||
override fun busy(): IdlerToken { | ||
return IdlerToken(Any()) | ||
} | ||
|
||
override fun busy(key: Any): IdlerToken { | ||
return IdlerToken(key) | ||
} | ||
|
||
override fun busy(token: IdlerToken) { | ||
// Do nothing | ||
} | ||
|
||
override fun done(key: Any) { | ||
// Do nothing | ||
} | ||
|
||
override fun done(token: IdlerToken) { | ||
// Do nothing | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package mobi.lab.sample | ||
|
||
import dagger.hilt.android.testing.CustomTestApplication | ||
|
||
// Hilt will generate an application class that extends TestAppBase | ||
@CustomTestApplication(TestAppBase::class) | ||
interface TestApp |
16 changes: 16 additions & 0 deletions
16
project/app/src/androidTest/java/mobi/lab/sample/TestAppBase.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package mobi.lab.sample | ||
|
||
import android.app.Application | ||
import androidx.test.espresso.IdlingRegistry | ||
import mobi.lab.sample.util.RealIdler | ||
import timber.log.Timber | ||
|
||
open class TestAppBase : Application() { | ||
|
||
override fun onCreate() { | ||
super.onCreate() | ||
// Any other relevant setup we need to make | ||
Timber.plant(Timber.DebugTree()) | ||
IdlingRegistry.getInstance().register(RealIdler.idlingResource) | ||
} | ||
} |
124 changes: 124 additions & 0 deletions
124
project/app/src/androidTest/java/mobi/lab/sample/demo/login/LoginActivityTest.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
package mobi.lab.sample.demo.login | ||
|
||
import androidx.test.espresso.Espresso | ||
import androidx.test.espresso.Espresso.onView | ||
import androidx.test.espresso.action.ViewActions.click | ||
import androidx.test.espresso.action.ViewActions.typeText | ||
import androidx.test.espresso.assertion.ViewAssertions.matches | ||
import androidx.test.espresso.intent.Intents | ||
import androidx.test.espresso.intent.matcher.IntentMatchers | ||
import androidx.test.espresso.matcher.RootMatchers.isDialog | ||
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed | ||
import androidx.test.espresso.matcher.ViewMatchers.withId | ||
import androidx.test.espresso.matcher.ViewMatchers.withText | ||
import androidx.test.ext.junit.rules.activityScenarioRule | ||
import dagger.hilt.android.testing.HiltAndroidRule | ||
import dagger.hilt.android.testing.HiltAndroidTest | ||
import mobi.lab.sample.R | ||
import mobi.lab.sample.common.rx.SchedulerProvider | ||
import mobi.lab.sample.demo.main.MainActivity | ||
import mobi.lab.sample.util.hasNoTextInputLayoutError | ||
import mobi.lab.sample.util.hasTextInputLayoutError | ||
import org.junit.After | ||
import org.junit.Before | ||
import org.junit.Rule | ||
import org.junit.Test | ||
import javax.inject.Inject | ||
|
||
@HiltAndroidTest | ||
class LoginActivityTest { | ||
|
||
@get:Rule | ||
var hiltRule = HiltAndroidRule(this) | ||
|
||
/** | ||
* Use [androidx.test.ext.junit.rules.ActivityScenarioRule] to create and launch the activity under test before each test, | ||
* and close it after each test. This is a replacement for | ||
* [androidx.test.rule.ActivityTestRule]. | ||
*/ | ||
@get:Rule | ||
val activityScenarioRule = activityScenarioRule<LoginActivity>() | ||
|
||
@Inject | ||
lateinit var schedulers: SchedulerProvider | ||
|
||
private lateinit var activity: LoginActivity | ||
|
||
@Before | ||
fun setup() { | ||
hiltRule.inject() | ||
Intents.init() | ||
activityScenarioRule.scenario.onActivity { | ||
activity = it | ||
} | ||
} | ||
|
||
@After | ||
fun tearDown() { | ||
Intents.release() | ||
} | ||
|
||
@Test | ||
fun show_input_error_when_fields_are_empty_rxidler() { | ||
onView(withId(R.id.button_login)).perform(click()) | ||
|
||
onView(withId(R.id.input_layout_email)).check(matches(hasTextInputLayoutError(TEXT_ID_REQUIRED))) | ||
onView(withId(R.id.input_layout_password)).check(matches(hasTextInputLayoutError(TEXT_ID_REQUIRED))) | ||
|
||
Intents.assertNoUnverifiedIntents() | ||
} | ||
|
||
@Test | ||
fun show_input_error_when_only_username_is_filled_rxidler() { | ||
onView(withId(R.id.edit_text_email)).perform(typeText("asd")) | ||
onView(withId(R.id.button_login)).perform(click()) | ||
|
||
onView(withId(R.id.input_layout_email)).check(matches(hasNoTextInputLayoutError())) | ||
onView(withId(R.id.input_layout_password)).check(matches(hasTextInputLayoutError(TEXT_ID_REQUIRED))) | ||
|
||
Intents.assertNoUnverifiedIntents() | ||
} | ||
|
||
@Test | ||
fun show_input_error_when_only_password_is_filled_rxidler() { | ||
onView(withId(R.id.edit_text_password)).perform(typeText("asd")) | ||
onView(withId(R.id.button_login)).perform(click()) | ||
|
||
onView(withId(R.id.input_layout_email)).check(matches(hasTextInputLayoutError(TEXT_ID_REQUIRED))) | ||
onView(withId(R.id.input_layout_password)).check(matches(hasNoTextInputLayoutError())) | ||
|
||
Intents.assertNoUnverifiedIntents() | ||
} | ||
|
||
@Test | ||
fun login_success_when_fields_are_filled_rxidler() { | ||
onView(withId(R.id.edit_text_email)).perform(typeText("asd")) | ||
onView(withId(R.id.edit_text_password)).perform(typeText("asd")) | ||
onView(withId(R.id.button_login)).perform(click()) | ||
|
||
Intents.intended(IntentMatchers.hasComponent(MainActivity::class.java.name)) | ||
} | ||
|
||
@Test | ||
fun show_error_dialog_when_login_fails_rxidler() { | ||
// "test" is a keyword to trigger an error response. See LoginUseCase implementation | ||
onView(withId(R.id.edit_text_email)).perform(typeText("test")) | ||
onView(withId(R.id.edit_text_password)).perform(typeText("asd")) | ||
onView(withId(R.id.button_login)).perform(click()) | ||
|
||
// Validate the dialog and close it | ||
onView(withText(R.string.error_generic)) | ||
.inRoot(isDialog()) | ||
.check(matches(isDisplayed())) | ||
Espresso.pressBack() | ||
|
||
onView(withId(R.id.input_layout_email)).check(matches(hasNoTextInputLayoutError())) | ||
onView(withId(R.id.input_layout_password)).check(matches(hasNoTextInputLayoutError())) | ||
|
||
Intents.assertNoUnverifiedIntents() | ||
} | ||
|
||
companion object { | ||
private val TEXT_ID_REQUIRED = R.string.demo_text_required | ||
} | ||
} |
38 changes: 38 additions & 0 deletions
38
project/app/src/androidTest/java/mobi/lab/sample/di/SchedulerModuleTest.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package mobi.lab.sample.di | ||
|
||
import dagger.hilt.android.testing.HiltAndroidRule | ||
import dagger.hilt.android.testing.HiltAndroidTest | ||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers | ||
import io.reactivex.rxjava3.schedulers.Schedulers | ||
import mobi.lab.sample.common.rx.SchedulerProvider | ||
import org.junit.Before | ||
import org.junit.Rule | ||
import org.junit.Test | ||
import javax.inject.Inject | ||
import kotlin.test.assertSame | ||
|
||
/** | ||
* A sample test showing how to inject dependencies via Dagger. | ||
* Verifies that our TestAppComponent gets its schedulers from TestSchedulerModule | ||
*/ | ||
@HiltAndroidTest | ||
class SchedulerModuleTest { | ||
|
||
@get:Rule | ||
var hiltRule = HiltAndroidRule(this) | ||
|
||
@Inject | ||
lateinit var schedulers: SchedulerProvider | ||
|
||
@Before | ||
fun setup() { | ||
hiltRule.inject() | ||
} | ||
|
||
@Test | ||
fun verify_test_schedulers() { | ||
assertSame(schedulers.main, AndroidSchedulers.mainThread()) | ||
assertSame(schedulers.io, Schedulers.io()) | ||
assertSame(schedulers.computation, Schedulers.computation()) | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
project/app/src/androidTest/java/mobi/lab/sample/di/TestIdlerModule.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package mobi.lab.sample.di | ||
|
||
import dagger.Module | ||
import dagger.Provides | ||
import dagger.hilt.components.SingletonComponent | ||
import dagger.hilt.testing.TestInstallIn | ||
import mobi.lab.sample.app.common.di.IdlerModule | ||
import mobi.lab.sample.app.common.test.Idler | ||
import mobi.lab.sample.util.RealIdler | ||
import javax.inject.Singleton | ||
|
||
@Module | ||
@TestInstallIn( | ||
components = [SingletonComponent::class], | ||
replaces = [IdlerModule::class] | ||
) | ||
object TestIdlerModule { | ||
|
||
@Singleton | ||
@Provides | ||
fun provideIdler(): Idler { | ||
return RealIdler | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
project/app/src/androidTest/java/mobi/lab/sample/di/TestSchedulerModule.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package mobi.lab.sample.di | ||
|
||
import dagger.Module | ||
import dagger.Provides | ||
import dagger.hilt.components.SingletonComponent | ||
import dagger.hilt.testing.TestInstallIn | ||
import mobi.lab.sample.app.common.test.Idler | ||
import mobi.lab.sample.common.rx.SchedulerProvider | ||
import mobi.lab.sample.util.TestSchedulerProvider | ||
import javax.inject.Singleton | ||
|
||
@Module | ||
@TestInstallIn( | ||
components = [SingletonComponent::class], | ||
replaces = [SchedulerModule::class] | ||
) | ||
object TestSchedulerModule { | ||
|
||
@Singleton | ||
@Provides | ||
fun provideSchedulerProvider(idler: Idler): SchedulerProvider { | ||
return TestSchedulerProvider(idler) | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe just-in-case a comment here that this is the provider for UI test idler and this one provides the default no-op one and safe for production?