diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 791c54c..3b590c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,14 +39,14 @@ jobs: - name: Upload test reports if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: test-reports path: android-app/app/build/reports/tests/ retention-days: 7 - name: Upload debug APKs - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: debug-apks path: android-app/app/build/outputs/apk/*/debug/*.apk diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ed20a94..a2a82b6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -77,11 +77,12 @@ jobs: run: rm -f "$RUNNER_TEMP/release.jks" - name: Publish GitHub release - uses: softprops/action-gh-release@v2 - with: - name: ${{ steps.version.outputs.name }} - generate_release_notes: true - fail_on_unmatched_files: true - files: | - android-app/dist/*.apk - android-app/dist/SHA256SUMS + env: + GH_TOKEN: ${{ github.token }} + VERSION: ${{ steps.version.outputs.name }} + run: | + gh release create "$GITHUB_REF_NAME" \ + --title "$VERSION" \ + --generate-notes \ + --verify-tag \ + dist/*.apk dist/SHA256SUMS diff --git a/android-app/app/src/test/kotlin/dev/hho/android/ui/receiving/ReceivingViewModelTest.kt b/android-app/app/src/test/kotlin/dev/hho/android/ui/receiving/ReceivingViewModelTest.kt index 72d5bb2..4e75083 100644 --- a/android-app/app/src/test/kotlin/dev/hho/android/ui/receiving/ReceivingViewModelTest.kt +++ b/android-app/app/src/test/kotlin/dev/hho/android/ui/receiving/ReceivingViewModelTest.kt @@ -215,7 +215,7 @@ class ReceivingViewModelTest { vm.dismissUnexpected() await { sessionState()!!.pendingUnexpected == null } assertTrue(sessionState()!!.lines.isEmpty()) - assertFalse(vm.paused) + await("analysis resumes") { !vm.paused } } @Test fun noMatchShowsMessageAndWritesNothing() { @@ -246,6 +246,7 @@ class ReceivingViewModelTest { vm.setScanning(true) scan("111") await { line("drill")?.discrepancy?.receivedQty == 1 } + await("first resolve finishes") { !vm.paused } clock += 1_000 vm.onBarcodes(code("111")) assertFalse("a repeat in the suppression window starts no resolve", vm.paused) diff --git a/android-app/app/src/test/kotlin/dev/hho/android/ui/scan/ScanViewModelTest.kt b/android-app/app/src/test/kotlin/dev/hho/android/ui/scan/ScanViewModelTest.kt index 498e87f..a2bdf0d 100644 --- a/android-app/app/src/test/kotlin/dev/hho/android/ui/scan/ScanViewModelTest.kt +++ b/android-app/app/src/test/kotlin/dev/hho/android/ui/scan/ScanViewModelTest.kt @@ -1,5 +1,6 @@ package dev.hho.android.ui.scan +import androidx.lifecycle.viewModelScope import androidx.test.ext.junit.runners.AndroidJUnit4 import dev.hho.android.data.items.ItemSearch import dev.hho.android.data.room.HhoDatabase @@ -17,6 +18,7 @@ import dev.hho.android.ui.items.ViewModelTracker import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.first +import kotlinx.coroutines.job import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.setMain @@ -40,7 +42,11 @@ class ScanViewModelTest { private val viewModels = ViewModelTracker() private fun awaitSheet(): ScanUiState.Sheet = kotlinx.coroutines.runBlocking { - kotlinx.coroutines.withTimeout(10_000) { vm.uiState.first { it is ScanUiState.Sheet } as ScanUiState.Sheet } + kotlinx.coroutines.withTimeout(10_000) { + val sheet = vm.uiState.first { it is ScanUiState.Sheet } as ScanUiState.Sheet + vm.viewModelScope.coroutineContext.job.children.forEach { it.join() } + sheet + } } private fun code(v: String) = listOf(DecodedBarcode(v, BarcodeFormat.QR_CODE)) diff --git a/android-app/app/src/test/kotlin/dev/hho/android/ui/syncstatus/SyncStatusViewModelTest.kt b/android-app/app/src/test/kotlin/dev/hho/android/ui/syncstatus/SyncStatusViewModelTest.kt index f40182b..bfe2faa 100644 --- a/android-app/app/src/test/kotlin/dev/hho/android/ui/syncstatus/SyncStatusViewModelTest.kt +++ b/android-app/app/src/test/kotlin/dev/hho/android/ui/syncstatus/SyncStatusViewModelTest.kt @@ -1,5 +1,6 @@ package dev.hho.android.ui.syncstatus +import androidx.lifecycle.viewModelScope import androidx.test.ext.junit.runners.AndroidJUnit4 import dev.hho.android.data.room.HhoDatabase import dev.hho.android.data.room.ItemEntity @@ -16,6 +17,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first +import kotlinx.coroutines.job import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.UnconfinedTestDispatcher @@ -65,7 +67,9 @@ class SyncStatusViewModelTest { } @After fun tearDown() { + val job = vm.viewModelScope.coroutineContext.job viewModels.cancelAll() + runBlocking { withTimeout(10_000) { job.join() } } db.close() Dispatchers.resetMain() }