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()` 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() @Before fun setUp() { val context = ApplicationProvider.getApplicationContext() 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 flow.value } catch (t: Throwable) { false } } }