Skip to content

Commit 5d97410

Browse files
authored
Merge pull request #77 from HellBus1/1.3.0
Staging 1.3.0
2 parents c784d9b + 28d7c47 commit 5d97410

65 files changed

Lines changed: 3889 additions & 936 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/android_ci.yml

Lines changed: 86 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,97 @@
1-
name: VentNote Build and Test CI
1+
name: VentNote CI
22

33
on:
4-
pull_request:
4+
push:
55
branches: [ master ]
6+
pull_request:
7+
branches: [ master, staging ]
68

79
jobs:
8-
test:
9-
name: Run Unit Tests
10+
lint-and-unit-test:
11+
name: Lint and Unit Tests
1012
runs-on: ubuntu-latest
11-
1213
steps:
13-
- uses: actions/checkout@v3
14-
- name: Set up JDK 17
15-
uses: actions/setup-java@v3
16-
with:
17-
java-version: '17'
18-
distribution: 'adopt'
19-
cache: gradle
20-
21-
- name: Unit tests
22-
run: ./gradlew test --stacktrace
14+
- uses: actions/checkout@v4
15+
16+
- name: Set up JDK 17
17+
uses: actions/setup-java@v4
18+
with:
19+
java-version: '17'
20+
distribution: 'temurin'
21+
cache: gradle
22+
23+
- name: Run Lint
24+
run: ./gradlew lintDebug --stacktrace
25+
26+
- name: Run Unit Tests
27+
run: ./gradlew testDebugUnitTest --stacktrace
2328

24-
build:
25-
runs-on: ubuntu-latest
26-
permissions:
27-
contents: read
28-
packages: write
29-
30-
steps:
31-
- uses: actions/checkout@v3
32-
- name: Set up JDK 17
33-
uses: actions/setup-java@v3
34-
with:
35-
java-version: '17'
36-
distribution: 'adopt'
37-
cache: gradle
29+
- name: Upload Test Reports
30+
if: always()
31+
uses: actions/upload-artifact@v4
32+
with:
33+
name: lint-and-unit-test-reports
34+
path: |
35+
**/build/reports/lint-results-*.html
36+
**/build/reports/tests/testDebugUnitTest/
3837
39-
- name: Clean project
40-
run: ./gradlew clean --stacktrace
38+
# instrumentation-test:
39+
# name: Instrumentation Tests
40+
# runs-on: macos-latest
41+
# timeout-minutes: 60
42+
# strategy:
43+
# matrix:
44+
# api-level: [34]
45+
# steps:
46+
# - uses: actions/checkout@v4
47+
#
48+
# - name: Set up JDK 17
49+
# uses: actions/setup-java@v4
50+
# with:
51+
# java-version: '17'
52+
# distribution: 'temurin'
53+
# cache: gradle
54+
#
55+
# - name: Run Instrumentation Tests
56+
# uses: reactivecircus/android-emulator-runner@v2
57+
# with:
58+
# api-level: ${{ matrix.api-level }}
59+
# arch: arm64-v8a
60+
# target: google_apis
61+
# force-avd-creation: true
62+
# emulator-options: -no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim
63+
# disable-animations: true
64+
# # Increased RAM for better stability on ARM runners
65+
# disk-size: 4096M
66+
# heap-size: 512M
67+
# script: ./gradlew connectedDebugAndroidTest --stacktrace
68+
#
69+
# - name: Upload Instrumentation Reports
70+
# if: always()
71+
# uses: actions/upload-artifact@v4
72+
# with:
73+
# name: instrumentation-test-reports
74+
# path: app/build/reports/androidTests/connected/
4175

42-
- name: Lint Debug
43-
run: ./gradlew lintDebug --stacktrace
76+
build-check:
77+
name: Build APK Check
78+
runs-on: ubuntu-latest
79+
needs: [lint-and-unit-test]
80+
steps:
81+
- uses: actions/checkout@v4
82+
83+
- name: Set up JDK 17
84+
uses: actions/setup-java@v4
85+
with:
86+
java-version: '17'
87+
distribution: 'temurin'
88+
cache: gradle
4489

