Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/ui-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ concurrency:
jobs:
ui-tests:
runs-on: ubuntu-latest
timeout-minutes: 45

steps:
- name: Checkout the code
Expand Down Expand Up @@ -62,8 +63,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: |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ class OnchainServiceTests {
descriptorCase = descriptorCase,
network = Network.REGTEST,
coinType = "1",
publicKeyPrefix = "tpub",
publicKeyPrefix = "xpub",
)
}
}
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -71,6 +72,7 @@ class PreparedOnchainRecoveryFixtureTest {

@Test
fun verifyPersistedOriginalWinnerAfterUi() = runBlocking {
assumeTrue(InstrumentationRegistry.getArguments().getString("expectedWinnerTxid") != null)
val context = ApplicationProvider.getApplicationContext<Context>()
Env.initAppStoragePath(context.filesDir.absolutePath)
hiltRule.inject()
Expand Down
19 changes: 14 additions & 5 deletions app/src/androidTest/java/to/bitkit/services/TxBumpingTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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())
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -39,7 +40,7 @@ class EditInvoiceScreenTest {
}

composeTestRule.onNodeWithTag("PaymentRequestSendButton").assertIsDisplayed()
composeTestRule.onNodeWithTag("PaymentRequestSendButton").assertIsNotEnabled()
composeTestRule.onNodeWithTag("PaymentRequestSendButton").onChild().assertIsNotEnabled()
composeTestRule.onNodeWithTag("ShowQrReceive").assertIsDisplayed()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -83,7 +84,7 @@ class SendAmountContentTest {
composeTestRule.setContent {
SendAmountContent(
nodeLifecycleState = nodeLifecycleState,
uiState = uiState,
uiState = uiState.copy(isAmountInputValid = true),
amountInputViewModel = previewAmountInputViewModel(),
onContinue = { eventTriggered = true }
)
Expand Down Expand Up @@ -122,7 +123,7 @@ class SendAmountContentTest {
)
}

composeTestRule.onNodeWithTag("AssetButton-switch").assertIsNotEnabled()
composeTestRule.onNodeWithTag("AssetButton-switch").assertHasNoClickAction()
composeTestRule.onNodeWithTag("ContinueAmount").assertIsNotEnabled()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -82,6 +83,7 @@ class SendPendingObservationDeviceTest {

@Test
fun restoredOriginalObservationNavigatesWithoutRetryOrNativeSend() = runBlocking {
assumeTrue(InstrumentationRegistry.getArguments().getString("expectedBackendTxid") != null)
val context = ApplicationProvider.getApplicationContext<Context>()
Env.initAppStoragePath(context.filesDir.absolutePath)
hiltRule.inject()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -59,26 +60,25 @@ 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()
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_label").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()
Expand All @@ -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
Expand Down Expand Up @@ -210,21 +210,20 @@ 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()
composeTestRule.onNodeWithTag("time_divider").assertExists()
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_label").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()
Expand Down Expand Up @@ -278,7 +277,7 @@ class HeadlinesEditContentTest {
}
}

composeTestRule.onNodeWithTag("WidgetEditReset").assertIsNotEnabled()
composeTestRule.onNodeWithTag("WidgetEditReset").onChild().assertIsNotEnabled()
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
Expand All @@ -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)
}
Expand Down Expand Up @@ -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()

Expand Down
Loading