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
2 changes: 1 addition & 1 deletion .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}

Expand Down
11 changes: 6 additions & 5 deletions Bitkit/Components/MoneyStack.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand All @@ -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,
Expand All @@ -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(
Expand All @@ -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
Expand Down
4 changes: 3 additions & 1 deletion Bitkit/Components/WalletBalanceView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import SwiftUI
struct WalletBalanceView: View {
let type: WalletType
let sats: UInt64
var amountTestIdentifier: String?

@EnvironmentObject var currency: CurrencyViewModel

Expand All @@ -20,6 +21,7 @@ struct WalletBalanceView: View {
.padding(.trailing, 4)

SubtitleText(btcComponents.value)
.accessibilityIdentifierIfPresent(amountTestIdentifier)
}
} else {
HStack(spacing: 4) {
Expand All @@ -30,12 +32,12 @@ struct WalletBalanceView: View {
SubtitleText(converted.symbol)
.frame(maxWidth: 12)
SubtitleText(converted.formatted)
.accessibilityIdentifierIfPresent(amountTestIdentifier)
}
}
}
}
.frame(maxWidth: .infinity, alignment: .leading)
.accessibilityIdentifier(type == .onchain ? "ActivitySavings" : "ActivitySpending")
}
}

Expand Down
16 changes: 16 additions & 0 deletions Bitkit/Services/LightningService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,22 @@
}
}

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 {
Expand Down Expand Up @@ -472,7 +488,7 @@
}

func closeChannel(_ channel: ChannelDetails, force: Bool = false, forceCloseReason: String? = nil) async throws {
guard let node else {

Check warning on line 491 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Tests

value 'node' was defined but never used; consider replacing with boolean test

Check warning on line 491 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

value 'node' was defined but never used; consider replacing with boolean test
throw AppError(serviceError: .nodeNotStarted)
}

Expand Down Expand Up @@ -675,7 +691,7 @@
onEvent?(event)

switch event {
case let .paymentSuccessful(paymentId, paymentHash, paymentPreimage, feePaidMsat):

Check warning on line 694 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Tests

immutable value 'paymentPreimage' was never used; consider replacing with '_' or removing it

Check warning on line 694 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'paymentPreimage' was never used; consider replacing with '_' or removing it
Logger.info("✅ Payment successful: paymentId: \(paymentId ?? "?") paymentHash: \(paymentHash) feePaidMsat: \(feePaidMsat ?? 0)")
Task {
let hash = paymentId ?? paymentHash
Expand All @@ -700,7 +716,7 @@
Logger.warn("No paymentId or paymentHash available for failed payment", context: "LightningService")
}
}
case let .paymentReceived(paymentId, paymentHash, amountMsat, feePaidMsat):

Check warning on line 719 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Tests

immutable value 'feePaidMsat' was never used; consider replacing with '_' or removing it

Check warning on line 719 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'feePaidMsat' was never used; consider replacing with '_' or removing it
Logger.info("🤑 Payment received: paymentId: \(paymentId ?? "?") paymentHash: \(paymentHash) amountMsat: \(amountMsat)")
Task {
let hash = paymentId ?? paymentHash
Expand All @@ -710,7 +726,7 @@
Logger.error("Failed to handle payment received for \(hash): \(error)", context: "LightningService")
}
}
case let .paymentClaimable(paymentId, paymentHash, claimableAmountMsat, claimDeadline, customRecords):

Check warning on line 729 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Tests

immutable value 'customRecords' was never used; consider replacing with '_' or removing it

Check warning on line 729 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Tests

immutable value 'claimDeadline' was never used; consider replacing with '_' or removing it

Check warning on line 729 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'customRecords' was never used; consider replacing with '_' or removing it

Check warning on line 729 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'claimDeadline' was never used; consider replacing with '_' or removing it
Logger.info(
"🫰 Payment claimable: paymentId: \(paymentId) paymentHash: \(paymentHash) claimableAmountMsat: \(claimableAmountMsat)"
)
Expand Down Expand Up @@ -739,7 +755,7 @@

if let channel {
await registerClosedChannel(channel: channel, reason: reasonString)
await MainActor.run {

Check warning on line 758 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Tests

result of call to 'run(resultType:body:)' is unused

Check warning on line 758 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

result of call to 'run(resultType:body:)' is unused
channelCache.removeValue(forKey: channelIdString)
}
} else {
Expand All @@ -762,7 +778,7 @@
Logger.error("Failed to handle transaction received for \(txid): \(error)", context: "LightningService")
}
}
case let .onchainTransactionConfirmed(txid, blockHash, blockHeight, confirmationTime, details):

Check warning on line 781 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Tests

immutable value 'confirmationTime' was never used; consider replacing with '_' or removing it

Check warning on line 781 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Tests

immutable value 'blockHash' was never used; consider replacing with '_' or removing it

Check warning on line 781 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'confirmationTime' was never used; consider replacing with '_' or removing it