45-
- name: Build debug APK
46-
run: ./gradlew build --stacktrace
90+
- name: Build Debug APK
91+
run: ./gradlew assembleDebug --stacktrace
92+
93+
- name: Upload Debug APK
94+
uses: actions/upload-artifact@v4
95+
with:
96+
name: debug-apk
97+
path: app/build/outputs/apk/debug/*.apk
File renamed without changes.
Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
//package com.digiventure.utils
2-
//
3-
//import androidx.test.ext.junit.runners.AndroidJUnit4
4-
//import org.junit.runner.RunWith
5-
//
6-
//@RunWith(AndroidJUnit4::class)
7-
//abstract class BaseAcceptanceTest {
8-
//// @get:Rule(order = 0)
9-
//// val composeTestRule = createComposeRule()
10-
//}
1+
package com.digiventure.utils
2+
3+
import androidx.test.ext.junit.runners.AndroidJUnit4
4+
import org.junit.runner.RunWith
5+
6+
@RunWith(AndroidJUnit4::class)
7+
abstract class BaseAcceptanceTest
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package com.digiventure.ventnote
2+
3+
import android.content.Intent
4+
import androidx.compose.ui.test.*
5+
import androidx.compose.ui.test.junit4.createAndroidComposeRule
6+
import androidx.test.espresso.intent.Intents
7+
import androidx.test.espresso.intent.Intents.intended
8+
import androidx.test.espresso.intent.matcher.IntentMatchers.hasAction
9+
import androidx.test.espresso.intent.matcher.IntentMatchers.hasData
10+
import com.digiventure.utils.BaseAcceptanceTest
11+
import com.digiventure.ventnote.commons.TestTags
12+
import dagger.hilt.android.testing.HiltAndroidRule
13+
import dagger.hilt.android.testing.HiltAndroidTest
14+
import org.hamcrest.Matchers.allOf
15+
import org.junit.After
16+
import org.junit.Before
17+
import org.junit.Rule
18+
import org.junit.Test
19+
20+
@HiltAndroidTest
21+
class NavDrawerFeature : BaseAcceptanceTest() {
22+
23+
@get:Rule(order = 0)
24+
val hiltRule = HiltAndroidRule(this)
25+
26+
@get:Rule(order = 1)
27+
val composeTestRule = createAndroidComposeRule<MainActivity>()
28+
29+
@Before
30+
fun setUp() {
31+
hiltRule.inject()
32+
Intents.init()
33+
34+
// Open the drawer
35+
composeTestRule.onNodeWithTag(TestTags.NOTES_PAGE).assertIsDisplayed()
36+
composeTestRule.onNodeWithTag(TestTags.MENU_ICON_BUTTON).performClick()
37+
composeTestRule.waitForIdle()
38+
composeTestRule.onNodeWithTag(TestTags.NAV_DRAWER, useUnmergedTree = true).assertIsDisplayed()
39+
}
40+
41+
@After
42+
fun tearDown() {
43+
Intents.release()
44+
}
45+
46+
@Test
47+
fun initialState_showsMenuItems() {
48+
composeTestRule.onNodeWithTag(TestTags.RATE_APP_TILE).assertIsDisplayed()
49+
composeTestRule.onNodeWithTag(TestTags.MORE_APPS_TILE).assertIsDisplayed()
50+
composeTestRule.onNodeWithTag(TestTags.APP_VERSION_TILE).assertIsDisplayed()
51+
composeTestRule.onNodeWithTag(TestTags.THEME_TILE).assertIsDisplayed()
52+
composeTestRule.onNodeWithTag(TestTags.COLOR_MODE_TILE).assertIsDisplayed()
53+
composeTestRule.onNodeWithTag(TestTags.BACKUP_TILE).assertIsDisplayed()
54+
}
55+
56+
@Test
57+
fun rateApp_launchesPlayStore() {
58+
composeTestRule.onNodeWithTag(TestTags.RATE_APP_TILE).performClick()
59+
60+
intended(allOf(
61+
hasAction(Intent.ACTION_VIEW),
62+
hasData("https://play.google.com/store/apps/details?id=com.digiventure.ventnote")
63+
))
64+
}
65+
66+
@Test
67+
fun moreApps_launchesDeveloperPage() {
68+
composeTestRule.onNodeWithTag(TestTags.MORE_APPS_TILE).performClick()
69+
70+
intended(allOf(
71+
hasAction(Intent.ACTION_VIEW),
72+
hasData("https://play.google.com/store/apps/developer?id=Mattrmost")
73+
))
74+
}
75+
76+
@Test
77+
fun backupNavigation_navigatesToBackupPage() {
78+
composeTestRule.onNodeWithTag(TestTags.BACKUP_TILE).performClick()
79+
composeTestRule.waitForIdle()
80+
81+
// Use text or tag to verify backup page (usually has "Backup" title in header)
82+
composeTestRule.onNodeWithText("Backup Notes").assertIsDisplayed()
83+
}
84+
85+
@Test
86+
fun themeColorChange_updatesTheme() {
87+
// Verify we can click all theme colors
88+
composeTestRule.onNodeWithTag(TestTags.THEME_COLOR_PURPLE).performClick()
89+
composeTestRule.onNodeWithTag(TestTags.THEME_COLOR_CRIMSON).performClick()
90+
composeTestRule.onNodeWithTag(TestTags.THEME_COLOR_CADMIUM_GREEN).performClick()
91+
composeTestRule.onNodeWithTag(TestTags.THEME_COLOR_COBALT_BLUE).performClick()
92+
93+
// Clicks should not crash and should update internal state (hard to verify without custom matchers)
94+
composeTestRule.onNodeWithTag(TestTags.THEME_TILE).assertIsDisplayed()
95+
}
96+
97+
@Test
98+
fun colorModeToggle_updatesMode() {
99+
// Find the current mode by checking the subtitle text
100+
val lightModeText = "switch to light mode"
101+
val darkModeText = "switch to dark mode"
102+
103+
// Initial click to toggle (assuming default is light mode or whatever)
104+
// We look for either text to be sure
105+
val initialNode = composeTestRule.onNode(
106+
hasText(lightModeText, ignoreCase = true) or hasText(darkModeText, ignoreCase = true)
107+
)
108+
109+
initialNode.assertIsDisplayed()
110+
val isInitiallyLight = try {
111+
composeTestRule.onNodeWithText(darkModeText, ignoreCase = true).assertIsDisplayed()
112+
true // It says "switch to dark", so it is currently light
113+
} catch (_: Throwable) {
114+
false
115+
}
116+
117+
// Toggle
118+
composeTestRule.onNodeWithTag(TestTags.COLOR_MODE_TILE).performClick()
119+
composeTestRule.waitForIdle()
120+
121+
// Verify text swapped
122+
if (isInitiallyLight) {
123+
composeTestRule.onNodeWithText(lightModeText, ignoreCase = true).assertIsDisplayed()
124+
} else {
125+
composeTestRule.onNodeWithText(darkModeText, ignoreCase = true).assertIsDisplayed()
126+
}
127+
}
128+
129+
@Test
130+
fun drawer_canBeClosed() {
131+
// Click outside or use a specific close mechanism if available,
132+
// but here we can just swipe or click the content area if accessible.
133+
// Easiest is to just verify it closes on back press
134+
androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().sendKeyDownUpSync(android.view.KeyEvent.KEYCODE_BACK)
135+
composeTestRule.waitForIdle()
136+
composeTestRule.onNodeWithTag(TestTags.NAV_DRAWER).assertDoesNotExist()
137+
}
138+
}

0 commit comments

Comments
 (0)