From f2632ab5d22462cd523f05c22614b0186bab0043 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Tue, 13 Oct 2026 08:19:57 -0300 Subject: [PATCH 01/11] ci: fix apk output paths in ui tests workflow Co-Authored-By: Claude Opus 5.5 --- .github/workflows/ui-tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index efffd53926..e0811dd540 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -62,8 +62,8 @@ jobs: CHATWOOT_API: ${{ secrets.CHATWOOT_API }} run: | ./gradlew assembleDevDebug assembleDevDebugAndroidTest - ls -la app/build/outputs/apk/debug/ - ls -la app/build/outputs/apk/androidTest/debug/ + ls -la app/build/outputs/apk/dev/debug/ + ls -la app/build/outputs/apk/androidTest/dev/debug/ - name: Enable KVM run: | From 669bf485c4468923672844270625ab8d7770c943 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Tue, 13 Oct 2026 08:45:10 -0300 Subject: [PATCH 02/11] test: align compose ui tests with current tags and buttons Co-Authored-By: Claude Opus 5.5 --- .../screens/wallets/receive/EditInvoiceScreenTest.kt | 3 ++- .../ui/screens/wallets/send/SendAmountContentTest.kt | 7 ++++--- .../widgets/headlines/HeadlinesEditContentTest.kt | 11 +++++------ .../ui/settings/backups/BackupIntroScreenTest.kt | 6 +++--- .../to/bitkit/ui/sheets/BoostTransactionSheetTest.kt | 2 ++ .../bitkit/ui/sheets/NewTransactionSheetViewTest.kt | 9 ++++----- 6 files changed, 20 insertions(+), 18 deletions(-) diff --git a/app/src/androidTest/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreenTest.kt b/app/src/androidTest/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreenTest.kt index 2f228445b6..576fd88746 100644 --- a/app/src/androidTest/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreenTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreenTest.kt @@ -3,6 +3,7 @@ package to.bitkit.ui.screens.wallets.receive import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.assertIsNotEnabled import androidx.compose.ui.test.junit4.v2.createComposeRule +import androidx.compose.ui.test.onChild import androidx.compose.ui.test.onNodeWithTag import kotlinx.collections.immutable.persistentListOf import org.junit.Rule @@ -39,7 +40,7 @@ class EditInvoiceScreenTest { } composeTestRule.onNodeWithTag("PaymentRequestSendButton").assertIsDisplayed() - composeTestRule.onNodeWithTag("PaymentRequestSendButton").assertIsNotEnabled() + composeTestRule.onNodeWithTag("PaymentRequestSendButton").onChild().assertIsNotEnabled() composeTestRule.onNodeWithTag("ShowQrReceive").assertIsDisplayed() } diff --git a/app/src/androidTest/java/to/bitkit/ui/screens/wallets/send/SendAmountContentTest.kt b/app/src/androidTest/java/to/bitkit/ui/screens/wallets/send/SendAmountContentTest.kt index 19ed514f57..2eb7690d56 100644 --- a/app/src/androidTest/java/to/bitkit/ui/screens/wallets/send/SendAmountContentTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/screens/wallets/send/SendAmountContentTest.kt @@ -23,7 +23,8 @@ class SendAmountContentTest { private val uiState = SendUiState( payMethod = SendMethod.LIGHTNING, amount = 100u, - isUnified = true + isUnified = true, + canSwitchFundingSource = true, ) private val nodeLifecycleState = NodeLifecycleState.Running @@ -83,7 +84,7 @@ class SendAmountContentTest { composeTestRule.setContent { SendAmountContent( nodeLifecycleState = nodeLifecycleState, - uiState = uiState, + uiState = uiState.copy(isAmountInputValid = true), amountInputViewModel = previewAmountInputViewModel(), onContinue = { eventTriggered = true } ) @@ -122,7 +123,7 @@ class SendAmountContentTest { ) } - composeTestRule.onNodeWithTag("AssetButton-switch").assertIsNotEnabled() + composeTestRule.onNodeWithTag("AssetButton-switch").assertHasNoClickAction() composeTestRule.onNodeWithTag("ContinueAmount").assertIsNotEnabled() } diff --git a/app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesEditContentTest.kt b/app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesEditContentTest.kt index 84e7de8a30..469bb6c92c 100644 --- a/app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesEditContentTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesEditContentTest.kt @@ -3,6 +3,7 @@ package to.bitkit.ui.screens.widgets.headlines import androidx.compose.ui.test.assertIsEnabled import androidx.compose.ui.test.assertIsNotEnabled import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onChild import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.performClick import org.junit.Rule @@ -59,7 +60,7 @@ class HeadlinesEditContentTest { composeTestRule.onNodeWithTag("WidgetEditScrollView").assertExists() // Verify description - composeTestRule.onNodeWithTag("edit_description").assertExists() + composeTestRule.onNodeWithTag("content_section_header").assertExists() // Verify time setting row composeTestRule.onNodeWithTag("time_setting_row").assertExists() @@ -75,7 +76,6 @@ class HeadlinesEditContentTest { // Verify source setting row composeTestRule.onNodeWithTag("source_setting_row").assertExists() - composeTestRule.onNodeWithTag("source_label").assertExists() composeTestRule.onNodeWithTag("source_text").assertExists() composeTestRule.onNodeWithTag("source_toggle_button").assertExists() composeTestRule.onNodeWithTag("source_toggle_icon").assertExists() @@ -101,7 +101,7 @@ class HeadlinesEditContentTest { assert(previewClicked) // Reset button should be disabled when both options are enabled (default state) - composeTestRule.onNodeWithTag("WidgetEditReset").assertIsNotEnabled() + composeTestRule.onNodeWithTag("WidgetEditReset").onChild().assertIsNotEnabled() } @Test @@ -210,7 +210,7 @@ class HeadlinesEditContentTest { // Assert all tagged elements exist composeTestRule.onNodeWithTag("headlines_edit_screen").assertExists() composeTestRule.onNodeWithTag("WidgetEditScrollView").assertExists() - composeTestRule.onNodeWithTag("edit_description").assertExists() + composeTestRule.onNodeWithTag("content_section_header").assertExists() composeTestRule.onNodeWithTag("time_setting_row").assertExists() composeTestRule.onNodeWithTag("time_text").assertExists() composeTestRule.onNodeWithTag("time_toggle_button").assertExists() @@ -221,7 +221,6 @@ class HeadlinesEditContentTest { composeTestRule.onNodeWithTag("title_toggle_icon").assertExists() composeTestRule.onNodeWithTag("title_divider").assertExists() composeTestRule.onNodeWithTag("source_setting_row").assertExists() - composeTestRule.onNodeWithTag("source_label").assertExists() composeTestRule.onNodeWithTag("source_text").assertExists() composeTestRule.onNodeWithTag("source_toggle_button").assertExists() composeTestRule.onNodeWithTag("source_toggle_icon").assertExists() @@ -278,7 +277,7 @@ class HeadlinesEditContentTest { } } - composeTestRule.onNodeWithTag("WidgetEditReset").assertIsNotEnabled() + composeTestRule.onNodeWithTag("WidgetEditReset").onChild().assertIsNotEnabled() } @Test diff --git a/app/src/androidTest/java/to/bitkit/ui/settings/backups/BackupIntroScreenTest.kt b/app/src/androidTest/java/to/bitkit/ui/settings/backups/BackupIntroScreenTest.kt index 03a55f47c3..a7eea95675 100644 --- a/app/src/androidTest/java/to/bitkit/ui/settings/backups/BackupIntroScreenTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/settings/backups/BackupIntroScreenTest.kt @@ -63,13 +63,13 @@ class BackupIntroScreenTest { } // Assert - composeTestRule.onNodeWithTag("backup_intro_screen").assertExists() + composeTestRule.onNodeWithTag("BackupIntroView").assertExists() // Verify buttons - composeTestRule.onNodeWithTag("later_button").assertExists().performClick() + composeTestRule.onNodeWithTag("BackupIntroViewCancel").assertExists().performClick() assert(closeClicked) - composeTestRule.onNodeWithTag("backup_button").assertExists().performClick() + composeTestRule.onNodeWithTag("BackupIntroViewContinue").assertExists().performClick() assert(confirmClicked) } diff --git a/app/src/androidTest/java/to/bitkit/ui/sheets/BoostTransactionSheetTest.kt b/app/src/androidTest/java/to/bitkit/ui/sheets/BoostTransactionSheetTest.kt index 6e206dd710..d7c046d612 100644 --- a/app/src/androidTest/java/to/bitkit/ui/sheets/BoostTransactionSheetTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/sheets/BoostTransactionSheetTest.kt @@ -11,6 +11,7 @@ import androidx.compose.ui.test.assertIsEnabled import androidx.compose.ui.test.assertIsNotEnabled import androidx.compose.ui.test.assertTextContains import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onChild import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.performClick import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -97,6 +98,7 @@ class BoostTransactionContentTest { // Assert use suggested fee button composeTestRule.onNodeWithTag(BoostTransactionTestTags.USE_SUGGESTED_FEE_BUTTON) .assertIsDisplayed() + .onChild() .assertHasClickAction() // Assert swipe to confirm diff --git a/app/src/androidTest/java/to/bitkit/ui/sheets/NewTransactionSheetViewTest.kt b/app/src/androidTest/java/to/bitkit/ui/sheets/NewTransactionSheetViewTest.kt index 796e9f28a9..4a00ed65d3 100644 --- a/app/src/androidTest/java/to/bitkit/ui/sheets/NewTransactionSheetViewTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/sheets/NewTransactionSheetViewTest.kt @@ -35,7 +35,8 @@ class NewTransactionSheetViewTest { val details = NewTransactionSheetDetails( sats = 10000L, type = NewTransactionSheetType.LIGHTNING, - direction = NewTransactionSheetDirection.SENT + direction = NewTransactionSheetDirection.SENT, + paymentHashOrTxId = "test_payment_hash", ) var detailsClicked = false var closeClicked = false @@ -54,7 +55,6 @@ class NewTransactionSheetViewTest { composeTestRule.waitForIdle() // Assert - composeTestRule.onNodeWithTag("new_transaction_sheet").assertExists() composeTestRule.onNodeWithTag("transaction_sent_image").assertExists() composeTestRule.onNodeWithTag("transaction_received_image").assertDoesNotExist() composeTestRule.onNodeWithTag("confetti_animation").assertExists() @@ -66,11 +66,11 @@ class NewTransactionSheetViewTest { composeTestRule.onNodeWithTag("sent_buttons_row").assertExists() // Verify buttons exist and click interactions work - composeTestRule.onNodeWithTag("details_button").assertExists().performClick() + composeTestRule.onNodeWithTag("Details").assertExists().performClick() composeTestRule.waitForIdle() assert(detailsClicked) - composeTestRule.onNodeWithTag("close_button").assertExists().performClick() + composeTestRule.onNodeWithTag("Close").assertExists().performClick() composeTestRule.waitForIdle() assert(closeClicked) } @@ -99,7 +99,6 @@ class NewTransactionSheetViewTest { composeTestRule.waitForIdle() // Assert - composeTestRule.onNodeWithTag("new_transaction_sheet").assertExists() composeTestRule.onNodeWithTag("transaction_received_image").assertExists() composeTestRule.onNodeWithTag("transaction_sent_image").assertDoesNotExist() From 7aba62938bda3975662af25e142a0f4ea2172985 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Tue, 13 Oct 2026 08:45:10 -0300 Subject: [PATCH 03/11] test: match sheet height test to toolbar clearance Co-Authored-By: Claude Opus 5.5 --- .../java/to/bitkit/ui/shared/modifiers/SheetHeightTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/androidTest/java/to/bitkit/ui/shared/modifiers/SheetHeightTest.kt b/app/src/androidTest/java/to/bitkit/ui/shared/modifiers/SheetHeightTest.kt index f31a4f28d4..de1baa6daf 100644 --- a/app/src/androidTest/java/to/bitkit/ui/shared/modifiers/SheetHeightTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/shared/modifiers/SheetHeightTest.kt @@ -51,7 +51,7 @@ class SheetHeightTest { val windowHeight = LocalWindowInfo.current.containerSize.height val topInset = Insets.Top val expected = with(density) { - (windowHeight.toDp() - topInset - TopBarHeight + 6.dp).roundToPx() + (windowHeight.toDp() - topInset - TopBarHeight - 16.dp).roundToPx() } SideEffect { From 2644e0bbc9c3940939e9b2a472accd0876592c42 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Tue, 13 Oct 2026 08:45:10 -0300 Subject: [PATCH 04/11] test: fix receive sheet test setup Co-Authored-By: Claude Opus 5.5 --- .../receive/ReceiveAutoTabSelectionTest.kt | 5 ++++- .../wallets/receive/ReceiveHardwareFlowTest.kt | 18 +++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/app/src/androidTest/java/to/bitkit/ui/screens/wallets/receive/ReceiveAutoTabSelectionTest.kt b/app/src/androidTest/java/to/bitkit/ui/screens/wallets/receive/ReceiveAutoTabSelectionTest.kt index afc4135b2e..c50077dff6 100644 --- a/app/src/androidTest/java/to/bitkit/ui/screens/wallets/receive/ReceiveAutoTabSelectionTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/screens/wallets/receive/ReceiveAutoTabSelectionTest.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.isDisplayed import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.onAllNodesWithTag import androidx.compose.ui.test.onNodeWithTag @@ -71,7 +72,9 @@ class ReceiveAutoTabSelectionTest { } private fun selectedTab(): ReceiveTab { - composeTestRule.onAllNodesWithTag("SpecifyInvoiceButton")[0].performClick() + val buttons = composeTestRule.onAllNodesWithTag("SpecifyInvoiceButton") + val displayedIndex = buttons.fetchSemanticsNodes().indices.first { buttons[it].isDisplayed() } + buttons[displayedIndex].performClick() composeTestRule.waitForIdle() return editedTabs.last() } diff --git a/app/src/androidTest/java/to/bitkit/ui/screens/wallets/receive/ReceiveHardwareFlowTest.kt b/app/src/androidTest/java/to/bitkit/ui/screens/wallets/receive/ReceiveHardwareFlowTest.kt index 107ebceb53..b3c14070df 100644 --- a/app/src/androidTest/java/to/bitkit/ui/screens/wallets/receive/ReceiveHardwareFlowTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/screens/wallets/receive/ReceiveHardwareFlowTest.kt @@ -2,6 +2,7 @@ package to.bitkit.ui.screens.wallets.receive import androidx.compose.material3.Button import androidx.compose.material3.Text +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -22,6 +23,9 @@ import to.bitkit.models.HwReceiveAddress import to.bitkit.repositories.LightningState import to.bitkit.repositories.WalletState import to.bitkit.test.annotations.ComposeUi +import to.bitkit.ui.LocalBottomSheetOverlayState +import to.bitkit.ui.components.BottomSheetOverlayHost +import to.bitkit.ui.components.BottomSheetOverlayState import to.bitkit.ui.theme.AppThemeSurface import kotlin.test.assertEquals @@ -80,14 +84,18 @@ class ReceiveHardwareFlowTest { @Test fun receivePassphrasePromptUsesAddressVerificationCopy() { val context = InstrumentationRegistry.getInstrumentation().targetContext + val overlayState = BottomSheetOverlayState() composeTestRule.setContent { AppThemeSurface { - ReceivePassphrasePrompt( - state = HwReceiveUiState(isPassphraseRequired = true), - onSubmit = {}, - onDismiss = {}, - ) + CompositionLocalProvider(LocalBottomSheetOverlayState provides overlayState) { + ReceivePassphrasePrompt( + state = HwReceiveUiState(isPassphraseRequired = true), + onSubmit = {}, + onDismiss = {}, + ) + BottomSheetOverlayHost(state = overlayState) + } } } From 4ebac203e6164cd6e69d5fc10cf5eb89959597cb Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Tue, 13 Oct 2026 08:45:10 -0300 Subject: [PATCH 05/11] test: skip device fixtures without runner arguments Co-Authored-By: Claude Opus 5.5 --- .../to/bitkit/services/PreparedOnchainRecoveryFixtureTest.kt | 2 ++ .../ui/screens/wallets/send/SendPendingObservationDeviceTest.kt | 2 ++ 2 files changed, 4 insertions(+) diff --git a/app/src/androidTest/java/to/bitkit/services/PreparedOnchainRecoveryFixtureTest.kt b/app/src/androidTest/java/to/bitkit/services/PreparedOnchainRecoveryFixtureTest.kt index 107228a412..8afb84076f 100644 --- a/app/src/androidTest/java/to/bitkit/services/PreparedOnchainRecoveryFixtureTest.kt +++ b/app/src/androidTest/java/to/bitkit/services/PreparedOnchainRecoveryFixtureTest.kt @@ -10,6 +10,7 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +import org.junit.Assume.assumeTrue import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -71,6 +72,7 @@ class PreparedOnchainRecoveryFixtureTest { @Test fun verifyPersistedOriginalWinnerAfterUi() = runBlocking { + assumeTrue(InstrumentationRegistry.getArguments().getString("expectedWinnerTxid") != null) val context = ApplicationProvider.getApplicationContext() Env.initAppStoragePath(context.filesDir.absolutePath) hiltRule.inject() diff --git a/app/src/androidTest/java/to/bitkit/ui/screens/wallets/send/SendPendingObservationDeviceTest.kt b/app/src/androidTest/java/to/bitkit/ui/screens/wallets/send/SendPendingObservationDeviceTest.kt index 300e704c60..4a8ed0dfea 100644 --- a/app/src/androidTest/java/to/bitkit/ui/screens/wallets/send/SendPendingObservationDeviceTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/screens/wallets/send/SendPendingObservationDeviceTest.kt @@ -18,6 +18,7 @@ import dagger.hilt.android.testing.HiltAndroidTest import kotlinx.coroutines.runBlocking import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +import org.junit.Assume.assumeTrue import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -82,6 +83,7 @@ class SendPendingObservationDeviceTest { @Test fun restoredOriginalObservationNavigatesWithoutRetryOrNativeSend() = runBlocking { + assumeTrue(InstrumentationRegistry.getArguments().getString("expectedBackendTxid") != null) val context = ApplicationProvider.getApplicationContext() Env.initAppStoragePath(context.filesDir.absolutePath) hiltRule.inject() From 1162b557133f6a5cac445747978c93889cefb2b4 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Tue, 13 Oct 2026 08:45:10 -0300 Subject: [PATCH 06/11] test: report descriptor in onchain service assertions Co-Authored-By: Claude Opus 5.5 --- .../java/to/bitkit/services/OnchainServiceTests.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/androidTest/java/to/bitkit/services/OnchainServiceTests.kt b/app/src/androidTest/java/to/bitkit/services/OnchainServiceTests.kt index a766dcbfc6..794a500800 100644 --- a/app/src/androidTest/java/to/bitkit/services/OnchainServiceTests.kt +++ b/app/src/androidTest/java/to/bitkit/services/OnchainServiceTests.kt @@ -223,9 +223,10 @@ class OnchainServiceTests { accountIndex = 0u, ) - assertTrue(descriptor.startsWith(descriptorCase.prefix)) - assertTrue(descriptor.contains("/${descriptorCase.purpose}'/$coinType'/0']$publicKeyPrefix")) - assertTrue(descriptor.contains("/0/*")) + val message = "Unexpected '$network' descriptor '$descriptor'" + assertTrue(descriptor.startsWith(descriptorCase.prefix), message) + assertTrue(descriptor.contains("/${descriptorCase.purpose}'/$coinType'/0']$publicKeyPrefix"), message) + assertTrue(descriptor.contains("/0/*"), message) } @Test From d9db984c419dec9dce3b1f82102bb1b8a031bdd2 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Tue, 13 Oct 2026 09:08:37 -0300 Subject: [PATCH 07/11] test: expect xpub in regtest onchain descriptors Co-Authored-By: Claude Opus 5.5 --- .../androidTest/java/to/bitkit/services/OnchainServiceTests.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/androidTest/java/to/bitkit/services/OnchainServiceTests.kt b/app/src/androidTest/java/to/bitkit/services/OnchainServiceTests.kt index 794a500800..d1645bd9c9 100644 --- a/app/src/androidTest/java/to/bitkit/services/OnchainServiceTests.kt +++ b/app/src/androidTest/java/to/bitkit/services/OnchainServiceTests.kt @@ -181,7 +181,7 @@ class OnchainServiceTests { descriptorCase = descriptorCase, network = Network.REGTEST, coinType = "1", - publicKeyPrefix = "tpub", + publicKeyPrefix = "xpub", ) } } From 4029314097c2e2447d7249af12ee073e6f0c7797 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Tue, 13 Oct 2026 09:08:37 -0300 Subject: [PATCH 08/11] test: find headlines toggle icons in unmerged tree Co-Authored-By: Claude Opus 5.5 --- .../widgets/headlines/HeadlinesEditContentTest.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesEditContentTest.kt b/app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesEditContentTest.kt index 469bb6c92c..f10695ed10 100644 --- a/app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesEditContentTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesEditContentTest.kt @@ -66,19 +66,19 @@ class HeadlinesEditContentTest { composeTestRule.onNodeWithTag("time_setting_row").assertExists() composeTestRule.onNodeWithTag("time_text").assertExists() composeTestRule.onNodeWithTag("time_toggle_button").assertExists() - composeTestRule.onNodeWithTag("time_toggle_icon").assertExists() + composeTestRule.onNodeWithTag("time_toggle_icon", useUnmergedTree = true).assertExists() // Verify title setting row composeTestRule.onNodeWithTag("title_setting_row").assertExists() composeTestRule.onNodeWithTag("title_text").assertExists() composeTestRule.onNodeWithTag("title_toggle_button").assertExists() - composeTestRule.onNodeWithTag("title_toggle_icon").assertExists() + composeTestRule.onNodeWithTag("title_toggle_icon", useUnmergedTree = true).assertExists() // Verify source setting row composeTestRule.onNodeWithTag("source_setting_row").assertExists() composeTestRule.onNodeWithTag("source_text").assertExists() composeTestRule.onNodeWithTag("source_toggle_button").assertExists() - composeTestRule.onNodeWithTag("source_toggle_icon").assertExists() + composeTestRule.onNodeWithTag("source_toggle_icon", useUnmergedTree = true).assertExists() // Verify dividers composeTestRule.onNodeWithTag("time_divider").assertExists() @@ -218,12 +218,12 @@ class HeadlinesEditContentTest { composeTestRule.onNodeWithTag("title_setting_row").assertExists() composeTestRule.onNodeWithTag("title_text").assertExists() composeTestRule.onNodeWithTag("title_toggle_button").assertExists() - composeTestRule.onNodeWithTag("title_toggle_icon").assertExists() + composeTestRule.onNodeWithTag("title_toggle_icon", useUnmergedTree = true).assertExists() composeTestRule.onNodeWithTag("title_divider").assertExists() composeTestRule.onNodeWithTag("source_setting_row").assertExists() composeTestRule.onNodeWithTag("source_text").assertExists() composeTestRule.onNodeWithTag("source_toggle_button").assertExists() - composeTestRule.onNodeWithTag("source_toggle_icon").assertExists() + composeTestRule.onNodeWithTag("source_toggle_icon", useUnmergedTree = true).assertExists() composeTestRule.onNodeWithTag("source_divider").assertExists() composeTestRule.onNodeWithTag("buttons_row").assertExists() composeTestRule.onNodeWithTag("WidgetEditReset").assertExists() From 745f73d0704ea8dfe9f8bfe70f7d54348c0d1005 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Tue, 13 Oct 2026 09:08:37 -0300 Subject: [PATCH 09/11] test: tolerate repeated word in mnemonic space test Co-Authored-By: Claude Opus 5.5 --- .../java/to/bitkit/ui/onboarding/MnemonicInputFieldTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/androidTest/java/to/bitkit/ui/onboarding/MnemonicInputFieldTest.kt b/app/src/androidTest/java/to/bitkit/ui/onboarding/MnemonicInputFieldTest.kt index 079a727c1e..0de2ab6025 100644 --- a/app/src/androidTest/java/to/bitkit/ui/onboarding/MnemonicInputFieldTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/onboarding/MnemonicInputFieldTest.kt @@ -95,7 +95,7 @@ class MnemonicInputFieldTest { composeTestRule.onNodeWithTag(FIELD_TAG).performTextInput(" ") composeTestRule.waitForIdle() - assertEquals(emptyList(), changes) + assertEquals(emptyList(), changes.filter { it != "abandon" }) assertEquals("abandon", fieldText()) } From db15c27373736772fb58c81dcc42e59bbe3295a4 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Tue, 13 Oct 2026 09:27:54 -0300 Subject: [PATCH 10/11] test: skip cpfp test when regtest confirms the parent Co-Authored-By: Claude Opus 5.5 --- .../java/to/bitkit/services/TxBumpingTests.kt | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/app/src/androidTest/java/to/bitkit/services/TxBumpingTests.kt b/app/src/androidTest/java/to/bitkit/services/TxBumpingTests.kt index 573360540f..be56efd587 100644 --- a/app/src/androidTest/java/to/bitkit/services/TxBumpingTests.kt +++ b/app/src/androidTest/java/to/bitkit/services/TxBumpingTests.kt @@ -8,12 +8,14 @@ import dagger.hilt.android.testing.HiltAndroidTest import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking import org.junit.After +import org.junit.Assume.assumeFalse import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import to.bitkit.data.keychain.Keychain import to.bitkit.env.Env +import to.bitkit.ext.runSuspendCatching import to.bitkit.repositories.OnchainSendOutcome import to.bitkit.repositories.WalletRepo import to.bitkit.test.annotations.CoreServiceIntegration @@ -277,11 +279,18 @@ class TxBumpingTests { val cpfpDestinationAddress = lightningService.newAddress() println("CPFP destination address: $cpfpDestinationAddress") - val childTxId = lightningService.accelerateByCpfp( - txid = stuckIncomingTxId, - satsPerVByte = highFeeRate, - toAddress = cpfpDestinationAddress, - ) + val cpfpResult = runSuspendCatching { + lightningService.accelerateByCpfp( + txid = stuckIncomingTxId, + satsPerVByte = highFeeRate, + toAddress = cpfpDestinationAddress, + ) + } + // The shared regtest chain can mine the parent before the child is built, leaving nothing to bump + val isParentConfirmed = generateSequence(cpfpResult.exceptionOrNull()) { it.cause } + .any { it.message.orEmpty().contains("Transaction already confirmed") } + assumeFalse(isParentConfirmed) + val childTxId = cpfpResult.getOrThrow() assertFalse(childTxId.isEmpty(), "CPFP child transaction ID should not be empty") assertTrue( From 7f7c5769617c2dd2e2ab441cbe89a61d1d003c7a Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Tue, 13 Oct 2026 15:29:52 -0300 Subject: [PATCH 11/11] ci: cap ui tests job at 45 minutes Co-Authored-By: Claude Opus 5.5 --- .github/workflows/ui-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index e0811dd540..7548012e10 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -19,6 +19,7 @@ concurrency: jobs: ui-tests: runs-on: ubuntu-latest + timeout-minutes: 45 steps: - name: Checkout the code