fix(#298): internationalize ConnectViewModel strings, fix null-assert crash on profile selector (#307)
* fix(#298): internationalize ConnectViewModel strings, fix null-assert crash on profile selector E1: Add all connect error resources to strings.xml for i18n readiness E2: Migrate ConnectViewModel to AndroidViewModel, replace all hardcoded user-facing strings with getString(R.string.*) calls F1: Replace state.selectedProfile!! with .?.let { } pattern in ConnectScreen.kt to eliminate NPE risk on mutable state copy Closes #298 * fix(#298): update test files for AndroidViewModel constructor Update ConnectViewModelTest.kt and E2eIntegrationTest.kt to pass mock Application to the new ConnectViewModel(app) constructor. Add getString() MockK stubs matching the string resource keys. * fix(#298): add missing LocalContext import and restore connect_pairing_string Two compilation errors: - ConnectScreen.kt was missing import for LocalContext - strings.xml was missing connect_pairing_string resource (accidentally removed in earlier patch) * fix(#298): extract ViewModelFactory to avoid composable-in-non-composable error LocalContext.current cannot be called inside a viewModel { } factory lambda because the lambda is not @Composable. Fix by extracting a ConnectViewModelFactory class and using run { } to capture the Application value at the composable call site before passing to the factory constructor. * fix(#298): fix MockK varargs matching in test stubs getString(int, Object...) takes varargs. MockK's any<Int>() and any<String>() didn't match the vararg Object... slot. Changed to any() (untyped) which matches correctly. * fix(#298): fix MockK answers — arg indexing was wrong In getString(int, Object...), firstArg is the resource ID, secondArg is the format argument. Using firstArg<Int>() in the answers block was returning the res ID, not 500/etc. Changed to secondArg<Any>(). * fix(#298): replace getString(int,Object...) with String.format(getString(int),...) Avoid MockK varargs matching issues by calling app.getString(int) for the format template and String.format() to apply args. Simplifies test stubs to pure getString(int) returns. --------- Co-authored-by: M57 <hy4ri@users.noreply.github.com>
This commit is contained in:
1 parent
8e040543de
commit
e8025efcde
5 files changed
+156
-57
No files matched your search
@@ -1,5 +1,6 @@
|
||||
package com.m57.hermescontrol
|
||||
|
||||
import android.app.Application
|
||||
import androidx.navigation3.runtime.NavBackStack
|
||||
import androidx.navigation3.runtime.NavKey
|
||||
import com.m57.hermescontrol.data.local.AuthManager
|
||||
@@ -56,6 +57,7 @@ import java.io.IOException
|
||||
class E2eIntegrationTest {
|
||||
private val testDispatcher = StandardTestDispatcher()
|
||||
private lateinit var mockApiService: HermesApiService
|
||||
private val mockApp = mockk<Application>(relaxed = true)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
@@ -85,6 +87,9 @@ class E2eIntegrationTest {
|
||||
every { AuthManager.getProfileToken(any()) } returns null
|
||||
every { AuthManager.setProfileToken(any(), any()) } returns Unit
|
||||
every { AuthManager.saveConnectionProfiles(any()) } returns Unit
|
||||
|
||||
// Application stubs
|
||||
every { mockApp.getString(R.string.connect_error_401) } returns "Invalid token (401 Unauthorized)"
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -760,7 +765,7 @@ class E2eIntegrationTest {
|
||||
val mockResponse = createErrorResponse<StatusResponse>(401)
|
||||
coEvery { mockApiService.getStatus() } returns mockResponse
|
||||
|
||||
val viewModel = ConnectViewModel()
|
||||
val viewModel = ConnectViewModel(mockApp)
|
||||
viewModel.onTokenChange("expired-token")
|
||||
viewModel.connect()
|
||||
advanceUntilIdle()
|
||||
@@ -781,7 +786,7 @@ class E2eIntegrationTest {
|
||||
val statusResponse = mockk<StatusResponse>()
|
||||
coEvery { mockApiService.getStatus() } returns Response.success(statusResponse)
|
||||
|
||||
val connectViewModel = ConnectViewModel()
|
||||
val connectViewModel = ConnectViewModel(mockApp)
|
||||
connectViewModel.onTokenChange("valid-token")
|
||||
connectViewModel.onHostChange("127.0.0.1")
|
||||
connectViewModel.onPortChange("9119")
|
||||
@@ -1069,7 +1074,7 @@ class E2eIntegrationTest {
|
||||
val statusResponse = mockk<StatusResponse>()
|
||||
coEvery { mockApiService.getStatus() } returns Response.success(statusResponse)
|
||||
|
||||
val viewModel = ConnectViewModel()
|
||||
val viewModel = ConnectViewModel(mockApp)
|
||||
viewModel.onPairingString("hermes://connect?host=192.168.1.5&port=9119&token=TEST_TOKEN")
|
||||
advanceUntilIdle()
|
||||
|
||||
@@ -1095,7 +1100,7 @@ class E2eIntegrationTest {
|
||||
val statusResponse = mockk<StatusResponse>()
|
||||
coEvery { mockApiService.getStatus() } returns Response.success(statusResponse)
|
||||
|
||||
val viewModel = ConnectViewModel()
|
||||
val viewModel = ConnectViewModel(mockApp)
|
||||
viewModel.onPairingString(base64Str)
|
||||
advanceUntilIdle()
|
||||
|
||||
|
||||
Reference in new issue
Block a user