11package com.darkrockstudios.app.securecamera
22
33import android.Manifest
4- import android.app.Application
5- import android.content.res.Resources
64import android.os.Build
7- import androidx.annotation.StringRes
85import androidx.compose.ui.semantics.Role
9- import androidx.compose.ui.semantics.SemanticsProperties
10- import androidx.compose.ui.test.SemanticsMatcher
116import androidx.compose.ui.test.assertIsDisplayed
127import androidx.compose.ui.test.hasContentDescription
13- import androidx.compose.ui.test.hasSetTextAction
148import androidx.compose.ui.test.hasTestTag
15- import androidx.compose.ui.test.hasText
16- import androidx.compose.ui.test.hasTextExactly
179import androidx.compose.ui.test.junit4.ComposeContentTestRule
1810import androidx.compose.ui.test.junit4.createAndroidComposeRule
19- import androidx.compose.ui.test.onNodeWithContentDescription
2011import androidx.compose.ui.test.onNodeWithText
2112import androidx.compose.ui.test.performClick
22- import androidx.compose.ui.test.performTextClearance
23- import androidx.compose.ui.test.performTextInput
24- import androidx.test.core.app.ApplicationProvider
2513import androidx.test.rule.GrantPermissionRule
2614import org.junit.Rule
2715import org.junit.Test
28- import kotlin.time.Duration
29- import kotlin.time.Duration.Companion.seconds
3016
3117
3218class SmokeTestUiTest {
@@ -77,19 +63,20 @@ class SmokeTestUiTest {
7763
7864 waitForTextEitherTree(str(R .string.pin_creating_vault), assertDisplayed = false )
7965
80- waitForButton( str(R .string.camera_shutter_button_desc))
66+ waitForEitherTree(hasRole( Role . Button ) and hasContentDescription( str(R .string.camera_shutter_button_desc) ))
8167
8268 onNode(
8369 hasRole(Role .Button ) and hasContentDescription(str(R .string.camera_shutter_button_desc))
8470 ).performClick()
8571
86- waitForContentDescriptionSimple( str(R .string.camera_more_options_content_description))
72+ waitForEitherTree(hasContentDescription( str(R .string.camera_more_options_content_description) ))
8773
8874 onNode(
8975 hasRole(Role .Button ) and hasContentDescription(str(R .string.camera_more_options_content_description))
9076 ).performClick()
9177
92- waitForTestTagSimple(" flash-switch" )
78+ waitForEitherTree(hasTestTag(" flash-switch" ))
79+
9380 onNode(
9481 hasRole(Role .Switch ) and hasTestTag(" flash-switch" )
9582 ).performClick()
@@ -100,50 +87,6 @@ class SmokeTestUiTest {
10087 }
10188 }
10289
103- private fun waitForButton (contentDescription : String ) {
104- composeTestRule.waitUntil(
105- timeoutMillis = 5 .seconds.inWholeMilliseconds
106- ) {
107- composeTestRule
108- .onAllNodes(hasRole(Role .Button ) and hasContentDescription(contentDescription))
109- .fetchSemanticsNodes().isNotEmpty()
110- }
111- }
112-
113- private fun waitForTextSimple (@StringRes id : Int ) {
114- waitForTextSimple(str(id))
115- }
116-
117- private fun waitForTextSimple (text : String ) {
118- composeTestRule.waitUntil(
119- timeoutMillis = 5 .seconds.inWholeMilliseconds
120- ) {
121- composeTestRule
122- .onAllNodes(hasText(text))
123- .fetchSemanticsNodes().isNotEmpty()
124- }
125- }
126-
127- private fun waitForContentDescriptionSimple (contentDescription : String ) {
128- composeTestRule.waitUntil(
129- timeoutMillis = 5 .seconds.inWholeMilliseconds
130- ) {
131- composeTestRule
132- .onAllNodes(hasContentDescription(contentDescription))
133- .fetchSemanticsNodes().isNotEmpty()
134- }
135- }
136-
137- private fun waitForTestTagSimple (testTag : String ) {
138- composeTestRule.waitUntil(
139- timeoutMillis = 5 .seconds.inWholeMilliseconds
140- ) {
141- composeTestRule
142- .onAllNodes(hasTestTag(testTag))
143- .fetchSemanticsNodes().isNotEmpty()
144- }
145- }
146-
14790 private fun ComposeContentTestRule.setPinFields (primary : String , confirm : String ) {
14891 setTextField(
14992 placeholder = R .string.pin_creation_hint,
@@ -155,118 +98,4 @@ class SmokeTestUiTest {
15598 value = confirm,
15699 )
157100 }
158-
159- fun hasRole (role : Role ): SemanticsMatcher =
160- SemanticsMatcher .expectValue(SemanticsProperties .Role , role)
161-
162- private fun str (@StringRes id : Int ): String = r.getString(id)
163- private val r: Resources
164- get() {
165- val application = ApplicationProvider .getApplicationContext<Application >()
166- return application.resources
167- }
168-
169- private fun ComposeContentTestRule.waitForText (
170- @StringRes text : Int ,
171- timeout : Duration = 10.seconds
172- ) {
173- this @waitForText.waitForText(str(text), timeout)
174- }
175-
176- fun ComposeContentTestRule.waitForText (
177- text : String ,
178- timeout : Duration = 10.seconds,
179- useUnmergedTree : Boolean = true,
180- substring : Boolean = true,
181- assertDisplayed : Boolean = true
182- ) {
183- waitUntil(timeout.inWholeMilliseconds) {
184- onAllNodes(
185- hasText(text, substring = substring),
186- useUnmergedTree = useUnmergedTree
187- ).fetchSemanticsNodes().isNotEmpty()
188- }
189- val node = onNode(
190- hasText(text, substring = substring),
191- useUnmergedTree = useUnmergedTree
192- )
193- if (assertDisplayed) node.assertIsDisplayed() else node.assertExists()
194- }
195-
196- fun ComposeContentTestRule.waitForTextEitherTree (
197- text : String ,
198- timeout : Duration = 10.seconds,
199- substring : Boolean = true,
200- ignoreCase : Boolean = false,
201- assertDisplayed : Boolean = true,
202- preferUnmergedFirst : Boolean = true
203- ) {
204- fun hasAny (useUnmerged : Boolean ) = onAllNodes(
205- hasText(text, substring = substring, ignoreCase = ignoreCase),
206- useUnmergedTree = useUnmerged
207- ).fetchSemanticsNodes().isNotEmpty()
208-
209- val order = if (preferUnmergedFirst) listOf (true , false ) else listOf (false , true )
210-
211- waitUntil(timeout.inWholeMilliseconds) {
212- hasAny(order[0 ]) || hasAny(order[1 ])
213- }
214-
215- // Pick the tree that actually has the node
216- val chosenUnmerged = if (hasAny(order[0 ])) order[0 ] else order[1 ]
217-
218- val node = onNode(
219- hasText(text, substring = substring, ignoreCase = ignoreCase),
220- useUnmergedTree = chosenUnmerged
221- )
222- if (assertDisplayed) node.assertIsDisplayed() else node.assertExists()
223- }
224-
225- fun ComposeContentTestRule.waitForTextEitherTree (
226- @StringRes resId : Int ,
227- timeout : Duration = 10.seconds,
228- substring : Boolean = true,
229- ignoreCase : Boolean = false,
230- assertDisplayed : Boolean = true,
231- preferUnmergedFirst : Boolean = true
232- ) {
233- val str = androidx.test.platform.app.InstrumentationRegistry
234- .getInstrumentation().targetContext.getString(resId)
235- waitForTextEitherTree(
236- text = str,
237- timeout = timeout,
238- substring = substring,
239- ignoreCase = ignoreCase,
240- assertDisplayed = assertDisplayed,
241- preferUnmergedFirst = preferUnmergedFirst
242- )
243- }
244-
245- fun ComposeContentTestRule.waitForContentDescription (
246- text : String ,
247- timeout : Duration = 10.seconds,
248- useUnmergedTree : Boolean = true,
249- substring : Boolean = true
250- ) {
251- waitUntil(timeout.inWholeMilliseconds) {
252- onAllNodes(
253- hasText(text, substring = substring),
254- useUnmergedTree = useUnmergedTree
255- ).fetchSemanticsNodes().isNotEmpty()
256- }
257- onNodeWithContentDescription(text, substring = substring)
258- .assertIsDisplayed()
259- }
260-
261- private fun ComposeContentTestRule.setTextField (value : String , placeholder : Int ) {
262- onNode(
263- hasSetTextAction() and hasTextExactly(
264- str(placeholder),
265- includeEditableText = false
266- )
267- ).apply {
268- performTextClearance()
269- performTextInput(value)
270- }
271- }
272101}
0 commit comments