-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #26 from azrael8576/test/ui-test
[Test] Add app navigation end to end test
- Loading branch information
Showing
3 changed files
with
212 additions
and
0 deletions.
There are no files selected for viewing
83 changes: 83 additions & 0 deletions
83
app/src/androidTest/java/com/wei/picquest/ui/NavigationRobot.kt
This file contains 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,83 @@ | ||
import androidx.annotation.StringRes | ||
import androidx.compose.ui.test.junit4.AndroidComposeTestRule | ||
import androidx.compose.ui.test.onNodeWithContentDescription | ||
import androidx.compose.ui.test.performClick | ||
import androidx.test.ext.junit.rules.ActivityScenarioRule | ||
import com.wei.picquest.MainActivity | ||
import kotlin.properties.ReadOnlyProperty | ||
|
||
/** | ||
* Robot for [NavigationTest]. | ||
* | ||
* 遵循此模型,找到測試使用者介面元素、檢查其屬性、和透過測試規則執行動作: | ||
* composeTestRule{.finder}{.assertion}{.action} | ||
* | ||
* Testing cheatsheet: | ||
* https://developer.android.com/jetpack/compose/testing-cheatsheet | ||
*/ | ||
internal fun navigationRobot( | ||
composeTestRule: AndroidComposeTestRule<ActivityScenarioRule<MainActivity>, MainActivity>, | ||
func: NavigationRobot.() -> Unit, | ||
) = NavigationRobot(composeTestRule).apply(func) | ||
|
||
internal open class NavigationRobot( | ||
private val composeTestRule: AndroidComposeTestRule<ActivityScenarioRule<MainActivity>, MainActivity>, | ||
) { | ||
private fun AndroidComposeTestRule<*, *>.stringResource(@StringRes resId: Int) = | ||
ReadOnlyProperty<Any?, String> { _, _ -> activity.getString(resId) } | ||
|
||
// The strings used for matching in these tests | ||
private val home by composeTestRule.stringResource(com.wei.picquest.R.string.home) | ||
private val photo by composeTestRule.stringResource(com.wei.picquest.R.string.photo) | ||
private val video by composeTestRule.stringResource(com.wei.picquest.R.string.video) | ||
private val contactMe by composeTestRule.stringResource(com.wei.picquest.R.string.contact_me) | ||
|
||
private val navHome by lazy { | ||
composeTestRule.onNodeWithContentDescription( | ||
home, | ||
useUnmergedTree = true, | ||
) | ||
} | ||
private val navPhoto by lazy { | ||
composeTestRule.onNodeWithContentDescription( | ||
photo, | ||
useUnmergedTree = true, | ||
) | ||
} | ||
private val navVideo by lazy { | ||
composeTestRule.onNodeWithContentDescription( | ||
video, | ||
useUnmergedTree = true, | ||
) | ||
} | ||
private val navContactMe by lazy { | ||
composeTestRule.onNodeWithContentDescription( | ||
contactMe, | ||
useUnmergedTree = true, | ||
) | ||
} | ||
|
||
internal fun clickNavHome() { | ||
navHome.performClick() | ||
// 等待任何動畫完成 | ||
composeTestRule.waitForIdle() | ||
} | ||
|
||
internal fun clickNavPhoto() { | ||
navPhoto.performClick() | ||
// 等待任何動畫完成 | ||
composeTestRule.waitForIdle() | ||
} | ||
|
||
internal fun clickVideo() { | ||
navVideo.performClick() | ||
// 等待任何動畫完成 | ||
composeTestRule.waitForIdle() | ||
} | ||
|
||
internal fun clickNavContactMe() { | ||
navContactMe.performClick() | ||
// 等待任何動畫完成 | ||
composeTestRule.waitForIdle() | ||
} | ||
} |
87 changes: 87 additions & 0 deletions
87
app/src/androidTest/java/com/wei/picquest/ui/NavigationTest.kt
This file contains 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,87 @@ | ||
package com.wei.picquest.ui | ||
|
||
import androidx.compose.ui.test.junit4.createAndroidComposeRule | ||
import androidx.test.espresso.Espresso | ||
import androidx.test.espresso.NoActivityResumedException | ||
import com.wei.picquest.MainActivity | ||
import com.wei.picquest.ui.robot.homeEndToEndRobot | ||
import dagger.hilt.android.testing.BindValue | ||
import dagger.hilt.android.testing.HiltAndroidRule | ||
import dagger.hilt.android.testing.HiltAndroidTest | ||
import navigationRobot | ||
import org.junit.Before | ||
import org.junit.Rule | ||
import org.junit.Test | ||
import org.junit.rules.TemporaryFolder | ||
|
||
/** | ||
* Tests all the navigation flows that are handled by the navigation library. | ||
*/ | ||
@HiltAndroidTest | ||
class NavigationTest { | ||
|
||
/** | ||
* Manages the components' state and is used to perform injection on your test | ||
*/ | ||
@get:Rule(order = 0) | ||
val hiltRule = HiltAndroidRule(this) | ||
|
||
/** | ||
* Create a temporary folder used to create a Data Store file. This guarantees that | ||
* the file is removed in between each test, preventing a crash. | ||
*/ | ||
@BindValue | ||
@get:Rule(order = 1) | ||
val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build() | ||
|
||
/** | ||
* Use the primary activity to initialize the app normally. | ||
*/ | ||
@get:Rule(order = 2) | ||
val composeTestRule = createAndroidComposeRule<MainActivity>() | ||
|
||
@Before | ||
fun setup() = hiltRule.inject() | ||
|
||
@Test | ||
fun firstScreen_isHome() { | ||
homeEndToEndRobot(composeTestRule) { | ||
verifyImportantNoteDisplayed() | ||
} | ||
} | ||
|
||
/* | ||
* When pressing back from any top level destination except "Home", the app navigates back | ||
* to the "Home" destination, no matter which destinations you visited in between. | ||
*/ | ||
@Test | ||
fun navigationBar_backFromAnyDestination_returnsToHome() { | ||
homeEndToEndRobot(composeTestRule) { | ||
navigationRobot(composeTestRule) { | ||
// GIVEN the user is on any of the top level destinations, THEN the Up arrow is not shown. | ||
clickNavContactMe() | ||
// WHEN the user uses the system button/gesture to go back | ||
Espresso.pressBack() | ||
} | ||
verifyImportantNoteDisplayed() | ||
} | ||
} | ||
|
||
/* | ||
* There should always be at most one instance of a top-level destination at the same time. | ||
*/ | ||
@Test(expected = NoActivityResumedException::class) | ||
fun topDestination_back_quitsApp() { | ||
homeEndToEndRobot(composeTestRule) { | ||
navigationRobot(composeTestRule) { | ||
// GIVEN the user navigates to the Contact Me destination | ||
clickNavContactMe() | ||
// and then navigates to the Home destination | ||
clickNavHome() | ||
// WHEN the user uses the system button/gesture to go back | ||
Espresso.pressBack() | ||
// THEN the app quits | ||
} | ||
} | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
app/src/androidTest/java/com/wei/picquest/ui/robot/HomeEndToEndRobot.kt
This file contains 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,42 @@ | ||
package com.wei.picquest.ui.robot | ||
|
||
import androidx.annotation.StringRes | ||
import androidx.compose.ui.test.assertIsDisplayed | ||
import androidx.compose.ui.test.hasContentDescription | ||
import androidx.compose.ui.test.junit4.AndroidComposeTestRule | ||
import androidx.test.ext.junit.rules.ActivityScenarioRule | ||
import com.wei.picquest.MainActivity | ||
import kotlin.properties.ReadOnlyProperty | ||
import com.wei.picquest.feature.home.R as FeatureHomeR | ||
|
||
/** | ||
* Screen Robot for End To End Test. | ||
* | ||
* 遵循此模型,找到測試使用者介面元素、檢查其屬性、和透過測試規則執行動作: | ||
* composeTestRule{.finder}{.assertion}{.action} | ||
* | ||
* Testing cheatsheet: | ||
* https://developer.android.com/jetpack/compose/testing-cheatsheet | ||
*/ | ||
internal fun homeEndToEndRobot( | ||
composeTestRule: AndroidComposeTestRule<ActivityScenarioRule<MainActivity>, MainActivity>, | ||
func: HomeEndToEndRobot.() -> Unit, | ||
) = HomeEndToEndRobot(composeTestRule).apply(func) | ||
|
||
internal open class HomeEndToEndRobot( | ||
private val composeTestRule: AndroidComposeTestRule<ActivityScenarioRule<MainActivity>, MainActivity>, | ||
) { | ||
private fun AndroidComposeTestRule<*, *>.stringResource(@StringRes resId: Int) = | ||
ReadOnlyProperty<Any?, String> { _, _ -> activity.getString(resId) } | ||
|
||
// The strings used for matching in these tests | ||
private val importantNoteDescription by composeTestRule.stringResource(FeatureHomeR.string.important_note) | ||
|
||
private val importantNote by lazy { | ||
composeTestRule.onNode(hasContentDescription(importantNoteDescription)) | ||
} | ||
|
||
fun verifyImportantNoteDisplayed() { | ||
importantNote.assertExists().assertIsDisplayed() | ||
} | ||
} |