From c9e06b98d0e4e11f51b652cbe4e628054a00ef45 Mon Sep 17 00:00:00 2001 From: Piotr Stachyra Date: Wed, 26 Nov 2025 15:13:10 +0100 Subject: [PATCH 1/9] test ids manual connection --- .../Views/Settings/Advanced/LightningConnectionsView.swift | 1 + Bitkit/Views/Transfer/FundManualSetupView.swift | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/Bitkit/Views/Settings/Advanced/LightningConnectionsView.swift b/Bitkit/Views/Settings/Advanced/LightningConnectionsView.swift index 2b1b9e89..15ee7068 100644 --- a/Bitkit/Views/Settings/Advanced/LightningConnectionsView.swift +++ b/Bitkit/Views/Settings/Advanced/LightningConnectionsView.swift @@ -25,6 +25,7 @@ struct LightningConnectionsView: View { .frame(width: 24, height: 24) .foregroundColor(.textPrimary) } + .accessibilityIdentifier("NavigationAction") ) ) .padding(.bottom, 16) diff --git a/Bitkit/Views/Transfer/FundManualSetupView.swift b/Bitkit/Views/Transfer/FundManualSetupView.swift index bdc61f03..a7f97212 100644 --- a/Bitkit/Views/Transfer/FundManualSetupView.swift +++ b/Bitkit/Views/Transfer/FundManualSetupView.swift @@ -66,18 +66,22 @@ struct FundManualSetupView: View { CaptionMText(t("lightning__external_manual__node_id")) TextField("00000000000000000000000000000000000000000000000000000000000000", text: $nodeId) .lineLimit(2 ... 2) + .accessibilityIdentifier("NodeIdInput") } // Host field VStack(alignment: .leading, spacing: 8) { CaptionMText(t("lightning__external_manual__host")) TextField("00.00.00.00", text: $host) + .accessibilityIdentifier("HostInput") } // Port field VStack(alignment: .leading, spacing: 8) { CaptionMText(t("lightning__external_manual__port")) TextField("9735", text: $port) + .keyboardType(.numberPad) + .accessibilityIdentifier("PortInput") } // Paste Node URI button @@ -119,6 +123,7 @@ struct FundManualSetupView: View { isDisabled: nodeId.isEmpty || host.isEmpty || port.isEmpty, destination: FundManualAmountView(lnPeer: LnPeer(nodeId: nodeId, host: host, port: UInt16(port) ?? 0)) ) + .accessibilityIdentifier("ExternalContinue") } } } From 3c1c5f87bbcf7b4e2cf4cd43bd2a8a56975045a0 Mon Sep 17 00:00:00 2001 From: Piotr Stachyra Date: Wed, 26 Nov 2025 15:32:06 +0100 Subject: [PATCH 2/9] Match Android manual-channel flow: connect peer up front + localized error --- Bitkit/Services/LightningService.swift | 16 ++++++++++++++ Bitkit/ViewModels/WalletViewModel.swift | 5 +++++ .../Views/Transfer/FundManualAmountView.swift | 22 +++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/Bitkit/Services/LightningService.swift b/Bitkit/Services/LightningService.swift index aec3b16e..711e5532 100644 --- a/Bitkit/Services/LightningService.swift +++ b/Bitkit/Services/LightningService.swift @@ -262,6 +262,22 @@ class LightningService { } } + func connectPeer(peer: LnPeer, persist: Bool = true) async throws { + guard let node else { + throw AppError(serviceError: .nodeNotSetup) + } + + do { + try await ServiceQueue.background(.ldk) { + try node.connect(nodeId: peer.nodeId, address: peer.address, persist: persist) + } + Logger.info("Connected to peer: \(peer.nodeId)@\(peer.address)") + } catch { + Logger.error(error, context: "Failed to connect peer: \(peer.nodeId)@\(peer.address)") + throw error + } + } + /// Temp fix for regtest where nodes might not agree on current fee rates private func setMaxDustHtlcExposureForCurrentChannels() throws { guard Env.network == .regtest else { diff --git a/Bitkit/ViewModels/WalletViewModel.swift b/Bitkit/ViewModels/WalletViewModel.swift index 921d4c4d..83b620dc 100644 --- a/Bitkit/ViewModels/WalletViewModel.swift +++ b/Bitkit/ViewModels/WalletViewModel.swift @@ -464,6 +464,11 @@ class WalletViewModel: ObservableObject { syncState() } + func connectPeer(_ peer: LnPeer) async throws { + try await lightningService.connectPeer(peer: peer) + syncState() + } + /// Sync all state (node status, channels, peers, balances) /// Use this for initial load or after sync operations func syncState() { diff --git a/Bitkit/Views/Transfer/FundManualAmountView.swift b/Bitkit/Views/Transfer/FundManualAmountView.swift index 9d41494f..57cab389 100644 --- a/Bitkit/Views/Transfer/FundManualAmountView.swift +++ b/Bitkit/Views/Transfer/FundManualAmountView.swift @@ -8,6 +8,7 @@ struct FundManualAmountView: View { let lnPeer: LnPeer @StateObject private var amountViewModel = AmountInputViewModel() + @State private var didAttemptPeerConnection = false var amountSats: UInt64 { amountViewModel.amountSats @@ -61,6 +62,9 @@ struct FundManualAmountView: View { .navigationBarHidden(true) .padding(.horizontal, 16) .bottomSafeAreaPadding() + .task { + await connectToPeerIfNeeded() + } } private var numberPadButtons: some View { @@ -83,6 +87,24 @@ struct FundManualAmountView: View { } } } + + private func connectToPeerIfNeeded() async { + guard !didAttemptPeerConnection else { return } + didAttemptPeerConnection = true + + do { + try await wallet.connectPeer(lnPeer) + } catch { + Logger.error("Failed to connect to peer \(lnPeer.nodeId): \(error)", context: "FundManualAmountView") + await MainActor.run { + app.toast( + type: .error, + title: t("lightning__error_add_title"), + description: t("lightning__error_add") + ) + } + } + } } #Preview { From 4f78f8f356cec800d542820871cc8db29fe896f9 Mon Sep 17 00:00:00 2001 From: Piotr Stachyra Date: Wed, 26 Nov 2025 18:05:31 +0100 Subject: [PATCH 3/9] lightning connection test ids --- .../LightningConnectionDetailView.swift | 18 ++++++++++++++---- .../Advanced/LightningConnectionsView.swift | 3 +++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Bitkit/Views/Settings/Advanced/LightningConnectionDetailView.swift b/Bitkit/Views/Settings/Advanced/LightningConnectionDetailView.swift index e4750795..b3f23bac 100644 --- a/Bitkit/Views/Settings/Advanced/LightningConnectionDetailView.swift +++ b/Bitkit/Views/Settings/Advanced/LightningConnectionDetailView.swift @@ -131,7 +131,11 @@ struct LightningConnectionDetailView: View { label: t("lightning__reserve_balance"), amount: channel.displayedUnspendablePunishmentReserve ) - DetailRowWithAmount(label: t("lightning__total_size"), amount: channel.channelValueSats) + DetailRowWithAmount( + label: t("lightning__total_size"), + amount: channel.channelValueSats, + amountTestId: "TotalSize" + ) } // FEES Section @@ -148,7 +152,11 @@ struct LightningConnectionDetailView: View { CaptionMText(t("lightning__other")) VStack(spacing: 0) { - DetailRow(label: t("lightning__is_usable"), value: channel.isUsable ? t("common__yes") : t("common__no")) + DetailRow( + label: t("lightning__is_usable"), + value: channel.isUsable ? t("common__yes") : t("common__no"), + valueTestId: channel.isUsable ? "IsUsableYes" : "IsUsableNo" + ) // TODO: Add channel opening date // if let formattedDate = formatDate(channel.fundingTxo) { @@ -327,7 +335,7 @@ struct LightningConnectionDetailView: View { } // Helper Views - private func DetailRow(label: String, value: String) -> some View { + private func DetailRow(label: String, value: String, valueTestId: String? = nil) -> some View { VStack(alignment: .leading, spacing: 0) { GeometryReader { geometry in HStack(alignment: .center, spacing: 0) { @@ -338,6 +346,7 @@ struct LightningConnectionDetailView: View { .lineLimit(1) .truncationMode(.middle) .frame(width: geometry.size.width * 0.6, alignment: .trailing) + .accessibilityIdentifierIfPresent(valueTestId) } .frame(height: 50) } @@ -347,7 +356,7 @@ struct LightningConnectionDetailView: View { .frame(height: 51) } - private func DetailRowWithAmount(label: String, amount: UInt64) -> some View { + private func DetailRowWithAmount(label: String, amount: UInt64, amountTestId: String? = nil) -> some View { VStack(alignment: .leading, spacing: 0) { GeometryReader { geometry in HStack(alignment: .center, spacing: 0) { @@ -356,6 +365,7 @@ struct LightningConnectionDetailView: View { MoneyText(sats: Int(amount), size: .captionB, symbol: true) .frame(width: geometry.size.width * 0.6, alignment: .trailing) + .accessibilityIdentifierIfPresent(amountTestId) } .frame(height: 50) } diff --git a/Bitkit/Views/Settings/Advanced/LightningConnectionsView.swift b/Bitkit/Views/Settings/Advanced/LightningConnectionsView.swift index 15ee7068..d10a8e53 100644 --- a/Bitkit/Views/Settings/Advanced/LightningConnectionsView.swift +++ b/Bitkit/Views/Settings/Advanced/LightningConnectionsView.swift @@ -96,6 +96,7 @@ struct LightningConnectionsView: View { } } .buttonStyle(PlainButtonStyle()) + .accessibilityIdentifier("Channel") } } .padding(.bottom, 16) @@ -134,6 +135,7 @@ struct LightningConnectionsView: View { } .opacity((!channel.isChannelReady || !channel.isUsable) ? 0.64 : 1.0) } + .accessibilityIdentifier("Channel") } } } @@ -171,6 +173,7 @@ struct LightningConnectionsView: View { } .opacity(0.64) } + .accessibilityIdentifier("Channel") } } .padding(.bottom, 16) From 2934c06b196836f4810b481c77c7e12f10adaf77 Mon Sep 17 00:00:00 2001 From: Piotr Stachyra Date: Thu, 27 Nov 2025 13:45:39 +0100 Subject: [PATCH 4/9] ActivitySavings and Spending --- Bitkit/Components/WalletBalanceView.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Bitkit/Components/WalletBalanceView.swift b/Bitkit/Components/WalletBalanceView.swift index ff90655c..a3a924b6 100644 --- a/Bitkit/Components/WalletBalanceView.swift +++ b/Bitkit/Components/WalletBalanceView.swift @@ -35,7 +35,6 @@ struct WalletBalanceView: View { } } .frame(maxWidth: .infinity, alignment: .leading) - .accessibilityIdentifier(type == .onchain ? "ActivitySavings" : "ActivitySpending") } } From a175944e6a271360c520632db6372a29684c4a18 Mon Sep 17 00:00:00 2001 From: Piotr Stachyra Date: Thu, 27 Nov 2025 13:48:13 +0100 Subject: [PATCH 5/9] TotalBalance vs. ReviewAmount --- Bitkit/Components/MoneyStack.swift | 11 ++++++----- Bitkit/Views/Wallets/Send/SendConfirmationView.swift | 4 ++-- Bitkit/Views/Wallets/Sheets/ReceivedTx.swift | 3 +-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Bitkit/Components/MoneyStack.swift b/Bitkit/Components/MoneyStack.swift index dec1bf90..48901024 100644 --- a/Bitkit/Components/MoneyStack.swift +++ b/Bitkit/Components/MoneyStack.swift @@ -7,6 +7,7 @@ struct MoneyStack: View { var showSymbol: Bool = false var showEyeIcon: Bool = false var enableSwipeGesture: Bool = false + var testIdPrefix: String = "TotalBalance" @EnvironmentObject var app: AppViewModel @EnvironmentObject var currency: CurrencyViewModel @@ -34,7 +35,7 @@ struct MoneyStack: View { .combined(with: .scale(scale: 1.5, anchor: .topLeading)) ) .accessibilityElement(children: .contain) - .accessibilityIdentifier("TotalBalance-secondary") + .accessibilityIdentifier("\(testIdPrefix)-secondary") HStack { MoneyText( @@ -60,7 +61,7 @@ struct MoneyStack: View { .combined(with: .scale(scale: 0.5, anchor: .topLeading)) ) .accessibilityElement(children: .contain) - .accessibilityIdentifier("TotalBalance-primary") + .accessibilityIdentifier("\(testIdPrefix)-primary") } else { MoneyText( sats: sats, @@ -77,7 +78,7 @@ struct MoneyStack: View { .combined(with: .scale(scale: 1.5, anchor: .topLeading)) ) .accessibilityElement(children: .contain) - .accessibilityIdentifier("TotalBalance-secondary") + .accessibilityIdentifier("\(testIdPrefix)-secondary") HStack { MoneyText( @@ -103,11 +104,11 @@ struct MoneyStack: View { .combined(with: .scale(scale: 0.5, anchor: .topLeading)) ) .accessibilityElement(children: .contain) - .accessibilityIdentifier("TotalBalance-primary") + .accessibilityIdentifier("\(testIdPrefix)-primary") } } .accessibilityElement(children: .contain) - .accessibilityIdentifier("TotalBalance") + .accessibilityIdentifier(testIdPrefix) .contentShape(Rectangle()) .onTapGesture { let previousDisplay = currency.primaryDisplay diff --git a/Bitkit/Views/Wallets/Send/SendConfirmationView.swift b/Bitkit/Views/Wallets/Send/SendConfirmationView.swift index 0126a43c..43e77c79 100644 --- a/Bitkit/Views/Wallets/Send/SendConfirmationView.swift +++ b/Bitkit/Views/Wallets/Send/SendConfirmationView.swift @@ -79,11 +79,11 @@ struct SendConfirmationView: View { VStack(alignment: .leading, spacing: 0) { if app.selectedWalletToPayFrom == .lightning, let invoice = app.scannedLightningInvoice { - MoneyStack(sats: Int(wallet.sendAmountSats ?? invoice.amountSatoshis), showSymbol: true) + MoneyStack(sats: Int(wallet.sendAmountSats ?? invoice.amountSatoshis), showSymbol: true, testIdPrefix: "ReviewAmount") .padding(.bottom, 44) lightningView(invoice) } else if app.selectedWalletToPayFrom == .onchain, let invoice = app.scannedOnchainInvoice { - MoneyStack(sats: Int(wallet.sendAmountSats ?? invoice.amountSatoshis), showSymbol: true) + MoneyStack(sats: Int(wallet.sendAmountSats ?? invoice.amountSatoshis), showSymbol: true, testIdPrefix: "ReviewAmount") .padding(.bottom, 44) onchainView(invoice) } diff --git a/Bitkit/Views/Wallets/Sheets/ReceivedTx.swift b/Bitkit/Views/Wallets/Sheets/ReceivedTx.swift index 6a19fb84..a86418ec 100644 --- a/Bitkit/Views/Wallets/Sheets/ReceivedTx.swift +++ b/Bitkit/Views/Wallets/Sheets/ReceivedTx.swift @@ -50,8 +50,7 @@ struct ReceivedTx: View { VStack(alignment: .leading, spacing: 0) { SheetHeader(title: title) - MoneyStack(sats: Int(config.details.sats), showSymbol: true) - .accessibilityIdentifier("ReceivedTransaction") + MoneyStack(sats: Int(config.details.sats), showSymbol: true, testIdPrefix: "ReceivedTransaction") Spacer() CustomButton(title: buttonText) { sheets.hideSheet() } .accessibilityIdentifier("ReceivedTransactionButton") From a2fa7c9edc0b30669b74b34048344010fb2a750e Mon Sep 17 00:00:00 2001 From: Piotr Stachyra Date: Thu, 27 Nov 2025 20:13:05 +0100 Subject: [PATCH 6/9] CloseConnection --- Bitkit/Views/Settings/Advanced/CloseConnectionConfirmation.swift | 1 + .../Views/Settings/Advanced/LightningConnectionDetailView.swift | 1 + 2 files changed, 2 insertions(+) diff --git a/Bitkit/Views/Settings/Advanced/CloseConnectionConfirmation.swift b/Bitkit/Views/Settings/Advanced/CloseConnectionConfirmation.swift index 35cb8d8b..c3024353 100644 --- a/Bitkit/Views/Settings/Advanced/CloseConnectionConfirmation.swift +++ b/Bitkit/Views/Settings/Advanced/CloseConnectionConfirmation.swift @@ -38,6 +38,7 @@ struct CloseConnectionConfirmation: View { await closeChannel() } } + .accessibilityIdentifier("CloseConnectionButton") } } .navigationBarHidden(true) diff --git a/Bitkit/Views/Settings/Advanced/LightningConnectionDetailView.swift b/Bitkit/Views/Settings/Advanced/LightningConnectionDetailView.swift index b3f23bac..8cda1030 100644 --- a/Bitkit/Views/Settings/Advanced/LightningConnectionDetailView.swift +++ b/Bitkit/Views/Settings/Advanced/LightningConnectionDetailView.swift @@ -199,6 +199,7 @@ struct LightningConnectionDetailView: View { CustomButton(title: t("lightning__close_conn")) { navigation.navigate(Route.closeConnection(channel: openChannel)) } + .accessibilityIdentifier("CloseConnection") } } } From d58308ef8107dd9b276f149669d1feb4cf86cd95 Mon Sep 17 00:00:00 2001 From: Piotr Stachyra Date: Mon, 1 Dec 2025 13:47:41 +0100 Subject: [PATCH 7/9] ActivitySavings, ActivitySpending --- Bitkit/Components/WalletBalanceView.swift | 3 +++ Bitkit/Views/Wallets/HomeView.swift | 12 ++++++++++-- Bitkit/Views/Wallets/SavingsWalletView.swift | 3 ++- Bitkit/Views/Wallets/SpendingWalletView.swift | 3 ++- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Bitkit/Components/WalletBalanceView.swift b/Bitkit/Components/WalletBalanceView.swift index a3a924b6..bec3c76c 100644 --- a/Bitkit/Components/WalletBalanceView.swift +++ b/Bitkit/Components/WalletBalanceView.swift @@ -3,6 +3,7 @@ import SwiftUI struct WalletBalanceView: View { let type: WalletType let sats: UInt64 + var amountTestIdentifier: String? @EnvironmentObject var currency: CurrencyViewModel @@ -20,6 +21,7 @@ struct WalletBalanceView: View { .padding(.trailing, 4) SubtitleText(btcComponents.value) + .accessibilityIdentifierIfPresent(amountTestIdentifier) } } else { HStack(spacing: 4) { @@ -30,6 +32,7 @@ struct WalletBalanceView: View { SubtitleText(converted.symbol) .frame(maxWidth: 12) SubtitleText(converted.formatted) + .accessibilityIdentifierIfPresent(amountTestIdentifier) } } } diff --git a/Bitkit/Views/Wallets/HomeView.swift b/Bitkit/Views/Wallets/HomeView.swift index 025a6d19..23c75d3f 100644 --- a/Bitkit/Views/Wallets/HomeView.swift +++ b/Bitkit/Views/Wallets/HomeView.swift @@ -26,7 +26,11 @@ struct HomeView: View { VStack(spacing: 0) { HStack(spacing: 0) { NavigationLink(value: Route.savingsWallet) { - WalletBalanceView(type: .onchain, sats: UInt64(wallet.totalOnchainSats)) + WalletBalanceView( + type: .onchain, + sats: UInt64(wallet.totalOnchainSats), + amountTestIdentifier: "ActivitySavings" + ) } Divider() @@ -36,7 +40,11 @@ struct HomeView: View { .padding(.leading, 16) NavigationLink(value: Route.spendingWallet) { - WalletBalanceView(type: .lightning, sats: UInt64(wallet.totalLightningSats)) + WalletBalanceView( + type: .lightning, + sats: UInt64(wallet.totalLightningSats), + amountTestIdentifier: "ActivitySpending" + ) } } .frame(maxWidth: .infinity, alignment: .leading) diff --git a/Bitkit/Views/Wallets/SavingsWalletView.swift b/Bitkit/Views/Wallets/SavingsWalletView.swift index efd0697d..a4fc5f03 100644 --- a/Bitkit/Views/Wallets/SavingsWalletView.swift +++ b/Bitkit/Views/Wallets/SavingsWalletView.swift @@ -14,7 +14,8 @@ struct SavingsWalletView: View { sats: wallet.totalOnchainSats, showSymbol: true, showEyeIcon: false, - enableSwipeGesture: true + enableSwipeGesture: true, + testIdPrefix: "TotalBalance" ) .padding(.top) diff --git a/Bitkit/Views/Wallets/SpendingWalletView.swift b/Bitkit/Views/Wallets/SpendingWalletView.swift index 59f26f20..339eb9e6 100644 --- a/Bitkit/Views/Wallets/SpendingWalletView.swift +++ b/Bitkit/Views/Wallets/SpendingWalletView.swift @@ -14,7 +14,8 @@ struct SpendingWalletView: View { sats: wallet.totalLightningSats, showSymbol: true, showEyeIcon: false, - enableSwipeGesture: true + enableSwipeGesture: true, + testIdPrefix: "TotalBalance" ) .padding(.top) From 9cdb6a1663071c69bbc1e33697fc93ed3cd9e761 Mon Sep 17 00:00:00 2001 From: Piotr Stachyra Date: Tue, 2 Dec 2025 15:15:46 +0100 Subject: [PATCH 8/9] Bg payments and quickpay test ids --- Bitkit/Views/Sheets/NotificationsSheet.swift | 2 +- Bitkit/Views/Sheets/QuickpaySheet.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Bitkit/Views/Sheets/NotificationsSheet.swift b/Bitkit/Views/Sheets/NotificationsSheet.swift index 160ded1a..8eb01cf0 100644 --- a/Bitkit/Views/Sheets/NotificationsSheet.swift +++ b/Bitkit/Views/Sheets/NotificationsSheet.swift @@ -21,7 +21,7 @@ struct NotificationsSheet: View { continueText: t("settings__notifications__intro__button"), cancelText: t("common__later"), accentColor: .blueAccent, - testID: "NotificationsSheet", + testID: "BackgroundPayments", onCancel: onLater, onContinue: onEnable ) diff --git a/Bitkit/Views/Sheets/QuickpaySheet.swift b/Bitkit/Views/Sheets/QuickpaySheet.swift index 6657da10..fd056b9d 100644 --- a/Bitkit/Views/Sheets/QuickpaySheet.swift +++ b/Bitkit/Views/Sheets/QuickpaySheet.swift @@ -21,7 +21,7 @@ struct QuickpaySheet: View { continueText: t("common__learn_more"), cancelText: t("common__later"), accentColor: .greenAccent, - testID: "QuickpaySheet", + testID: "QuickpayIntro", onCancel: onLater, onContinue: onLearnMore ) From 3e53a74968ea36215dea20c69e89bd59517b955f Mon Sep 17 00:00:00 2001 From: Piotr Stachyra Date: Tue, 2 Dec 2025 15:29:37 +0100 Subject: [PATCH 9/9] Enable @lightning e2e --- .github/workflows/e2e-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index e3abd3e3..5a7b4ce7 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -108,7 +108,7 @@ jobs: # - { name: onchain_boost_receive_widgets, grep: "@onchain|@boost|@receive|@widgets" } # - { name: settings, grep: "@settings" } # - { name: security, grep: "@security" } - - { name: e2e, grep: '@backup|@onboarding|@onchain_1|@onchain_2|@numberpad|@widgets|@boost|@receive|@settings|@security' } + - { name: e2e, grep: '@lightning|@backup|@onboarding|@onchain_1|@onchain_2|@numberpad|@widgets|@boost|@receive|@settings|@security' } name: e2e-tests - ${{ matrix.shard.name }}