Skip to content

Commit 46618ff

Browse files
committed
CI tests
??? ??? ??? ??? Refactored SmokeTestUiTest ??? ??? ??? ??? ??? Test Disable Instrumentation Tests I don't know, I can't get it to pass on CI
1 parent 97c8cf8 commit 46618ff

File tree

2 files changed

+105
-91
lines changed

2 files changed

+105
-91
lines changed

.github/workflows/build.yml

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ on:
99
jobs:
1010
build:
1111
runs-on: ubuntu-latest
12+
strategy:
13+
matrix:
14+
api-level: [ 34 ]
1215

1316
steps:
1417
- uses: actions/checkout@v4
@@ -34,22 +37,49 @@ jobs:
3437
- name: Run Unit Tests
3538
run: ./gradlew test
3639

37-
# This is not working on GitHub yet
38-
# - name: Enable KVM group perms
39-
# run: |
40-
# echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' \
41-
# | sudo tee /etc/udev/rules.d/99-kvm4all.rules
42-
# sudo udevadm control --reload-rules
43-
# sudo udevadm trigger --name-match=kvm
44-
#
45-
# - name: Run instrumentation tests
46-
# uses: reactivecircus/android-emulator-runner@v2
47-
# with:
48-
# api-level: 34
49-
# target: google_apis
50-
# arch: x86_64
51-
# profile: pixel_5
52-
# emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim
53-
# disable-animations: true
54-
# emulator-boot-timeout: 600
55-
# script: ./gradlew connectedCheck
40+
# - name: Enable KVM
41+
# run: |
42+
# echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
43+
# sudo udevadm control --reload-rules
44+
# sudo udevadm trigger --name-match=kvm
45+
#
46+
# - name: AVD cache
47+
# uses: actions/cache@v4
48+
# id: avd-cache
49+
# with:
50+
# path: |
51+
# ~/.android/avd/*
52+
# ~/.android/adb*
53+
# key: avd-${{ matrix.api-level }}
54+
#
55+
# - name: create AVD and generate snapshot for caching
56+
# if: steps.avd-cache.outputs.cache-hit != 'true'
57+
# uses: reactivecircus/android-emulator-runner@v2
58+
# with:
59+
# api-level: ${{ matrix.api-level }}
60+
# arch: x86_64
61+
# target: default
62+
# force-avd-creation: false
63+
# disable-animations: false
64+
# script: echo "Generated AVD snapshot for caching."
65+
#
66+
# - name: Run Instrumentation Tests
67+
# uses: reactivecircus/android-emulator-runner@v2
68+
# with:
69+
# api-level: ${{ matrix.api-level }}
70+
# arch: x86_64
71+
# target: default
72+
# force-avd-creation: false
73+
# emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-front emulated -camera-back emulated
74+
# disable-animations: true
75+
# script: |
76+
# adb wait-for-device
77+
# adb shell input keyevent 82
78+
# ./gradlew connectedOssDebugAndroidTest --continue
79+
80+
- name: Upload Test Reports
81+
if: failure()
82+
uses: actions/upload-artifact@v4
83+
with:
84+
name: android-test-report
85+
path: '**/build/reports/'

app/src/androidTest/kotlin/com/darkrockstudios/app/securecamera/SmokeTestUiTest.kt

Lines changed: 56 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,14 @@ import android.content.res.Resources
55
import androidx.annotation.StringRes
66
import androidx.compose.ui.semantics.Role
77
import androidx.compose.ui.semantics.SemanticsProperties
8-
import androidx.compose.ui.test.SemanticsMatcher
9-
import androidx.compose.ui.test.assertIsDisplayed
10-
import androidx.compose.ui.test.hasContentDescription
11-
import androidx.compose.ui.test.hasSetTextAction
12-
import androidx.compose.ui.test.hasTextExactly
8+
import androidx.compose.ui.test.*
9+
import androidx.compose.ui.test.junit4.ComposeContentTestRule
1310
import androidx.compose.ui.test.junit4.createAndroidComposeRule
14-
import androidx.compose.ui.test.onNodeWithText
15-
import androidx.compose.ui.test.performClick
16-
import androidx.compose.ui.test.performTextClearance
17-
import androidx.compose.ui.test.performTextInput
1811
import androidx.test.core.app.ApplicationProvider
1912
import androidx.test.rule.GrantPermissionRule
20-
import kotlinx.coroutines.test.runTest
2113
import org.junit.Rule
2214
import org.junit.Test
15+
import kotlin.time.Duration
2316
import kotlin.time.Duration.Companion.seconds
2417

