1+ package com.darkrockstudios.app.securecamera
2+
3+ import android.app.Application
4+ import android.content.res.Resources
5+ import androidx.annotation.StringRes
6+ import androidx.compose.ui.semantics.Role
7+ import androidx.compose.ui.semantics.SemanticsProperties
8+ import androidx.compose.ui.test.*
9+ import androidx.compose.ui.test.junit4.ComposeContentTestRule
10+ import androidx.compose.ui.test.junit4.createAndroidComposeRule
11+ import androidx.test.core.app.ApplicationProvider
12+ import androidx.test.rule.GrantPermissionRule
13+ import org.junit.Rule
14+ import org.junit.Test
15+ import kotlin.time.Duration
16+ import kotlin.time.Duration.Companion.seconds
17+
18+
19+ class SmokeTestUiTest {
20+
21+ @get:Rule
22+ val permissionsRule = GrantPermissionRule .grant(
23+ android.Manifest .permission.POST_NOTIFICATIONS ,
24+ android.Manifest .permission.ACCESS_FINE_LOCATION ,
25+ android.Manifest .permission.CAMERA
26+ )
27+
28+ @get:Rule
29+ val composeTestRule = createAndroidComposeRule<MainActivity >()
30+
31+ @Test
32+ fun smokeTest () {
33+ composeTestRule.apply {
34+ onNodeWithText(str(R .string.intro_next)).performClick()
35+ onNodeWithText(str(R .string.intro_slide1_title)).assertIsDisplayed()
36+
37+ onNodeWithText(str(R .string.intro_next)).performClick()
38+ onNodeWithText(str(R .string.intro_slide2_title)).assertIsDisplayed()
39+
40+ onNodeWithText(str(R .string.intro_skip)).performClick()
41+ onNodeWithText(str(R .string.security_intro_supported_security_label)).assertIsDisplayed()
42+
43+ onNodeWithText(str(R .string.intro_next)).performClick()
44+ onNodeWithText(str(R .string.pin_creation_title)).assertIsDisplayed()
45+
46+ setPinFields(" 3133734" , " 313373" )
47+ onNodeWithText(str(R .string.pin_creation_button)).performClick()
48+ waitForText(R .string.pin_creation_error)
49+
50+ setPinFields(" 123456" , " 123456" )
51+ onNodeWithText(str(R .string.pin_creation_button)).performClick()
52+ waitForText(R .string.pin_creation_error_weak_pin)
53+
54+ setPinFields(" 313373" , " 313373" )
55+ onNodeWithText(str(R .string.pin_creation_button)).performClick()
56+
57+ waitForText(R .string.pin_creating_vault)
58+
59+ composeTestRule.waitUntil(
60+ timeoutMillis = 30 .seconds.inWholeMilliseconds
61+ ) {
62+ composeTestRule
63+ .onAllNodes(hasRole(Role .Button ) and hasContentDescription(str(R .string.camera_shutter_button_desc)))
64+ .fetchSemanticsNodes().isNotEmpty()
65+ }
66+
67+ onNode(
68+ hasRole(Role .Button ) and hasContentDescription(str(R .string.camera_shutter_button_desc))
69+ ).assertExists()
70+ }
71+ }
72+
73+ private fun ComposeContentTestRule.setPinFields (primary : String , confirm : String ) {
74+ setTextField(
75+ placeholder = R .string.pin_creation_hint,
76+ value = primary,
77+ )
78+
79+ setTextField(
80+ placeholder = R .string.pin_creation_confirm_hint,
81+ value = confirm,
82+ )
83+ }
84+
85+ fun hasRole (role : Role ): SemanticsMatcher =
86+ SemanticsMatcher .expectValue(SemanticsProperties .Role , role)
87+
88+ private fun str (@StringRes id : Int ): String = r.getString(id)
89+ private val r: Resources
90+ get() {
91+ val application = ApplicationProvider .getApplicationContext<Application >()
92+ return application.resources
93+ }
94+
95+ private fun ComposeContentTestRule.waitForText (@StringRes text : Int , timeout : Duration = 10.seconds) {
96+ waitForText(str(text), timeout)
97+ }
98+
99+ fun ComposeContentTestRule.waitForText (
100+ text : String ,
101+ timeout : Duration = 10.seconds,
102+ useUnmergedTree : Boolean = true,
103+ substring : Boolean = true
104+ ) {
105+ waitUntil(timeout.inWholeMilliseconds) {
106+ onAllNodes(
107+ hasText(text, substring = substring),
108+ useUnmergedTree = useUnmergedTree
109+ ).fetchSemanticsNodes().isNotEmpty()
110+ }
111+ onNodeWithText(text, substring = substring)
112+ .assertIsDisplayed()
113+ }
114+
115+ private fun ComposeContentTestRule.setTextField (value : String , placeholder : Int ) {
116+ onNode(
117+ hasSetTextAction() and hasTextExactly(
118+ str(placeholder),
119+ includeEditableText = false
120+ )
121+ ).apply {
122+ performTextClearance()
123+ performTextInput(value)
124+ }
125+ }
126+ }
0 commit comments