package com.tt.honeyDue.ui import androidx.compose.ui.test.SemanticsNodeInteraction import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.junit4.ComposeTestRule import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onNodeWithText /** * Base class for Android Compose UI test page objects. * * Mirrors `iosApp/HoneyDueUITests/PageObjects/BaseScreen.swift`: provides * condition-based waits so screen objects can interact with Compose nodes * without reaching for ad-hoc `Thread.sleep` calls. */ abstract class BaseScreen(protected val rule: ComposeTestRule) { /** Returns a node interaction for the given test tag (unmerged tree for testability). */ protected fun tag(testTag: String): SemanticsNodeInteraction = rule.onNodeWithTag(testTag, useUnmergedTree = true) /** Returns a node interaction for the given display text. */ protected fun text(value: String): SemanticsNodeInteraction = rule.onNodeWithText(value, useUnmergedTree = true) /** Waits until a node with [testTag] exists in the semantics tree. */ protected fun waitFor(testTag: String, timeoutMs: Long = DEFAULT_TIMEOUT_MS) { rule.waitUntil(timeoutMs) { try { tag(testTag).assertExists() true } catch (e: AssertionError) { false } } } /** Waits until a node with the given visible [value] text exists. */ protected fun waitForText(value: String, timeoutMs: Long = DEFAULT_TIMEOUT_MS) { rule.waitUntil(timeoutMs) { try { text(value).assertExists() true } catch (e: AssertionError) { false } } } /** Waits until a node with [testTag] is actually displayed (not just present). */ protected fun waitForDisplayed(testTag: String, timeoutMs: Long = DEFAULT_TIMEOUT_MS) { rule.waitUntil(timeoutMs) { try { tag(testTag).assertIsDisplayed() true } catch (e: AssertionError) { false } } } /** Non-throwing existence check. */ protected fun exists(testTag: String): Boolean = try { tag(testTag).assertExists() true } catch (e: AssertionError) { false } /** Non-throwing text existence check. */ protected fun textExists(value: String): Boolean = try { text(value).assertExists() true } catch (e: AssertionError) { false } /** Subclasses report whether their screen is currently visible. */ abstract fun isDisplayed(): Boolean companion object { const val DEFAULT_TIMEOUT_MS: Long = 10_000L const val SHORT_TIMEOUT_MS: Long = 5_000L } }