Skip to content

Commit

Permalink
Merge pull request #289 from wealthfront/dog-recyclerview
Browse files Browse the repository at this point in the history
Use RecyclerView to display dog breeds
  • Loading branch information
cmathew committed Oct 19, 2023
2 parents d68e331 + 4a10cb7 commit 64d14a6
Show file tree
Hide file tree
Showing 40 changed files with 476 additions and 548 deletions.
3 changes: 3 additions & 0 deletions buildSrc/src/main/java/Libs.kt
Expand Up @@ -20,6 +20,7 @@ import Versions.materialVersion
import Versions.mockKVersion
import Versions.mockitoVersion
import Versions.okhttpVersion
import Versions.recyclerViewVersion
import Versions.retrofitVersion
import Versions.robolectricVersion
import Versions.rxAndroid2Version
Expand Down Expand Up @@ -48,9 +49,11 @@ object Libs {
const val androidXCore = "androidx.core:core-ktx:$androidXCoreVersion"

const val material = "com.google.android.material:material:$materialVersion"
const val recyclerView = "androidx.recyclerview:recyclerview:$recyclerViewVersion"
const val junit = "junit:junit:$junitVersion"
const val truth = "com.google.truth:truth:$truthVersion"
const val mockito = "org.mockito:mockito-core:$mockitoVersion"
const val mockitoAndroid = "org.mockito:mockito-android:$mockitoVersion"
const val mockK = "io.mockk:mockk:$mockKVersion"
const val archTesting = "androidx.arch.core:core-testing:$archVersion"
const val robolectric = "org.robolectric:robolectric:$robolectricVersion"
Expand Down
1 change: 1 addition & 0 deletions buildSrc/src/main/java/Versions.kt
Expand Up @@ -27,6 +27,7 @@ object Versions {
const val jodaTimeVersion = "2.10.9.1"
const val javaInjectVersion = "1"
const val materialVersion = "1.4.0"
const val recyclerViewVersion = "1.2.1"
const val coroutinesVersion = "1.6.4"

const val testCoreVersion = "1.4.0"
Expand Down
5 changes: 4 additions & 1 deletion magellan-sample-migration/build.gradle
Expand Up @@ -11,7 +11,7 @@ android {
targetSdkVersion Versions.targetSdkVersion
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunner "com.wealthfront.magellan.sample.migration.IntegrationTestRunner"
}

compileOptions {
Expand Down Expand Up @@ -64,6 +64,7 @@ dependencies {
implementation Libs.coroutines
implementation Libs.coroutinesAndroid
implementation Libs.jodaTime
implementation Libs.recyclerView

kaptTest Libs.daggerCompiler
testImplementation Libs.junit
Expand All @@ -73,13 +74,15 @@ dependencies {
testImplementation Libs.robolectric
testImplementation Libs.truth

kaptAndroidTest Libs.daggerCompiler
androidTestImplementation Libs.extJunit
androidTestImplementation Libs.espressoCore
androidTestImplementation Libs.espressoContrib
androidTestImplementation Libs.testCore
androidTestImplementation Libs.testCoreKtx
androidTestImplementation Libs.testRunner
androidTestImplementation Libs.testRules
androidTestImplementation Libs.mockitoAndroid

androidTestImplementation 'androidx.test:runner:1.4.0'
androidTestUtil 'androidx.test:orchestrator:1.4.1'
Expand Down
@@ -1,4 +1,4 @@
package com.wealthfront.magellan
package com.wealthfront.magellan.sample.migration

import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.idling.CountingIdlingResource
Expand Down
@@ -0,0 +1,21 @@
package com.wealthfront.magellan.sample.migration

import android.app.Application
import android.content.Context
import androidx.test.runner.AndroidJUnitRunner

class IntegrationTestRunner : AndroidJUnitRunner() {

@Throws(
InstantiationException::class,
IllegalAccessException::class,
ClassNotFoundException::class
)
override fun newApplication(
cl: ClassLoader,
className: String,
context: Context,
): Application {
return super.newApplication(cl, TestSampleApplication::class.java.name, context)
}
}
@@ -0,0 +1,12 @@
package com.wealthfront.magellan.sample.migration

import com.wealthfront.magellan.sample.migration.uitest.NavigationTest
import dagger.Component
import javax.inject.Singleton

@Component(modules = [AppModule::class, ToolbarHelperModule::class, TestDogApiModule::class])
@Singleton
interface TestAppComponent : AppComponent {

fun inject(test: NavigationTest)
}
@@ -0,0 +1,17 @@
package com.wealthfront.magellan.sample.migration

import com.wealthfront.magellan.sample.migration.api.DogApi
import dagger.Module
import dagger.Provides
import org.mockito.Mockito.mock
import javax.inject.Singleton

@Module
object TestDogApiModule {

@Provides
@Singleton
fun provideDogApi(): DogApi {
return mock(DogApi::class.java)
}
}
@@ -0,0 +1,33 @@
@file:Suppress("UNCHECKED_CAST")

package com.wealthfront.magellan.sample.migration

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.runBlocking
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.stubbing.LenientStubber
import org.mockito.stubbing.OngoingStubbing
import org.mockito.verification.VerificationMode

fun <T> LenientStubber.coWhen(block: suspend CoroutineScope.() -> T): OngoingStubbing<T> =
runBlocking {
this@coWhen.`when`(block())
}

fun <T> coWhen(block: suspend CoroutineScope.() -> T): OngoingStubbing<T> =
runBlocking {
`when`(block())
}

fun <T> coVerify(mock: T, block: suspend CoroutineScope.(T) -> Unit) {
runBlocking {
block(verify(mock))
}
}

fun <T> coVerify(mock: T, mode: VerificationMode, block: suspend CoroutineScope.(T) -> Unit) {
runBlocking {
block(verify(mock, mode))
}
}
@@ -0,0 +1,21 @@
package com.wealthfront.magellan.sample.migration

import android.app.Application

class TestSampleApplication : Application(), AppComponentContainer {

private lateinit var appComponent: TestAppComponent

override fun onCreate() {
super.onCreate()
appComponent = DaggerTestAppComponent.builder()
.appModule(AppModule)
.testDogApiModule(TestDogApiModule)
.toolbarHelperModule(ToolbarHelperModule)
.build()
}

override fun injector(): AppComponent {
return appComponent
}
}
@@ -0,0 +1,54 @@
package com.wealthfront.magellan.sample.migration.uitest

import android.app.Application
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import com.wealthfront.magellan.sample.migration.AppComponentContainer
import com.wealthfront.magellan.sample.migration.CoroutineIdlingRule
import com.wealthfront.magellan.sample.migration.MainActivity
import com.wealthfront.magellan.sample.migration.R
import com.wealthfront.magellan.sample.migration.TestAppComponent
import com.wealthfront.magellan.sample.migration.api.DogApi
import com.wealthfront.magellan.sample.migration.api.DogBreedsResponse
import com.wealthfront.magellan.sample.migration.api.DogImageResponse
import com.wealthfront.magellan.sample.migration.coWhen
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import javax.inject.Inject

class NavigationTest {

@Rule @JvmField
val coroutineIdlingRule = CoroutineIdlingRule()

@Inject lateinit var api: DogApi

private lateinit var activityScenario: ActivityScenario<MainActivity>

@Before
fun setup() {
val context = ApplicationProvider.getApplicationContext<Application>()
((context as AppComponentContainer).injector() as TestAppComponent).inject(this)

coWhen { api.getAllBreeds() }
.thenReturn(DogBreedsResponse(message = mapOf("robotic" to emptyList()), status = "success"))
coWhen { api.getRandomImageForBreed("robotic") }.thenReturn(
DogImageResponse(message = "image-url", status = "success")
)
}

@Test
fun visitRetriever() {
activityScenario = launchActivity()
onView(withText("robotic")).perform(click())
onView(withId(R.id.dogDetailsView)).check(matches(isDisplayed()))
}
}

This file was deleted.

This file was deleted.

@@ -0,0 +1,16 @@
package com.wealthfront.magellan.sample.migration

import com.wealthfront.magellan.sample.migration.tide.DogDetailsScreen
import com.wealthfront.magellan.sample.migration.tide.DogListStep
import dagger.Component
import javax.inject.Singleton

@Component(modules = [AppModule::class, DogApiModule::class, ToolbarHelperModule::class])
@Singleton
interface AppComponent {

fun inject(activity: MainActivity)
fun inject(step: DogListStep)
fun inject(screen: DogDetailsScreen)
fun inject(expedition: Expedition)
}

This file was deleted.

0 comments on commit 64d14a6

Please sign in to comment.