Check warning on line 781 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'blockHash' was never used; consider replacing with '_' or removing it
Logger.info("✅ Onchain transaction confirmed: txid=\(txid) blockHeight=\(blockHeight) amountSats=\(details.amountSats)")
Task {
do {
Expand Down Expand Up @@ -816,7 +832,7 @@

// MARK: Balance Events

case let .balanceChanged(oldSpendableOnchain, newSpendableOnchain, oldTotalOnchain, newTotalOnchain, oldLightning, newLightning):

Check warning on line 835 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'newTotalOnchain' was never used; consider replacing with '_' or removing it

Check warning on line 835 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'oldTotalOnchain' was never used; consider replacing with '_' or removing it
Logger
.info("💰 Balance changed: onchain=\(oldSpendableOnchain)->\(newSpendableOnchain) lightning=\(oldLightning)->\(newLightning)")

Expand Down
5 changes: 5 additions & 0 deletions Bitkit/ViewModels/WalletViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ struct CloseConnectionConfirmation: View {
await closeChannel()
}
}
.accessibilityIdentifier("CloseConnectionButton")
}
}
.navigationBarHidden(true)
Expand Down
19 changes: 15 additions & 4 deletions Bitkit/Views/Settings/Advanced/LightningConnectionDetailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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) {
Expand Down Expand Up @@ -191,6 +199,7 @@ struct LightningConnectionDetailView: View {
CustomButton(title: t("lightning__close_conn")) {
navigation.navigate(Route.closeConnection(channel: openChannel))
}
.accessibilityIdentifier("CloseConnection")
}
}
}
Expand Down Expand Up @@ -327,7 +336,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) {
Expand All @@ -338,6 +347,7 @@ struct LightningConnectionDetailView: View {
.lineLimit(1)
.truncationMode(.middle)
.frame(width: geometry.size.width * 0.6, alignment: .trailing)
.accessibilityIdentifierIfPresent(valueTestId)
}
.frame(height: 50)
}
Expand All @@ -347,7 +357,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) {
Expand All @@ -356,6 +366,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)
}
Expand Down
4 changes: 4 additions & 0 deletions Bitkit/Views/Settings/Advanced/LightningConnectionsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ struct LightningConnectionsView: View {
.frame(width: 24, height: 24)
.foregroundColor(.textPrimary)
}
.accessibilityIdentifier("NavigationAction")
)
)
.padding(.bottom, 16)
Expand Down Expand Up @@ -95,6 +96,7 @@ struct LightningConnectionsView: View {
}
}
.buttonStyle(PlainButtonStyle())
.accessibilityIdentifier("Channel")
}
}
.padding(.bottom, 16)
Expand Down Expand Up @@ -133,6 +135,7 @@ struct LightningConnectionsView: View {
}
.opacity((!channel.isChannelReady || !channel.isUsable) ? 0.64 : 1.0)
}
.accessibilityIdentifier("Channel")
}
}
}
Expand Down Expand Up @@ -170,6 +173,7 @@ struct LightningConnectionsView: View {
}
.opacity(0.64)
}
.accessibilityIdentifier("Channel")
}
}
.padding(.bottom, 16)
Expand Down
2 changes: 1 addition & 1 deletion Bitkit/Views/Sheets/NotificationsSheet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down
2 changes: 1 addition & 1 deletion Bitkit/Views/Sheets/QuickpaySheet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down
22 changes: 22 additions & 0 deletions Bitkit/Views/Transfer/FundManualAmountView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -61,6 +62,9 @@ struct FundManualAmountView: View {
.navigationBarHidden(true)
.padding(.horizontal, 16)
.bottomSafeAreaPadding()
.task {
await connectToPeerIfNeeded()
}
}

private var numberPadButtons: some View {
Expand All @@ -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 {
Expand Down
5 changes: 5 additions & 0 deletions Bitkit/Views/Transfer/FundManualSetupView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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")
}
}
}
Expand Down
12 changes: 10 additions & 2 deletions Bitkit/Views/Wallets/HomeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion Bitkit/Views/Wallets/SavingsWalletView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ struct SavingsWalletView: View {
sats: wallet.totalOnchainSats,
showSymbol: true,
showEyeIcon: false,
enableSwipeGesture: true
enableSwipeGesture: true,
testIdPrefix: "TotalBalance"
)
.padding(.top)

Expand Down
4 changes: 2 additions & 2 deletions Bitkit/Views/Wallets/Send/SendConfirmationView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
3 changes: 1 addition & 2 deletions Bitkit/Views/Wallets/Sheets/ReceivedTx.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
3 changes: 2 additions & 1 deletion Bitkit/Views/Wallets/SpendingWalletView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ struct SpendingWalletView: View {
sats: wallet.totalLightningSats,
showSymbol: true,
showEyeIcon: false,
enableSwipeGesture: true
enableSwipeGesture: true,
testIdPrefix: "TotalBalance"
)
.padding(.top)

Expand Down
Loading