Ports iOS Suite1_RegistrationTests.swift + SimpleLoginTest.swift to Android Compose UI Test. Adds testTag annotations on auth screens using shared AccessibilityIds.Authentication constants. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
105 lines
3.7 KiB
Kotlin
105 lines
3.7 KiB
Kotlin
package com.tt.honeyDue
|
|
|
|
import android.content.Context
|
|
import androidx.compose.ui.test.assertIsDisplayed
|
|
import androidx.compose.ui.test.junit4.createAndroidComposeRule
|
|
import androidx.compose.ui.test.onNodeWithTag
|
|
import androidx.compose.ui.test.performTextInput
|
|
import androidx.test.core.app.ApplicationProvider
|
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
|
import com.tt.honeyDue.data.DataManager
|
|
import com.tt.honeyDue.data.PersistenceManager
|
|
import com.tt.honeyDue.storage.TaskCacheManager
|
|
import com.tt.honeyDue.storage.TaskCacheStorage
|
|
import com.tt.honeyDue.storage.ThemeStorageManager
|
|
import com.tt.honeyDue.storage.TokenManager
|
|
import com.tt.honeyDue.testing.AccessibilityIds
|
|
import org.junit.After
|
|
import org.junit.Before
|
|
import org.junit.Rule
|
|
import org.junit.Test
|
|
import org.junit.runner.RunWith
|
|
|
|
/**
|
|
* Android port of `iosApp/HoneyDueUITests/SimpleLoginTest.swift` — a smoke
|
|
* test suite that verifies the app launches and surfaces a usable login
|
|
* screen. Merged into one test (`testAppLaunchesAndShowsLoginScreen`) because
|
|
* `createAndroidComposeRule<MainActivity>()` launches a fresh activity per
|
|
* test anyway, and the two iOS tests exercise the exact same semantic
|
|
* contract.
|
|
*/
|
|
@RunWith(AndroidJUnit4::class)
|
|
class SimpleLoginTest {
|
|
|
|
@get:Rule
|
|
val composeRule = createAndroidComposeRule<MainActivity>()
|
|
|
|
@Before
|
|
fun setUp() {
|
|
val context = ApplicationProvider.getApplicationContext<Context>()
|
|
if (!isDataManagerInitialized()) {
|
|
DataManager.initialize(
|
|
tokenMgr = TokenManager.getInstance(context),
|
|
themeMgr = ThemeStorageManager.getInstance(context),
|
|
persistenceMgr = PersistenceManager.getInstance(context),
|
|
)
|
|
}
|
|
TaskCacheStorage.initialize(TaskCacheManager.getInstance(context))
|
|
|
|
// CRITICAL: mirror iOS `ensureLoggedOut()` — UITestHelpers handles both
|
|
// the already-logged-in and mid-onboarding cases.
|
|
UITestHelpers.ensureOnLoginScreen(composeRule)
|
|
}
|
|
|
|
@After
|
|
fun tearDown() {
|
|
UITestHelpers.tearDown(composeRule)
|
|
}
|
|
|
|
/**
|
|
* iOS: `testAppLaunchesAndShowsLoginScreen` + `testCanTypeInLoginFields`.
|
|
*
|
|
* Verifies the login screen elements exist AND that the username/password
|
|
* fields accept text input (the minimum contract for SimpleLoginTest).
|
|
*/
|
|
@Test
|
|
fun testAppLaunchesAndShowsLoginScreen() {
|
|
// App launches and username field is reachable.
|
|
composeRule.onNodeWithTag(
|
|
AccessibilityIds.Authentication.usernameField,
|
|
useUnmergedTree = true,
|
|
).assertIsDisplayed()
|
|
|
|
// Can type into username & password fields.
|
|
composeRule.onNodeWithTag(
|
|
AccessibilityIds.Authentication.usernameField,
|
|
useUnmergedTree = true,
|
|
).performTextInput("testuser")
|
|
|
|
composeRule.onNodeWithTag(
|
|
AccessibilityIds.Authentication.passwordField,
|
|
useUnmergedTree = true,
|
|
).performTextInput("testpass123")
|
|
|
|
// Login button should be displayed (and, because both fields are
|
|
// populated, also enabled — we don't tap it here to avoid a real API
|
|
// call from a smoke test).
|
|
composeRule.onNodeWithTag(
|
|
AccessibilityIds.Authentication.loginButton,
|
|
useUnmergedTree = true,
|
|
).assertIsDisplayed()
|
|
}
|
|
|
|
private fun isDataManagerInitialized(): Boolean {
|
|
return try {
|
|
val field = DataManager::class.java.getDeclaredField("_isInitialized")
|
|
field.isAccessible = true
|
|
@Suppress("UNCHECKED_CAST")
|
|
val flow = field.get(DataManager) as kotlinx.coroutines.flow.MutableStateFlow<Boolean>
|
|
flow.value
|
|
} catch (t: Throwable) {
|
|
false
|
|
}
|
|
}
|
|
}
|