Skip to content
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

Create UI / Instrumentation tests #27

Open
wants to merge 3 commits into
base: feature/slack
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ android {
targetSdk = (ProjectProperties.TARGET_SDK)
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner"
testInstrumentationRunner = "com.mutualmobile.base.TextPraxisApplication"
vectorDrawables.useSupportLibrary = true
}

Expand Down Expand Up @@ -112,7 +112,12 @@ dependencies {
testImplementation(TestLib.ROBO_ELECTRIC)
testImplementation(TestLib.COROUTINES)
testImplementation(TestLib.MOCKK)
androidTestImplementation(TestLib.MOCKK)
androidTestImplementation(TestLib.MOCK_WEB_SERVER)

androidTestImplementation("androidx.compose.ui:ui-test-junit4:${Lib.Android.COMPOSE_VERSION}")
debugImplementation("androidx.compose.ui:ui-test-manifest:${Lib.Android.COMPOSE_VERSION}")
androidTestImplementation("com.google.dagger:hilt-android-testing:2.38.1")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add this to TestLib. deps

kaptAndroidTest("com.google.dagger:hilt-android-compiler:2.38.1")
androidTestImplementation("androidx.test:runner:1.4.0")
}
36 changes: 36 additions & 0 deletions app/src/androidTest/java/com/mutualmobile/base/BaseComposeTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.mutualmobile.base

