Issue#31 Remove hilt completely
This commit is contained in:
parent
e3bf7fd3e2
commit
b29870c90c
84 changed files with 75 additions and 1875 deletions
|
|
@ -2,8 +2,6 @@ plugins {
|
|||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'kotlin-kapt'
|
||||
// hilt specific
|
||||
id 'dagger.hilt.android.plugin'
|
||||
}
|
||||
|
||||
android {
|
||||
|
|
@ -33,19 +31,6 @@ android {
|
|||
}
|
||||
}
|
||||
flavorDimensions 'di'
|
||||
productFlavors {
|
||||
hilt {
|
||||
dimension 'di'
|
||||
resValue "string", "app_name", "Hilt Test-ShowCase"
|
||||
applicationId "org.fnives.test.showcase.hilt"
|
||||
testInstrumentationRunner "org.fnives.test.showcase.testutils.configuration.HiltTestRunner"
|
||||
}
|
||||
koin {
|
||||
dimension 'di'
|
||||
resValue "string", "app_name", "Koin Test-ShowCase"
|
||||
applicationId "org.fnives.test.showcase.koin"
|
||||
}
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
|
|
@ -56,29 +41,11 @@ android {
|
|||
java.srcDirs += "src/sharedTest/java"
|
||||
assets.srcDirs += files("$projectDir/schemas".toString())
|
||||
}
|
||||
androidTestHilt {
|
||||
java.srcDirs += "src/sharedTestHilt/java"
|
||||
assets.srcDirs += files("$projectDir/schemas".toString())
|
||||
}
|
||||
androidTestKoin {
|
||||
java.srcDirs += "src/sharedTestKoin/java"
|
||||
assets.srcDirs += files("$projectDir/schemas".toString())
|
||||
}
|
||||
|
||||
test {
|
||||
java.srcDirs += "src/sharedTest/java"
|
||||
java.srcDirs += "src/robolectricTest/java"
|
||||
resources.srcDirs += files("$projectDir/schemas".toString())
|
||||
}
|
||||
testHilt {
|
||||
java.srcDirs += "src/sharedTestHilt/java"
|
||||
java.srcDirs += "src/robolectricTestHilt/java"
|
||||
resources.srcDirs += "src/robolectricTestHilt/resources"
|
||||
}
|
||||
testKoin {
|
||||
java.srcDirs += "src/sharedTestKoin/java"
|
||||
java.srcDirs += "src/robolectricTestKoin/java"
|
||||
}
|
||||
}
|
||||
|
||||
// needed for androidTest
|
||||
|
|
@ -90,17 +57,10 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
hilt {
|
||||
enableAggregatingTask = true
|
||||
enableExperimentalClasspathAggregation = true
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
// making sure the :mockserver is assembled after :clean when running tests
|
||||
testKoinDebugUnitTest.dependsOn tasks.getByPath(':mockserver:assemble')
|
||||
testKoinReleaseUnitTest.dependsOn tasks.getByPath(':mockserver:assemble')
|
||||
testHiltDebugUnitTest.dependsOn tasks.getByPath(':mockserver:assemble')
|
||||
testHiltReleaseUnitTest.dependsOn tasks.getByPath(':mockserver:assemble')
|
||||
testDebugUnitTest.dependsOn tasks.getByPath(':mockserver:assemble')
|
||||
testReleaseUnitTest.dependsOn tasks.getByPath(':mockserver:assemble')
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
|
@ -113,13 +73,7 @@ dependencies {
|
|||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$androidx_livedata_version"
|
||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:$androidx_swiperefreshlayout_version"
|
||||
|
||||
// Koin
|
||||
koinImplementation "io.insert-koin:koin-android:$koin_version"
|
||||
|
||||
// Hilt
|
||||
implementation "com.google.dagger:hilt-android:$hilt_version"
|
||||
kaptHilt "com.google.dagger:hilt-compiler:$hilt_version"
|
||||
hiltImplementation "androidx.activity:activity-ktx:$activity_ktx_version"
|
||||
implementation "io.insert-koin:koin-android:$koin_version"
|
||||
|
||||
implementation "androidx.room:room-runtime:$androidx_room_version"
|
||||
kapt "androidx.room:room-compiler:$androidx_room_version"
|
||||
|
|
@ -151,8 +105,6 @@ dependencies {
|
|||
testImplementation project(':mockserver')
|
||||
testImplementation "androidx.arch.core:core-testing:$testing_androidx_arch_core_version"
|
||||
testRuntimeOnly "org.junit.vintage:junit-vintage-engine:$testing_junit5_version"
|
||||
testImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
|
||||
kaptTest "com.google.dagger:hilt-compiler:$hilt_version"
|
||||
|
||||
androidTestImplementation "androidx.room:room-testing:$androidx_room_version"
|
||||
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version"
|
||||
|
|
@ -167,9 +119,6 @@ dependencies {
|
|||
androidTestImplementation project(':mockserver')
|
||||
androidTestImplementation "androidx.arch.core:core-testing:$testing_androidx_arch_core_version"
|
||||
androidTestRuntimeOnly "org.junit.vintage:junit-vintage-engine:$testing_junit5_version"
|
||||
androidTestImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
|
||||
kaptAndroidTest "com.google.dagger:hilt-compiler:$hilt_version"
|
||||
androidTestImplementation project(":network") // hilt needs it
|
||||
|
||||
implementation "io.reactivex.rxjava3:rxjava:3.1.3"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
package org.fnives.test.showcase.testutils.configuration
|
||||
|
||||
import org.fnives.test.showcase.network.mockserver.MockServerScenarioSetup
|
||||
|
||||
object AndroidTestServerTypeConfiguration : ServerTypeConfiguration {
|
||||
override val useHttps: Boolean get() = true
|
||||
|
||||
override val url: String get() = "${MockServerScenarioSetup.HTTPS_BASE_URL}:${MockServerScenarioSetup.PORT}/"
|
||||
|
||||
override fun invoke(mockServerScenarioSetup: MockServerScenarioSetup) {
|
||||
val handshakeCertificates = mockServerScenarioSetup.clientCertificates ?: return
|
||||
HttpsConfigurationModule.handshakeCertificates = handshakeCertificates
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
package org.fnives.test.showcase.testutils.configuration
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import androidx.test.runner.AndroidJUnitRunner
|
||||
import dagger.hilt.android.testing.HiltTestApplication
|
||||
|
||||
class HiltTestRunner : AndroidJUnitRunner() {
|
||||
|
||||
override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application =
|
||||
super.newApplication(cl, HiltTestApplication::class.java.name, context)
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
package org.fnives.test.showcase.testutils.configuration
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dagger.hilt.testing.TestInstallIn
|
||||
import okhttp3.tls.HandshakeCertificates
|
||||
import org.fnives.test.showcase.hilt.SessionLessQualifier
|
||||
import org.fnives.test.showcase.network.di.hilt.BindsBaseOkHttpClient
|
||||
import org.fnives.test.showcase.network.di.hilt.HiltNetworkModule
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@TestInstallIn(
|
||||
components = [SingletonComponent::class],
|
||||
replaces = [BindsBaseOkHttpClient::class]
|
||||
)
|
||||
object HttpsConfigurationModule {
|
||||
|
||||
lateinit var handshakeCertificates: HandshakeCertificates
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@SessionLessQualifier
|
||||
fun bindsBaseOkHttpClient(enableLogging: Boolean) =
|
||||
HiltNetworkModule.provideSessionLessOkHttpClient(enableLogging)
|
||||
.newBuilder()
|
||||
.sslSocketFactory(
|
||||
handshakeCertificates.sslSocketFactory(),
|
||||
handshakeCertificates.trustManager
|
||||
)
|
||||
.build()
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="org.fnives.test.showcase">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application>
|
||||
<activity
|
||||
android:name=".ui.splash.HiltSplashActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".ui.home.HiltMainActivity" />
|
||||
<activity android:name=".ui.auth.HiltAuthActivity" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
package org.fnives.test.showcase
|
||||
|
||||
import android.app.Application
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
|
||||
@HiltAndroidApp
|
||||
class TestShowcaseApplication : Application()
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
package org.fnives.test.showcase.di
|
||||
|
||||
import android.content.Context
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import org.fnives.test.showcase.core.session.SessionExpirationListener
|
||||
import org.fnives.test.showcase.core.storage.UserDataLocalStorage
|
||||
import org.fnives.test.showcase.core.storage.content.FavouriteContentLocalStorage
|
||||
import org.fnives.test.showcase.session.SessionExpirationListenerImpl
|
||||
import org.fnives.test.showcase.storage.SharedPreferencesManagerImpl
|
||||
import org.fnives.test.showcase.storage.database.DatabaseInitialization
|
||||
import org.fnives.test.showcase.storage.favourite.FavouriteContentLocalStorageImpl
|
||||
import javax.inject.Singleton
|
||||
|
||||
@InstallIn(SingletonComponent::class)
|
||||
@Module
|
||||
object AppModule {
|
||||
|
||||
@Provides
|
||||
fun provideBaseUrl(): String = BaseUrlProvider.get().baseUrl
|
||||
|
||||
@Provides
|
||||
fun enableLogging(): Boolean = true
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideFavouriteDao(@ApplicationContext context: Context) =
|
||||
DatabaseInitialization.create(context).favouriteDao
|
||||
|
||||
@Provides
|
||||
fun provideSharedPreferencesManagerImpl(@ApplicationContext context: Context) =
|
||||
SharedPreferencesManagerImpl.create(context)
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideUserDataLocalStorage(
|
||||
sharedPreferencesManagerImpl: SharedPreferencesManagerImpl
|
||||
): UserDataLocalStorage = sharedPreferencesManagerImpl
|
||||
|
||||
@Provides
|
||||
fun provideFavouriteContentLocalStorage(
|
||||
favouriteContentLocalStorageImpl: FavouriteContentLocalStorageImpl
|
||||
): FavouriteContentLocalStorage = favouriteContentLocalStorageImpl
|
||||
|
||||
@Provides
|
||||
internal fun bindSessionExpirationListener(
|
||||
sessionExpirationListenerImpl: SessionExpirationListenerImpl
|
||||
): SessionExpirationListener = sessionExpirationListenerImpl
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
package org.fnives.test.showcase.ui
|
||||
|
||||
import android.content.Context
|
||||
import org.fnives.test.showcase.ui.auth.HiltAuthActivity
|
||||
import org.fnives.test.showcase.ui.home.HiltMainActivity
|
||||
|
||||
object IntentCoordinator {
|
||||
|
||||
fun mainActivitygetStartIntent(context: Context) =
|
||||
HiltMainActivity.getStartIntent(context)
|
||||
|
||||
fun authActivitygetStartIntent(context: Context) =
|
||||
HiltAuthActivity.getStartIntent(context)
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
package org.fnives.test.showcase.ui
|
||||
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelStoreOwner
|
||||
import androidx.activity.viewModels as androidxViewModel
|
||||
|
||||
inline fun <reified T : ViewModel> ViewModelStoreOwner.viewModels(): Lazy<T> =
|
||||
when (this) {
|
||||
is ComponentActivity -> androidxViewModel()
|
||||
else -> throw IllegalStateException("Only supports activity viewModel for now")
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
package org.fnives.test.showcase.ui.auth
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@AndroidEntryPoint
|
||||
class HiltAuthActivity : AuthActivity() {
|
||||
companion object {
|
||||
fun getStartIntent(context: Context): Intent = Intent(context, HiltAuthActivity::class.java)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
package org.fnives.test.showcase.ui.home
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@AndroidEntryPoint
|
||||
class HiltMainActivity : MainActivity() {
|
||||
companion object {
|
||||
fun getStartIntent(context: Context): Intent = Intent(context, HiltMainActivity::class.java)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
package org.fnives.test.showcase.ui.splash
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@SuppressLint("CustomSplashScreen")
|
||||
@AndroidEntryPoint
|
||||
class HiltSplashActivity : SplashActivity()
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.fnives.test.showcase">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application>
|
||||
<activity
|
||||
android:name=".ui.splash.SplashActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".ui.home.MainActivity" />
|
||||
<activity android:name=".ui.auth.AuthActivity" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
@ -13,6 +13,18 @@
|
|||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.TestShowCase"
|
||||
tools:ignore="AllowBackup"/>
|
||||
tools:ignore="AllowBackup">
|
||||
<activity
|
||||
android:name=".ui.splash.SplashActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".ui.home.MainActivity" />
|
||||
<activity android:name=".ui.auth.AuthActivity" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
@ -4,15 +4,10 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import org.fnives.test.showcase.core.session.SessionExpirationListener
|
||||
import org.fnives.test.showcase.ui.IntentCoordinator
|
||||
import javax.inject.Inject
|
||||
|
||||
class SessionExpirationListenerImpl @Inject constructor(
|
||||
@ApplicationContext
|
||||
private val context: Context
|
||||
) : SessionExpirationListener {
|
||||
class SessionExpirationListenerImpl(private val context: Context) : SessionExpirationListener {
|
||||
|
||||
override fun onSessionExpired() {
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
|
|
|
|||
|
|
@ -4,9 +4,8 @@ import kotlinx.coroutines.flow.Flow
|
|||
import kotlinx.coroutines.flow.map
|
||||
import org.fnives.test.showcase.core.storage.content.FavouriteContentLocalStorage
|
||||
import org.fnives.test.showcase.model.content.ContentId
|
||||
import javax.inject.Inject
|
||||
|
||||
class FavouriteContentLocalStorageImpl @Inject constructor(
|
||||
class FavouriteContentLocalStorageImpl(
|
||||
private val favouriteDao: FavouriteDao
|
||||
) : FavouriteContentLocalStorage {
|
||||
|
||||
|
|
|
|||
|
|
@ -4,17 +4,14 @@ import androidx.lifecycle.LiveData
|
|||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import org.fnives.test.showcase.core.login.LoginUseCase
|
||||
import org.fnives.test.showcase.model.auth.LoginCredentials
|
||||
import org.fnives.test.showcase.model.auth.LoginStatus
|
||||
import org.fnives.test.showcase.model.shared.Answer
|
||||
import org.fnives.test.showcase.ui.shared.Event
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class AuthViewModel @Inject constructor(private val loginUseCase: LoginUseCase) : ViewModel() {
|
||||
class AuthViewModel(private val loginUseCase: LoginUseCase) : ViewModel() {
|
||||
|
||||
private val _username = MutableLiveData<String>()
|
||||
val username: LiveData<String> = _username
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.distinctUntilChanged
|
||||
import androidx.lifecycle.liveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import org.fnives.test.showcase.core.content.AddContentToFavouriteUseCase
|
||||
import org.fnives.test.showcase.core.content.FetchContentUseCase
|
||||
|
|
@ -18,10 +16,8 @@ import org.fnives.test.showcase.model.content.ContentId
|
|||
import org.fnives.test.showcase.model.content.FavouriteContent
|
||||
import org.fnives.test.showcase.model.shared.Resource
|
||||
import org.fnives.test.showcase.ui.shared.Event
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class MainViewModel @Inject constructor(
|
||||
class MainViewModel(
|
||||
private val getAllContentUseCase: GetAllContentUseCase,
|
||||
private val logoutUseCase: LogoutUseCase,
|
||||
private val fetchContentUseCase: FetchContentUseCase,
|
||||
|
|
|
|||
|
|
@ -4,15 +4,12 @@ import androidx.lifecycle.LiveData
|
|||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.fnives.test.showcase.core.login.IsUserLoggedInUseCase
|
||||
import org.fnives.test.showcase.ui.shared.Event
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class SplashViewModel @Inject constructor(isUserLoggedInUseCase: IsUserLoggedInUseCase) : ViewModel() {
|
||||
class SplashViewModel(isUserLoggedInUseCase: IsUserLoggedInUseCase) : ViewModel() {
|
||||
|
||||
private val _navigateTo = MutableLiveData<Event<NavigateTo>>()
|
||||
val navigateTo: LiveData<Event<NavigateTo>> = _navigateTo
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<resources>
|
||||
<string name="app_name">Test ShowCase</string>
|
||||
<string name="login">Login</string>
|
||||
<string name="username">Username</string>
|
||||
<string name="password">Password</string>
|
||||
|
|
|
|||
|
|
@ -1,101 +0,0 @@
|
|||
package org.fnives.test.showcase.favourite
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import dagger.hilt.android.testing.HiltAndroidRule
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.take
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||
import kotlinx.coroutines.test.TestCoroutineScheduler
|
||||
import kotlinx.coroutines.test.TestDispatcher
|
||||
import kotlinx.coroutines.test.advanceUntilIdle
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.fnives.test.showcase.core.storage.content.FavouriteContentLocalStorage
|
||||
import org.fnives.test.showcase.model.content.ContentId
|
||||
import org.fnives.test.showcase.storage.database.DatabaseInitialization
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@HiltAndroidTest
|
||||
internal class FavouriteContentLocalStorageImplTest {
|
||||
|
||||
@get:Rule
|
||||
val hiltRule = HiltAndroidRule(this)
|
||||
|
||||
@Inject
|
||||
lateinit var sut: FavouriteContentLocalStorage
|
||||
private lateinit var testDispatcher: TestDispatcher
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
testDispatcher = StandardTestDispatcher(TestCoroutineScheduler())
|
||||
DatabaseInitialization.dispatcher = testDispatcher
|
||||
hiltRule.inject()
|
||||
}
|
||||
|
||||
/** GIVEN content_id WHEN added to Favourite THEN it can be read out */
|
||||
@Test
|
||||
fun addingContentIdToFavouriteCanBeLaterReadOut() = runTest(testDispatcher) {
|
||||
val expected = listOf(ContentId("a"))
|
||||
|
||||
sut.markAsFavourite(ContentId("a"))
|
||||
val actual = sut.observeFavourites().first()
|
||||
|
||||
Assert.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
/** GIVEN content_id added WHEN removed to Favourite THEN it no longer can be read out */
|
||||
@Test
|
||||
fun contentIdAddedThenRemovedCanNoLongerBeReadOut() = runTest(testDispatcher) {
|
||||
val expected = listOf<ContentId>()
|
||||
sut.markAsFavourite(ContentId("b"))
|
||||
|
||||
sut.deleteAsFavourite(ContentId("b"))
|
||||
val actual = sut.observeFavourites().first()
|
||||
|
||||
Assert.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
/** GIVEN empty database WHILE observing content WHEN favourite added THEN change is emitted */
|
||||
@Test
|
||||
fun addingFavouriteUpdatesExistingObservers() = runTest(testDispatcher) {
|
||||
val expected = listOf(listOf(), listOf(ContentId("a")))
|
||||
|
||||
val actual = async(coroutineContext) {
|
||||
sut.observeFavourites().take(2).toList()
|
||||
}
|
||||
advanceUntilIdle()
|
||||
|
||||
sut.markAsFavourite(ContentId("a"))
|
||||
advanceUntilIdle()
|
||||
|
||||
Assert.assertEquals(expected, actual.getCompleted())
|
||||
}
|
||||
|
||||
/** GIVEN non empty database WHILE observing content WHEN favourite removed THEN change is emitted */
|
||||
@Test
|
||||
fun removingFavouriteUpdatesExistingObservers() = runTest(testDispatcher) {
|
||||
val expected = listOf(listOf(ContentId("a")), listOf())
|
||||
sut.markAsFavourite(ContentId("a"))
|
||||
|
||||
val actual = async(coroutineContext) {
|
||||
sut.observeFavourites().take(2).toList()
|
||||
}
|
||||
advanceUntilIdle()
|
||||
|
||||
sut.deleteAsFavourite(ContentId("a"))
|
||||
advanceUntilIdle()
|
||||
|
||||
Assert.assertEquals(expected, actual.getCompleted())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
sdk=28
|
||||
shadows=org.fnives.test.showcase.testutils.shadow.ShadowSnackbar
|
||||
instrumentedPackages=androidx.loader.content
|
||||
application=dagger.hilt.android.testing.HiltTestApplication
|
||||
|
|
@ -5,8 +5,9 @@ import androidx.test.core.app.ActivityScenario
|
|||
import org.fnives.test.showcase.network.mockserver.MockServerScenarioSetup
|
||||
import org.fnives.test.showcase.network.mockserver.scenario.auth.AuthScenario
|
||||
import org.fnives.test.showcase.testutils.configuration.MainDispatcherTestRule
|
||||
import org.fnives.test.showcase.ui.ActivityClassHolder
|
||||
import org.fnives.test.showcase.ui.auth.AuthActivity
|
||||
import org.fnives.test.showcase.ui.home.HomeRobot
|
||||
import org.fnives.test.showcase.ui.home.MainActivity
|
||||
import org.fnives.test.showcase.ui.login.LoginRobot
|
||||
import org.koin.test.KoinTest
|
||||
|
||||
|
|
@ -22,7 +23,7 @@ object SetupAuthenticationState : KoinTest {
|
|||
password = "b"
|
||||
)
|
||||
)
|
||||
val activityScenario = ActivityScenario.launch(ActivityClassHolder.authActivity().java)
|
||||
val activityScenario = ActivityScenario.launch(AuthActivity::class.java)
|
||||
activityScenario.moveToState(Lifecycle.State.RESUMED)
|
||||
val loginRobot = LoginRobot()
|
||||
loginRobot.setupIntentResults()
|
||||
|
|
@ -39,7 +40,7 @@ object SetupAuthenticationState : KoinTest {
|
|||
fun setupLogout(
|
||||
mainDispatcherTestRule: MainDispatcherTestRule
|
||||
) {
|
||||
val activityScenario = ActivityScenario.launch(ActivityClassHolder.mainActivity().java)
|
||||
val activityScenario = ActivityScenario.launch(MainActivity::class.java)
|
||||
activityScenario.moveToState(Lifecycle.State.RESUMED)
|
||||
val homeRobot = HomeRobot()
|
||||
homeRobot
|
||||
|
|
|
|||
|
|
@ -26,14 +26,14 @@ import org.fnives.test.showcase.testutils.statesetup.SetupAuthenticationState
|
|||
import org.fnives.test.showcase.testutils.viewactions.PullToRefresh
|
||||
import org.fnives.test.showcase.testutils.viewactions.WithDrawable
|
||||
import org.fnives.test.showcase.testutils.viewactions.notIntended
|
||||
import org.fnives.test.showcase.ui.ActivityClassHolder
|
||||
import org.fnives.test.showcase.ui.auth.AuthActivity
|
||||
import org.hamcrest.Matchers.allOf
|
||||
|
||||
class HomeRobot : Robot {
|
||||
|
||||
override fun init() {
|
||||
Intents.init()
|
||||
Intents.intending(IntentMatchers.hasComponent(ActivityClassHolder.authActivity().java.canonicalName))
|
||||
Intents.intending(IntentMatchers.hasComponent(AuthActivity::class.java.canonicalName))
|
||||
.respondWith(Instrumentation.ActivityResult(0, null))
|
||||
}
|
||||
|
||||
|
|
@ -42,11 +42,11 @@ class HomeRobot : Robot {
|
|||
}
|
||||
|
||||
fun assertNavigatedToAuth() = apply {
|
||||
Intents.intended(IntentMatchers.hasComponent(ActivityClassHolder.authActivity().java.canonicalName))
|
||||
Intents.intended(IntentMatchers.hasComponent(AuthActivity::class.java.canonicalName))
|
||||
}
|
||||
|
||||
fun assertDidNotNavigateToAuth() = apply {
|
||||
notIntended(IntentMatchers.hasComponent(ActivityClassHolder.authActivity().java.canonicalName))
|
||||
notIntended(IntentMatchers.hasComponent(AuthActivity::class.java.canonicalName))
|
||||
}
|
||||
|
||||
fun clickSignOut() = apply {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import org.fnives.test.showcase.testutils.configuration.SpecificTestConfiguratio
|
|||
import org.fnives.test.showcase.testutils.configuration.TestConfigurationsFactory
|
||||
import org.fnives.test.showcase.testutils.robot.Robot
|
||||
import org.fnives.test.showcase.testutils.viewactions.notIntended
|
||||
import org.fnives.test.showcase.ui.ActivityClassHolder
|
||||
import org.fnives.test.showcase.ui.home.MainActivity
|
||||
import org.hamcrest.core.IsNot.not
|
||||
|
||||
class LoginRobot(
|
||||
|
|
@ -41,7 +41,7 @@ class LoginRobot(
|
|||
}
|
||||
|
||||
fun setupIntentResults() {
|
||||
intending(hasComponent(ActivityClassHolder.mainActivity().java.canonicalName))
|
||||
intending(hasComponent(MainActivity::class.java.canonicalName))
|
||||
.respondWith(Instrumentation.ActivityResult(Activity.RESULT_OK, Intent()))
|
||||
}
|
||||
|
||||
|
|
@ -95,10 +95,10 @@ class LoginRobot(
|
|||
}
|
||||
|
||||
fun assertNavigatedToHome() = apply {
|
||||
intended(hasComponent(ActivityClassHolder.mainActivity().java.canonicalName))
|
||||
intended(hasComponent(MainActivity::class.java.canonicalName))
|
||||
}
|
||||
|
||||
fun assertNotNavigatedToHome() = apply {
|
||||
notIntended(hasComponent(ActivityClassHolder.mainActivity().java.canonicalName))
|
||||
notIntended(hasComponent(MainActivity::class.java.canonicalName))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,15 +8,16 @@ import org.fnives.test.showcase.testutils.configuration.MainDispatcherTestRule
|
|||
import org.fnives.test.showcase.testutils.robot.Robot
|
||||
import org.fnives.test.showcase.testutils.statesetup.SetupAuthenticationState
|
||||
import org.fnives.test.showcase.testutils.viewactions.notIntended
|
||||
import org.fnives.test.showcase.ui.ActivityClassHolder
|
||||
import org.fnives.test.showcase.ui.auth.AuthActivity
|
||||
import org.fnives.test.showcase.ui.home.MainActivity
|
||||
|
||||
class SplashRobot : Robot {
|
||||
|
||||
override fun init() {
|
||||
Intents.init()
|
||||
Intents.intending(IntentMatchers.hasComponent(ActivityClassHolder.mainActivity().java.canonicalName))
|
||||
Intents.intending(IntentMatchers.hasComponent(MainActivity::class.java.canonicalName))
|
||||
.respondWith(Instrumentation.ActivityResult(0, null))
|
||||
Intents.intending(IntentMatchers.hasComponent(ActivityClassHolder.authActivity().java.canonicalName))
|
||||
Intents.intending(IntentMatchers.hasComponent(AuthActivity::class.java.canonicalName))
|
||||
.respondWith(Instrumentation.ActivityResult(0, null))
|
||||
}
|
||||
|
||||
|
|
@ -42,18 +43,18 @@ class SplashRobot : Robot {
|
|||
}
|
||||
|
||||
fun assertHomeIsStarted() = apply {
|
||||
Intents.intended(IntentMatchers.hasComponent(ActivityClassHolder.mainActivity().java.canonicalName))
|
||||
Intents.intended(IntentMatchers.hasComponent(MainActivity::class.java.canonicalName))
|
||||
}
|
||||
|
||||
fun assertHomeIsNotStarted() = apply {
|
||||
notIntended(IntentMatchers.hasComponent(ActivityClassHolder.mainActivity().java.canonicalName))
|
||||
notIntended(IntentMatchers.hasComponent(MainActivity::class.java.canonicalName))
|
||||
}
|
||||
|
||||
fun assertAuthIsStarted() = apply {
|
||||
Intents.intended(IntentMatchers.hasComponent(ActivityClassHolder.authActivity().java.canonicalName))
|
||||
Intents.intended(IntentMatchers.hasComponent(AuthActivity::class.java.canonicalName))
|
||||
}
|
||||
|
||||
fun assertAuthIsNotStarted() = apply {
|
||||
notIntended(IntentMatchers.hasComponent(ActivityClassHolder.authActivity().java.canonicalName))
|
||||
notIntended(IntentMatchers.hasComponent(AuthActivity::class.java.canonicalName))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,41 +0,0 @@
|
|||
package org.fnives.test.showcase.testutils.idling
|
||||
|
||||
import androidx.annotation.CheckResult
|
||||
import androidx.test.espresso.IdlingResource
|
||||
import okhttp3.OkHttpClient
|
||||
import org.fnives.test.showcase.hilt.SessionLessQualifier
|
||||
import org.fnives.test.showcase.hilt.SessionQualifier
|
||||
import javax.inject.Inject
|
||||
|
||||
class NetworkSynchronization @Inject constructor(
|
||||
@SessionQualifier
|
||||
private val sessionOkhttpClient: OkHttpClient,
|
||||
@SessionLessQualifier
|
||||
private val sessionlessOkhttpClient: OkHttpClient
|
||||
) {
|
||||
|
||||
@CheckResult
|
||||
fun registerNetworkingSynchronization(): Disposable {
|
||||
val idlingResources = OkHttpClientTypes.values()
|
||||
.map { it to getOkHttpClient(it) }
|
||||
.associateBy { it.second.dispatcher }
|
||||
.values
|
||||
.map { (key, client) -> client.asIdlingResource(key.qualifier) }
|
||||
.map(::IdlingResourceDisposable)
|
||||
|
||||
return CompositeDisposable(idlingResources)
|
||||
}
|
||||
|
||||
private fun getOkHttpClient(type: OkHttpClientTypes): OkHttpClient =
|
||||
when (type) {
|
||||
OkHttpClientTypes.SESSION -> sessionOkhttpClient
|
||||
OkHttpClientTypes.SESSIONLESS -> sessionlessOkhttpClient
|
||||
}
|
||||
|
||||
private fun OkHttpClient.asIdlingResource(name: String): IdlingResource =
|
||||
OkHttp3IdlingResource.create(name, this)
|
||||
|
||||
enum class OkHttpClientTypes(val qualifier: String) {
|
||||
SESSION("SESSION-NETWORKING"), SESSIONLESS("SESSIONLESS-NETWORKING")
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
package org.fnives.test.showcase.ui
|
||||
|
||||
import org.fnives.test.showcase.ui.auth.HiltAuthActivity
|
||||
import org.fnives.test.showcase.ui.home.HiltMainActivity
|
||||
import org.fnives.test.showcase.ui.splash.HiltSplashActivity
|
||||
|
||||
object ActivityClassHolder {
|
||||
|
||||
fun authActivity() = HiltAuthActivity::class
|
||||
|
||||
fun mainActivity() = HiltMainActivity::class
|
||||
|
||||
fun splashActivity() = HiltSplashActivity::class
|
||||
}
|
||||
|
|
@ -1,251 +0,0 @@
|
|||
package org.fnives.test.showcase.ui.home
|
||||
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.test.core.app.ActivityScenario
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import dagger.hilt.android.testing.HiltAndroidRule
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import org.fnives.test.showcase.model.content.FavouriteContent
|
||||
import org.fnives.test.showcase.network.mockserver.ContentData
|
||||
import org.fnives.test.showcase.network.mockserver.scenario.content.ContentScenario
|
||||
import org.fnives.test.showcase.network.mockserver.scenario.refresh.RefreshTokenScenario
|
||||
import org.fnives.test.showcase.testutils.MockServerScenarioSetupTestRule
|
||||
import org.fnives.test.showcase.testutils.configuration.SpecificTestConfigurationsFactory
|
||||
import org.fnives.test.showcase.testutils.idling.Disposable
|
||||
import org.fnives.test.showcase.testutils.idling.NetworkSynchronization
|
||||
import org.fnives.test.showcase.testutils.idling.loopMainThreadFor
|
||||
import org.fnives.test.showcase.testutils.idling.loopMainThreadUntilIdleWithIdlingResources
|
||||
import org.fnives.test.showcase.testutils.robot.RobotTestRule
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@HiltAndroidTest
|
||||
class MainActivityTest {
|
||||
|
||||
private lateinit var activityScenario: ActivityScenario<HiltMainActivity>
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val instantTaskExecutorRule = InstantTaskExecutorRule()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val snackbarVerificationTestRule = SpecificTestConfigurationsFactory.createSnackbarVerification()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val robotRule = RobotTestRule(HomeRobot())
|
||||
private val homeRobot get() = robotRule.robot
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val mockServerScenarioSetupTestRule = MockServerScenarioSetupTestRule()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val mainDispatcherTestRule = SpecificTestConfigurationsFactory.createMainDispatcherTestRule()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val hiltRule = HiltAndroidRule(this)
|
||||
|
||||
@Inject
|
||||
lateinit var networkSynchronization: NetworkSynchronization
|
||||
|
||||
private lateinit var disposable: Disposable
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
SpecificTestConfigurationsFactory.createServerTypeConfiguration()
|
||||
.invoke(mockServerScenarioSetupTestRule.mockServerScenarioSetup)
|
||||
|
||||
hiltRule.inject()
|
||||
disposable = networkSynchronization.registerNetworkingSynchronization()
|
||||
homeRobot.setupLogin(mainDispatcherTestRule, mockServerScenarioSetupTestRule.mockServerScenarioSetup)
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
activityScenario.moveToState(Lifecycle.State.DESTROYED)
|
||||
disposable.dispose()
|
||||
}
|
||||
|
||||
/** GIVEN initialized MainActivity WHEN signout is clicked THEN user is signed out */
|
||||
@Test
|
||||
fun signOutClickedResultsInNavigation() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Error(false))
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
||||
homeRobot.clickSignOut()
|
||||
mainDispatcherTestRule.advanceUntilIdleOrActivityIsDestroyed()
|
||||
|
||||
homeRobot.assertNavigatedToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN success response WHEN data is returned THEN it is shown on the ui */
|
||||
@Test
|
||||
fun successfulDataLoadingShowsTheElementsOnTheUI() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Success(false))
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
ContentData.contentSuccess.forEachIndexed { index, content ->
|
||||
homeRobot.assertContainsItem(index, FavouriteContent(content, false))
|
||||
}
|
||||
homeRobot.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN success response WHEN item is clicked THEN ui is updated */
|
||||
@Test
|
||||
fun clickingOnListElementUpdatesTheElementsFavouriteState() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Success(false))
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
homeRobot.clickOnContentItem(0, ContentData.contentSuccess.first())
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
||||
val expectedItem = FavouriteContent(ContentData.contentSuccess.first(), true)
|
||||
homeRobot.assertContainsItem(0, expectedItem)
|
||||
.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN success response WHEN item is clicked THEN ui is updated even if activity is recreated */
|
||||
@Test
|
||||
fun elementFavouritedIsKeptEvenIfActivityIsRecreated() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Success(false))
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
homeRobot.clickOnContentItem(0, ContentData.contentSuccess.first())
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
||||
val expectedItem = FavouriteContent(ContentData.contentSuccess.first(), true)
|
||||
|
||||
activityScenario.moveToState(Lifecycle.State.DESTROYED)
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
||||
homeRobot.assertContainsItem(0, expectedItem)
|
||||
.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN success response WHEN item is clicked then clicked again THEN ui is updated */
|
||||
@Test
|
||||
fun clickingAnElementMultipleTimesProperlyUpdatesIt() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Success(false))
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
homeRobot.clickOnContentItem(0, ContentData.contentSuccess.first())
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
homeRobot.clickOnContentItem(0, ContentData.contentSuccess.first())
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
||||
val expectedItem = FavouriteContent(ContentData.contentSuccess.first(), false)
|
||||
homeRobot.assertContainsItem(0, expectedItem)
|
||||
.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN error response WHEN loaded THEN error is Shown */
|
||||
@Test
|
||||
fun networkErrorResultsInUIErrorStateShown() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Error(false))
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
||||
homeRobot.assertContainsNoItems()
|
||||
.assertContainsError()
|
||||
.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN error response then success WHEN retried THEN success is shown */
|
||||
@Test
|
||||
fun retryingFromErrorStateAndSucceedingShowsTheData() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(
|
||||
ContentScenario.Error(false)
|
||||
.then(ContentScenario.Success(false))
|
||||
)
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
||||
homeRobot.swipeRefresh()
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
loopMainThreadFor(2000L)
|
||||
|
||||
ContentData.contentSuccess.forEachIndexed { index, content ->
|
||||
homeRobot.assertContainsItem(index, FavouriteContent(content, false))
|
||||
}
|
||||
homeRobot.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN success then error WHEN retried THEN error is shown */
|
||||
@Test
|
||||
fun errorIsShownIfTheDataIsFetchedAndErrorIsReceived() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(
|
||||
ContentScenario.Success(false)
|
||||
.then(ContentScenario.Error(false))
|
||||
)
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
||||
homeRobot.swipeRefresh()
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
loopMainThreadUntilIdleWithIdlingResources()
|
||||
mainDispatcherTestRule.advanceTimeBy(1000L)
|
||||
loopMainThreadFor(1000)
|
||||
|
||||
homeRobot
|
||||
.assertContainsError()
|
||||
.assertContainsNoItems()
|
||||
.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN unauthenticated then success WHEN loaded THEN success is shown */
|
||||
@Test
|
||||
fun authenticationIsHandledWithASingleLoading() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(
|
||||
ContentScenario.Unauthorized(false)
|
||||
.then(ContentScenario.Success(true))
|
||||
)
|
||||
.setScenario(RefreshTokenScenario.Success)
|
||||
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
||||
ContentData.contentSuccess.forEachIndexed { index, content ->
|
||||
homeRobot.assertContainsItem(index, FavouriteContent(content, false))
|
||||
}
|
||||
homeRobot.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN unauthenticated then error WHEN loaded THEN navigated to auth */
|
||||
@Test
|
||||
fun sessionExpirationResultsInNavigation() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Unauthorized(false))
|
||||
.setScenario(RefreshTokenScenario.Error)
|
||||
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
||||
homeRobot.assertNavigatedToAuth()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,170 +0,0 @@
|
|||
package org.fnives.test.showcase.ui.login
|
||||
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.test.core.app.ActivityScenario
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import dagger.hilt.android.testing.HiltAndroidRule
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import org.fnives.test.showcase.R
|
||||
import org.fnives.test.showcase.network.mockserver.scenario.auth.AuthScenario
|
||||
import org.fnives.test.showcase.testutils.MockServerScenarioSetupTestRule
|
||||
import org.fnives.test.showcase.testutils.configuration.SpecificTestConfigurationsFactory
|
||||
import org.fnives.test.showcase.testutils.idling.Disposable
|
||||
import org.fnives.test.showcase.testutils.idling.NetworkSynchronization
|
||||
import org.fnives.test.showcase.testutils.robot.RobotTestRule
|
||||
import org.fnives.test.showcase.ui.auth.HiltAuthActivity
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@HiltAndroidTest
|
||||
class AuthActivityTest {
|
||||
|
||||
private lateinit var activityScenario: ActivityScenario<HiltAuthActivity>
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val instantTaskExecutorRule = InstantTaskExecutorRule()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val snackbarVerificationTestRule = SpecificTestConfigurationsFactory.createSnackbarVerification()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val robotRule = RobotTestRule(LoginRobot())
|
||||
private val loginRobot get() = robotRule.robot
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val mockServerScenarioSetupTestRule = MockServerScenarioSetupTestRule()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val mainDispatcherTestRule = SpecificTestConfigurationsFactory.createMainDispatcherTestRule()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val hiltRule = HiltAndroidRule(this)
|
||||
|
||||
@Inject
|
||||
lateinit var networkSynchronization: NetworkSynchronization
|
||||
|
||||
private lateinit var disposable: Disposable
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
SpecificTestConfigurationsFactory.createServerTypeConfiguration()
|
||||
.invoke(mockServerScenarioSetupTestRule.mockServerScenarioSetup)
|
||||
hiltRule.inject()
|
||||
disposable = networkSynchronization.registerNetworkingSynchronization()
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
activityScenario.moveToState(Lifecycle.State.DESTROYED)
|
||||
disposable.dispose()
|
||||
}
|
||||
|
||||
/** GIVEN non empty password and username and successful response WHEN signIn THEN no error is shown and navigating to home */
|
||||
@Test
|
||||
fun properLoginResultsInNavigationToHome() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup.setScenario(
|
||||
AuthScenario.Success(
|
||||
password = "alma",
|
||||
username = "banan"
|
||||
)
|
||||
)
|
||||
activityScenario = ActivityScenario.launch(HiltAuthActivity::class.java)
|
||||
loginRobot
|
||||
.setPassword("alma")
|
||||
.setUsername("banan")
|
||||
.assertPassword("alma")
|
||||
.assertUsername("banan")
|
||||
.clickOnLogin()
|
||||
.assertLoadingBeforeRequests()
|
||||
|
||||
mainDispatcherTestRule.advanceUntilIdleOrActivityIsDestroyed()
|
||||
loginRobot.assertNavigatedToHome()
|
||||
}
|
||||
|
||||
/** GIVEN empty password and username WHEN signIn THEN error password is shown */
|
||||
@Test
|
||||
fun emptyPasswordShowsProperErrorMessage() {
|
||||
activityScenario = ActivityScenario.launch(HiltAuthActivity::class.java)
|
||||
loginRobot
|
||||
.setUsername("banan")
|
||||
.assertUsername("banan")
|
||||
.clickOnLogin()
|
||||
.assertLoadingBeforeRequests()
|
||||
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
loginRobot.assertErrorIsShown(R.string.password_is_invalid)
|
||||
.assertNotNavigatedToHome()
|
||||
.assertNotLoading()
|
||||
}
|
||||
|
||||
/** GIVEN password and empty username WHEN signIn THEN error username is shown */
|
||||
@Test
|
||||
fun emptyUserNameShowsProperErrorMessage() {
|
||||
activityScenario = ActivityScenario.launch(HiltAuthActivity::class.java)
|
||||
loginRobot
|
||||
.setPassword("banan")
|
||||
.assertPassword("banan")
|
||||
.clickOnLogin()
|
||||
.assertLoadingBeforeRequests()
|
||||
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
loginRobot.assertErrorIsShown(R.string.username_is_invalid)
|
||||
.assertNotNavigatedToHome()
|
||||
.assertNotLoading()
|
||||
}
|
||||
|
||||
/** GIVEN password and username and invalid credentials response WHEN signIn THEN error invalid credentials is shown */
|
||||
@Test
|
||||
fun invalidCredentialsGivenShowsProperErrorMessage() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup.setScenario(
|
||||
AuthScenario.InvalidCredentials(username = "alma", password = "banan")
|
||||
)
|
||||
activityScenario = ActivityScenario.launch(HiltAuthActivity::class.java)
|
||||
loginRobot
|
||||
.setUsername("alma")
|
||||
.setPassword("banan")
|
||||
.assertUsername("alma")
|
||||
.assertPassword("banan")
|
||||
.clickOnLogin()
|
||||
.assertLoadingBeforeRequests()
|
||||
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
loginRobot.assertErrorIsShown(R.string.credentials_invalid)
|
||||
.assertNotNavigatedToHome()
|
||||
.assertNotLoading()
|
||||
}
|
||||
|
||||
/** GIVEN password and username and error response WHEN signIn THEN error invalid credentials is shown */
|
||||
@Test
|
||||
fun networkErrorShowsProperErrorMessage() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup.setScenario(
|
||||
AuthScenario.GenericError(username = "alma", password = "banan")
|
||||
)
|
||||
activityScenario = ActivityScenario.launch(HiltAuthActivity::class.java)
|
||||
loginRobot
|
||||
.setUsername("alma")
|
||||
.setPassword("banan")
|
||||
.assertUsername("alma")
|
||||
.assertPassword("banan")
|
||||
.clickOnLogin()
|
||||
.assertLoadingBeforeRequests()
|
||||
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
loginRobot.assertErrorIsShown(R.string.something_went_wrong)
|
||||
.assertNotNavigatedToHome()
|
||||
.assertNotLoading()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
package org.fnives.test.showcase.ui.splash
|
||||
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.test.core.app.ActivityScenario
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import dagger.hilt.android.testing.HiltAndroidRule
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import org.fnives.test.showcase.testutils.MockServerScenarioSetupTestRule
|
||||
import org.fnives.test.showcase.testutils.configuration.SpecificTestConfigurationsFactory
|
||||
import org.fnives.test.showcase.testutils.idling.Disposable
|
||||
import org.fnives.test.showcase.testutils.idling.NetworkSynchronization
|
||||
import org.fnives.test.showcase.testutils.robot.RobotTestRule
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.koin.test.KoinTest
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@HiltAndroidTest
|
||||
class SplashActivityTest : KoinTest {
|
||||
|
||||
private var activityScenario: ActivityScenario<HiltSplashActivity>? = null
|
||||
|
||||
private val splashRobot: SplashRobot get() = robotTestRule.robot
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val instantTaskExecutorRule = InstantTaskExecutorRule()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val robotTestRule = RobotTestRule(SplashRobot())
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val mainDispatcherTestRule = SpecificTestConfigurationsFactory.createMainDispatcherTestRule()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val mockServerScenarioSetupTestRule = MockServerScenarioSetupTestRule()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val hiltRule = HiltAndroidRule(this)
|
||||
|
||||
@Inject
|
||||
lateinit var networkSynchronization: NetworkSynchronization
|
||||
|
||||
var disposable: Disposable? = null
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
SpecificTestConfigurationsFactory.createServerTypeConfiguration()
|
||||
.invoke(mockServerScenarioSetupTestRule.mockServerScenarioSetup)
|
||||
hiltRule.inject()
|
||||
disposable = networkSynchronization.registerNetworkingSynchronization()
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
activityScenario?.moveToState(Lifecycle.State.DESTROYED)
|
||||
disposable?.dispose()
|
||||
}
|
||||
|
||||
/** GIVEN loggedInState WHEN opened THEN MainActivity is started */
|
||||
@Test
|
||||
fun loggedInStateNavigatesToHome() {
|
||||
splashRobot.setupLoggedInState(mainDispatcherTestRule, mockServerScenarioSetupTestRule.mockServerScenarioSetup)
|
||||
|
||||
activityScenario = ActivityScenario.launch(HiltSplashActivity::class.java)
|
||||
|
||||
mainDispatcherTestRule.advanceTimeBy(501)
|
||||
|
||||
splashRobot.assertHomeIsStarted()
|
||||
.assertAuthIsNotStarted()
|
||||
}
|
||||
|
||||
/** GIVEN loggedOffState WHEN opened THEN AuthActivity is started */
|
||||
@Test
|
||||
fun loggedOutStatesNavigatesToAuthentication() {
|
||||
splashRobot.setupLoggedOutState(mainDispatcherTestRule)
|
||||
|
||||
activityScenario = ActivityScenario.launch(HiltSplashActivity::class.java)
|
||||
|
||||
mainDispatcherTestRule.advanceTimeBy(501)
|
||||
|
||||
splashRobot.assertAuthIsStarted()
|
||||
.assertHomeIsNotStarted()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun loggedOutStatesNotEnoughTime() {
|
||||
splashRobot.setupLoggedOutState(mainDispatcherTestRule)
|
||||
|
||||
activityScenario = ActivityScenario.launch(HiltSplashActivity::class.java)
|
||||
|
||||
mainDispatcherTestRule.advanceTimeBy(10)
|
||||
|
||||
splashRobot.assertAuthIsNotStarted()
|
||||
.assertHomeIsNotStarted()
|
||||
}
|
||||
|
||||
/** GIVEN loggedInState and not enough time WHEN opened THEN no activity is started */
|
||||
@Test
|
||||
fun loggedInStatesNotEnoughTime() {
|
||||
splashRobot.setupLoggedInState(mainDispatcherTestRule, mockServerScenarioSetupTestRule.mockServerScenarioSetup)
|
||||
|
||||
activityScenario = ActivityScenario.launch(HiltSplashActivity::class.java)
|
||||
|
||||
mainDispatcherTestRule.advanceTimeBy(10)
|
||||
|
||||
splashRobot.assertHomeIsNotStarted()
|
||||
.assertAuthIsNotStarted()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
package org.fnives.test.showcase.ui
|
||||
|
||||
import org.fnives.test.showcase.ui.auth.AuthActivity
|
||||
import org.fnives.test.showcase.ui.home.MainActivity
|
||||
import org.fnives.test.showcase.ui.splash.SplashActivity
|
||||
|
||||
object ActivityClassHolder {
|
||||
|
||||
fun authActivity() = AuthActivity::class
|
||||
|
||||
fun mainActivity() = MainActivity::class
|
||||
|
||||
fun splashActivity() = SplashActivity::class
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue