- UI test for unit change

This commit is contained in:
2023-12-25 17:54:30 +00:00
parent 32ce5112c1
commit c9d406fbb8
10 changed files with 98 additions and 12 deletions

View File

@@ -8,10 +8,9 @@ import android.content.Intent
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.view.WindowManager
import androidx.test.core.app.ActivityScenario import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
import androidx.test.espresso.Espresso import androidx.test.espresso.Espresso
import androidx.test.espresso.Root
import androidx.test.espresso.UiController import androidx.test.espresso.UiController
import androidx.test.espresso.ViewAction import androidx.test.espresso.ViewAction
import androidx.test.espresso.assertion.ViewAssertions import androidx.test.espresso.assertion.ViewAssertions
@@ -20,15 +19,12 @@ import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.GrantPermissionRule import androidx.test.rule.GrantPermissionRule
import com.appttude.h_mal.atlas_weather.application.TestAppClass import com.appttude.h_mal.atlas_weather.application.TestAppClass
import com.appttude.h_mal.atlas_weather.helpers.BaseCustomMatcher import com.appttude.h_mal.atlas_weather.data.prefs.PreferenceProvider
import com.appttude.h_mal.atlas_weather.helpers.BaseViewAction
import com.appttude.h_mal.atlas_weather.helpers.SnapshotRule import com.appttude.h_mal.atlas_weather.helpers.SnapshotRule
import com.appttude.h_mal.atlas_weather.utils.Stubs import com.appttude.h_mal.atlas_weather.utils.Stubs
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.hamcrest.Description
import org.hamcrest.Matcher import org.hamcrest.Matcher
import org.hamcrest.Matchers import org.hamcrest.Matchers
import org.hamcrest.TypeSafeMatcher
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
@@ -46,6 +42,8 @@ open class BaseTest<A : Activity>(
private lateinit var testActivity: Activity private lateinit var testActivity: Activity
private lateinit var decorView: View private lateinit var decorView: View
private val prefs by lazy { PreferenceProvider(ApplicationProvider.getApplicationContext()) }
@get:Rule @get:Rule
var permissionRule = GrantPermissionRule.grant(Manifest.permission.ACCESS_COARSE_LOCATION) var permissionRule = GrantPermissionRule.grant(Manifest.permission.ACCESS_COARSE_LOCATION)
@@ -87,6 +85,8 @@ open class BaseTest<A : Activity>(
testApp.stubLocation(location, lat, long) testApp.stubLocation(location, lat, long)
} }
fun clearPrefs() = prefs.clearPrefs()
fun getActivity() = testActivity fun getActivity() = testActivity
@After @After

View File

@@ -5,6 +5,7 @@ import android.view.View
import android.widget.DatePicker import android.widget.DatePicker
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.recyclerview.widget.RecyclerView.ViewHolder import androidx.recyclerview.widget.RecyclerView.ViewHolder
import androidx.test.espresso.Espresso
import androidx.test.espresso.Espresso.onData import androidx.test.espresso.Espresso.onData
import androidx.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.UiController import androidx.test.espresso.UiController
@@ -28,6 +29,8 @@ import org.hamcrest.Matcher
@SuppressWarnings("unused") @SuppressWarnings("unused")
open class BaseTestRobot { open class BaseTestRobot {
fun goBack() = Espresso.pressBack()
fun fillEditText(resId: Int, text: String?): ViewInteraction = fun fillEditText(resId: Int, text: String?): ViewInteraction =
onView(withId(resId)).perform( onView(withId(resId)).perform(
ViewActions.replaceText(text), ViewActions.replaceText(text),
@@ -151,4 +154,8 @@ open class BaseTestRobot {
) )
) )
} }
fun openMenuItem() {
matchView(R.id.settings_fragment).perform(click())
}
} }

View File

@@ -0,0 +1,48 @@
package com.appttude.h_mal.monoWeather.robot
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions
import androidx.test.espresso.contrib.RecyclerViewActions
import androidx.test.espresso.matcher.RootMatchers.isDialog
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import com.appttude.h_mal.atlas_weather.BaseTestRobot
import com.appttude.h_mal.atlas_weather.R
import com.appttude.h_mal.atlas_weather.model.types.UnitType
fun settingsScreen(func: SettingsScreen.() -> Unit) = SettingsScreen().apply { func() }
class SettingsScreen : BaseTestRobot() {
fun selectWeatherUnits(unitType: UnitType) {
onView(withId(androidx.preference.R.id.recycler_view))
.perform(
RecyclerViewActions.actionOnItem<ViewHolder>(
ViewMatchers.hasDescendant(withText(R.string.weather_units)),
click()))
val label = when (unitType) {
UnitType.METRIC -> "Metric"
UnitType.IMPERIAL -> "Imperial"
}
onView(withText(label))
.inRoot(isDialog())
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
.perform(click())
}
fun verifyCurrentTemperature(temperature: Int) =
matchText(R.id.temp_main_4, temperature.toString())
fun verifyCurrentLocation(location: String) = matchText(R.id.location_main_4, location)
fun refresh() = pullToRefresh(R.id.swipe_refresh)
fun verifyUnableToRetrieve() {
matchText(R.id.header_text, R.string.retrieve_warning)
matchText(R.id.body_text, R.string.empty_retrieve_warning)
}
}

View File

@@ -2,8 +2,10 @@ package com.appttude.h_mal.monoWeather.tests
import com.appttude.h_mal.atlas_weather.BaseTest import com.appttude.h_mal.atlas_weather.BaseTest
import com.appttude.h_mal.atlas_weather.model.types.UnitType
import com.appttude.h_mal.atlas_weather.ui.MainActivity import com.appttude.h_mal.atlas_weather.ui.MainActivity
import com.appttude.h_mal.atlas_weather.utils.Stubs import com.appttude.h_mal.atlas_weather.utils.Stubs
import com.appttude.h_mal.monoWeather.robot.settingsScreen
import com.appttude.h_mal.monoWeather.robot.weatherScreen import com.appttude.h_mal.monoWeather.robot.weatherScreen
import org.junit.Test import org.junit.Test
@@ -11,6 +13,7 @@ class HomePageUITest : BaseTest<MainActivity>(MainActivity::class.java) {
override fun beforeLaunch() { override fun beforeLaunch() {
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Metric) stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Metric)
clearPrefs()
} }
@Test @Test
@@ -21,4 +24,25 @@ class HomePageUITest : BaseTest<MainActivity>(MainActivity::class.java) {
verifyCurrentLocation("Mock Location") verifyCurrentLocation("Mock Location")
} }
} }
@Test
fun loadApp_changeToImperial_returnsValidPage() {
weatherScreen {
isDisplayed()
verifyCurrentTemperature(2)
verifyCurrentLocation("Mock Location")
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Imperial)
openMenuItem()
}
settingsScreen {
selectWeatherUnits(UnitType.IMPERIAL)
goBack()
}
weatherScreen {
isDisplayed()
refresh()
verifyCurrentTemperature(58)
verifyCurrentLocation("Mock Location")
}
}
} }

View File

@@ -2,6 +2,7 @@ package com.appttude.h_mal.atlas_weather.data.prefs
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.annotation.VisibleForTesting
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.appttude.h_mal.atlas_weather.data.room.entity.CURRENT_LOCATION import com.appttude.h_mal.atlas_weather.data.room.entity.CURRENT_LOCATION
import com.appttude.h_mal.atlas_weather.model.types.UnitType import com.appttude.h_mal.atlas_weather.model.types.UnitType
@@ -61,4 +62,9 @@ class PreferenceProvider(
return UnitType.getByName(unit) ?: UnitType.METRIC return UnitType.getByName(unit) ?: UnitType.METRIC
} }
@VisibleForTesting
fun clearPrefs() {
preference.edit().clear().apply()
}
} }

View File

@@ -9,7 +9,7 @@ import com.appttude.h_mal.atlas_weather.data.room.entity.EntityItem
@Database( @Database(
entities = [EntityItem::class], entities = [EntityItem::class],
version = 2, version = 1,
exportSchema = false exportSchema = false
) )
@TypeConverters(Converter::class) @TypeConverters(Converter::class)

View File

@@ -2,7 +2,6 @@ package com.appttude.h_mal.atlas_weather.viewmodel
import android.Manifest import android.Manifest
import androidx.annotation.RequiresPermission import androidx.annotation.RequiresPermission
import androidx.lifecycle.viewModelScope
import com.appttude.h_mal.atlas_weather.base.baseViewModels.BaseViewModel import com.appttude.h_mal.atlas_weather.base.baseViewModels.BaseViewModel
import com.appttude.h_mal.atlas_weather.data.WeatherSource import com.appttude.h_mal.atlas_weather.data.WeatherSource
import com.appttude.h_mal.atlas_weather.data.location.LocationProvider import com.appttude.h_mal.atlas_weather.data.location.LocationProvider
@@ -35,6 +34,7 @@ class MainViewModel(
val latLong = locationProvider.getCurrentLatLong() val latLong = locationProvider.getCurrentLatLong()
weatherSource.getWeather(latLon = latLong) weatherSource.getWeather(latLon = latLong)
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace()
onError(e.message ?: "Retrieving weather failed") onError(e.message ?: "Retrieving weather failed")
} }
} }

View File

@@ -6,10 +6,9 @@ import android.appwidget.AppWidgetManager
import android.content.ComponentName import android.content.ComponentName
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import androidx.annotation.RequiresPermission
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import com.appttude.h_mal.atlas_weather.R import com.appttude.h_mal.atlas_weather.R
import com.appttude.h_mal.atlas_weather.application.AppClass import com.appttude.h_mal.atlas_weather.application.BaseAppClass
import com.appttude.h_mal.atlas_weather.base.baseViewModels.BaseAndroidViewModel import com.appttude.h_mal.atlas_weather.base.baseViewModels.BaseAndroidViewModel
import com.appttude.h_mal.atlas_weather.data.WeatherSource import com.appttude.h_mal.atlas_weather.data.WeatherSource
import com.appttude.h_mal.atlas_weather.data.location.LocationProvider import com.appttude.h_mal.atlas_weather.data.location.LocationProvider
@@ -27,7 +26,7 @@ class SettingsViewModel(
private val settingsRepository: SettingsRepository private val settingsRepository: SettingsRepository
) : BaseAndroidViewModel(application) { ) : BaseAndroidViewModel(application) {
private fun getContext() = getApplication<AppClass>().applicationContext private fun getContext() = getApplication<BaseAppClass>().applicationContext
fun updateWidget() { fun updateWidget() {
val context = getContext() val context = getContext()
@@ -63,6 +62,7 @@ class SettingsViewModel(
val units = settingsRepository.getUnitType().name.lowercase(Locale.ROOT) val units = settingsRepository.getUnitType().name.lowercase(Locale.ROOT)
onSuccess("Units have been changes to $units") onSuccess("Units have been changes to $units")
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace()
onError(e.message ?: "Retrieving weather failed") onError(e.message ?: "Retrieving weather failed")
} }
} }

View File

@@ -33,6 +33,7 @@
<string name="no_weather_to_display">No weather to display</string> <string name="no_weather_to_display">No weather to display</string>
<string name="unit_key">Units</string> <string name="unit_key">Units</string>
<string name="widget_black_background">widget_black_background</string> <string name="widget_black_background">widget_black_background</string>
<string name="weather_units">Weather units</string>
<string-array name="units"> <string-array name="units">
<item>Metric</item> <item>Metric</item>

View File

@@ -2,7 +2,7 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<ListPreference <ListPreference
android:title="Weather units" android:title="@string/weather_units"
android:entries="@array/units" android:entries="@array/units"
android:entryValues="@array/units" android:entryValues="@array/units"
android:defaultValue="Metric" android:defaultValue="Metric"