import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.mutualmobile.praxis.root.MainActivity
import dagger.hilt.android.testing.HiltAndroidRule
import javax.inject.Inject
import okhttp3.mockwebserver.MockWebServer
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
abstract class BaseComposeTest {

@get:Rule
val composeTestRule = createAndroidComposeRule<MainActivity>()

@get:Rule
var hiltRule = HiltAndroidRule(this)

@Inject
lateinit var mockWebServer: MockWebServer

@Before
fun setup() {
hiltRule.inject()
}

@After
fun tearDown() {
mockWebServer.shutdown()
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.mutualmobile.base

import android.app.Application
import android.content.Context
import android.os.Bundle
import android.os.StrictMode
import androidx.test.runner.AndroidJUnitRunner
import dagger.hilt.android.testing.HiltTestApplication

class TextPraxisApplication : AndroidJUnitRunner() {

override fun onCreate(arguments: Bundle?) {
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder().permitAll().build())
super.onCreate(arguments)
}

override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application {
return super.newApplication(cl, HiltTestApplication::class.java.name, context)
}
}
65 changes: 65 additions & 0 deletions app/src/androidTest/java/com/mutualmobile/di/FakeNetworkModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.mutualmobile.di

import com.mutualmobile.praxis.data.injection.NetworkModule
import com.mutualmobile.praxis.data.remote.JokeApiService
import com.mutualmobile.praxis.data.remote.RetrofitHelper
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import dagger.hilt.testing.TestInstallIn
import javax.inject.Named
import javax.inject.Singleton
import okhttp3.OkHttpClient
import okhttp3.mockwebserver.MockWebServer
import retrofit2.Retrofit

@Module
@TestInstallIn(
components = [SingletonComponent::class],
replaces = [NetworkModule::class]
)
class TestNetworkModule {

@Provides
@Singleton
fun provideMockWebServer(): MockWebServer {
var mockWebServer: MockWebServer? = null
val thread = Thread {
mockWebServer = MockWebServer()
mockWebServer?.start()
}
thread.start()
thread.join()
return mockWebServer!!
}

@Provides
@Singleton
fun provideBaseUrl(mockWebServer: MockWebServer): String {
return mockWebServer.url("/")
.toString()
}

@Provides
@Singleton
fun provideHttpClient(): OkHttpClient {
return RetrofitHelper.createOkHttpClient()
}

@Provides
@Singleton
fun provideRetrofit(
okHttpClient: OkHttpClient,
rootUrl: String
): Retrofit {
return RetrofitHelper.createRetrofitClient(okHttpClient, rootUrl)
}

@Provides
@Singleton
fun provideJokesApiService(retrofit: Retrofit): JokeApiService {
return JokeApiService.createRetrofitService(retrofit)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.mutualmobile.feat.jokes.ui.home

import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTextInput
import com.mutualmobile.base.BaseComposeTest
import com.mutualmobile.praxis.commonui.theme.PraxisTheme
import com.mutualmobile.utils.enqueueResponse
import dagger.hilt.android.testing.HiltAndroidTest
import org.junit.Test

@HiltAndroidTest
class DashboardShould : BaseComposeTest() {

@Test
fun display_demo_jokes() {
mockWebServer.enqueueResponse("jokes_response.json", 200)
composeTestRule.setContent {
PraxisTheme {
Dashboard()
}
}
with(composeTestRule) {
onNodeWithText("Chuck Norris can believe it's not butter.").assertIsDisplayed()
}
}

@Test
fun display_jokeDetailScreen_onClick_of_joke() {
with(composeTestRule) {
onNodeWithText("Email").performTextInput("[email protected]")
onNodeWithText("Password").performTextInput("testpassword")
onNodeWithText("Login").performClick()
onNodeWithText("Chuck Norris Random Joke Generator").assertIsDisplayed()
mockWebServer.enqueueResponse("jokes_response.json", 200)
onNodeWithText("Chuck Norris can believe it's not butter.").performClick()
onNodeWithText("Joke Detail").assertIsDisplayed()
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.mutualmobile.praxis.feat.authentication.ui

import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTextInput
import com.mutualmobile.base.BaseComposeTest
import dagger.hilt.android.testing.HiltAndroidTest
import org.junit.Test

@HiltAndroidTest
class AuthenticationUIShould: BaseComposeTest() {

@Test
fun display_emailErrorSnackBar_onClick_of_loginBtn_with_empty_credentials() {
with(composeTestRule) {
onNodeWithText("Login").performClick()
onNodeWithText("Email is not valid").assertIsDisplayed()
}
}

@Test
fun display_passwordErrorSnackBar_onClick_of_loginBtn_with_empty_password_only() {
with(composeTestRule) {
onNodeWithText("Email").performTextInput("[email protected]")
onNodeWithText("Login").performClick()
onNodeWithText("Password should be at least 6 characters long").assertIsDisplayed()
}
}

@Test
fun display_emailErrorSnackBar_onClick_of_loginBtn_with_empty_email_only() {
with(composeTestRule) {
onNodeWithText("Password").performTextInput("testpassword")
onNodeWithText("Login").performClick()
onNodeWithText("Email is not valid").assertIsDisplayed()
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.mutualmobile.praxis.root

import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTextInput
import com.mutualmobile.base.BaseComposeTest
import dagger.hilt.android.testing.HiltAndroidTest
import org.junit.Test

@HiltAndroidTest
class PraxisNavigationShould : BaseComposeTest() {

@Test
fun check_if_all_items_are_displayed_correctly() {
with(composeTestRule) {
onNodeWithText("Authentication").assertIsDisplayed()
onNodeWithContentDescription("Logo").assertIsDisplayed()
onNodeWithText("Email").assertIsDisplayed()
onNodeWithContentDescription("Email").assertIsDisplayed()
onNodeWithText("Password").assertIsDisplayed()
onNodeWithContentDescription("Password").assertIsDisplayed()
onNodeWithText("Login").assertIsDisplayed()
onNodeWithText("Forgot Password?").assertIsDisplayed()
}
}

@Test
fun navigate_to_forgotPasswordScreen_onClick_of_forgotPassword_text() {
with(composeTestRule) {
onNodeWithText("Forgot Password?").performClick()
onNodeWithText("Forgot Password").assertIsDisplayed()
}
}

@Test
fun navigate_to_dashboard_on_correct_credentials() {
with(composeTestRule) {
onNodeWithText("Email").performTextInput("[email protected]")
onNodeWithText("Password").performTextInput("testpassword")
onNodeWithText("Login").performClick()
onNodeWithText("Chuck Norris Random Joke Generator").assertIsDisplayed()
}
}
}
20 changes: 20 additions & 0 deletions app/src/androidTest/java/com/mutualmobile/utils/NetworkUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.mutualmobile.utils

import java.nio.charset.StandardCharsets
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import okio.buffer
import okio.source

internal fun MockWebServer.enqueueResponse(fileName: String, code: Int) {
val inputStream = javaClass.classLoader?.getResourceAsStream("responses/$fileName")

val source = inputStream?.let { inputStream.source().buffer() }
source?.let {
enqueue(
MockResponse()
.setResponseCode(code)
.setBody(source.readString(StandardCharsets.UTF_8))
)
}
}
30 changes: 30 additions & 0 deletions app/src/androidTest/resources/responses/jokes_response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"type": "success",
"value": [
{
"id": 427,
"joke": "Chuck Norris' favorite cereal is Kellogg's Nails 'N' Gravel.",
"categories": []
},
{
"id": 75,
"joke": "Chuck Norris can believe it's not butter.",
"categories": []
},
{
"id": 302,
"joke": "Chuck Norris doesn't go on the internet, he has every internet site stored in his memory. He refreshes webpages by blinking.",
"categories": []
},
{
"id": 275,
"joke": "Little Miss Muffet sat on her tuffet, until Chuck Norris roundhouse kicked her into a glacier.",
"categories": []
},
{
"id": 76,
"joke": "If tapped, a Chuck Norris roundhouse kick could power the country of Australia for 44 minutes.",
"categories": []
}
]
}
4 changes: 3 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
<uses-permission android:name="android.permission.INTERNET" />

<application
android:usesCleartextTraffic="true"
android:name=".PraxisApp"
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.App.SplashScreeTheme"
tools:ignore="GoogleAppIndexingWarning">
tools:ignore="GoogleAppIndexingWarning"
tools:targetApi="m">
<activity
android:name=".root.MainActivity"
android:exported="true"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ fun ForgotPasswordText(authVM: AuthVM) {
color = PraxisTheme.colors.accent,
)
) {
append("Forgot Password? ")
append("Forgot Password?")
}

}, onClick = {
Expand Down Expand Up @@ -194,7 +194,7 @@ private fun PasswordTF(authVM: AuthVM, focusRequester: FocusRequester) {
leadingIcon = {
Image(
painter = painterResource(id = R.drawable.ic_eye),
contentDescription = "email"
contentDescription = "Password"
)
},
colors = textFieldColors(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ fun ForgotPasswordUI(forgotPasswordVM: ForgotPasswordVM = hiltViewModel()){
.statusBarsPadding()
.navigationBarsPadding(),
topBar = {
CommonTopAppBar(titleText = "ForgotPasswordentication")
CommonTopAppBar(titleText = "Forgot Password")
}) {
ForgotPasswordSurface(forgotPasswordVM)
}
Expand Down