2518

@@ -36,7 +29,7 @@ class SmokeTestUiTest {
3629
val composeTestRule = createAndroidComposeRule<MainActivity>()
3730

3831
@Test
39-
fun smokeTest() = runTest {
32+
fun smokeTest() {
4033
composeTestRule.apply {
4134
onNodeWithText(str(R.string.intro_next)).performClick()
4235
onNodeWithText(str(R.string.intro_slide1_title)).assertIsDisplayed()
@@ -50,74 +43,21 @@ class SmokeTestUiTest {
5043
onNodeWithText(str(R.string.intro_next)).performClick()
5144
onNodeWithText(str(R.string.pin_creation_title)).assertIsDisplayed()
5245

53-
onNode(
54-
hasSetTextAction() and hasTextExactly(
55-
str(R.string.pin_creation_hint),
56-
includeEditableText = false
57-
)
58-
).performTextInput("3133734")
59-
60-
onNode(
61-
hasSetTextAction() and hasTextExactly(
62-
str(R.string.pin_creation_confirm_hint),
63-
includeEditableText = false
64-
)
65-
).performTextInput("313373")
66-
46+
setPinFields("3133734", "313373")
6747
onNodeWithText(str(R.string.pin_creation_button)).performClick()
48+
waitForText(R.string.pin_creation_error)
6849

69-
onNodeWithText(str(R.string.pin_creation_error)).assertIsDisplayed()
70-
71-
onNode(
72-
hasSetTextAction() and hasTextExactly(
73-
str(R.string.pin_creation_hint),
74-
includeEditableText = false
75-
)
76-
).apply {
77-
performTextClearance()
78-
performTextInput("123456")
79-
}
80-
81-
onNode(
82-
hasSetTextAction() and hasTextExactly(
83-
str(R.string.pin_creation_confirm_hint),
84-
includeEditableText = false
85-
)
86-
).apply {
87-
performTextClearance()
88-
performTextInput("123456")
89-
}
90-
50+
setPinFields("123456", "123456")
9151
onNodeWithText(str(R.string.pin_creation_button)).performClick()
52+
waitForText(R.string.pin_creation_error_weak_pin)
9253

93-
onNodeWithText(str(R.string.pin_creation_error_weak_pin)).assertIsDisplayed()
94-
95-
onNode(
96-
hasSetTextAction() and hasTextExactly(
97-
str(R.string.pin_creation_hint),
98-
includeEditableText = false
99-
)
100-
).apply {
101-
performTextClearance()
102-
performTextInput("313373")
103-
}
104-
105-
onNode(
106-
hasSetTextAction() and hasTextExactly(
107-
str(R.string.pin_creation_confirm_hint),
108-
includeEditableText = false
109-
)
110-
).apply {
111-
performTextClearance()
112-
performTextInput("313373")
113-
}
114-
54+
setPinFields("313373", "313373")
11555
onNodeWithText(str(R.string.pin_creation_button)).performClick()
11656

117-
onNodeWithText(str(R.string.pin_creating_vault)).assertIsDisplayed()
57+
waitForText(R.string.pin_creating_vault)
11858

11959
composeTestRule.waitUntil(
120-
timeoutMillis = 10.seconds.inWholeMilliseconds
60+
timeoutMillis = 30.seconds.inWholeMilliseconds
12161
) {
12262
composeTestRule
12363
.onAllNodes(hasRole(Role.Button) and hasContentDescription(str(R.string.camera_shutter_button_desc)))
@@ -130,13 +70,57 @@ class SmokeTestUiTest {
13070
}
13171
}
13272

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+
13385
fun hasRole(role: Role): SemanticsMatcher =
13486
SemanticsMatcher.expectValue(SemanticsProperties.Role, role)
13587

13688
private fun str(@StringRes id: Int): String = r.getString(id)
13789
private val r: Resources
13890
get() {
139-
val application = ApplicationProvider.getApplicationContext<Application?>()
91+
val application = ApplicationProvider.getApplicationContext<Application>()
14092
return application.resources
14193
}
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+
}
142126
}

0 commit comments

Comments
 (0)