Skip to content

Commit 364e0a1

Browse files
authored
Merge pull request #266 from synonymdev/test/lnurl
Test/lnurl
2 parents b78b19b + cec0db6 commit 364e0a1

20 files changed

+155
-42
lines changed

.github/workflows/e2e-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ jobs:
108108
# - { name: onchain_boost_receive_widgets, grep: "@onchain|@boost|@receive|@widgets" }
109109
# - { name: settings, grep: "@settings" }
110110
# - { name: security, grep: "@security" }
111-
- { name: e2e, grep: '@lightning|@backup|@onboarding|@onchain_1|@onchain_2|@numberpad|@widgets|@boost|@receive|@settings|@security' }
111+
- { name: e2e, grep: '@lnurl|@lightning|@backup|@onboarding|@onchain_1|@onchain_2|@numberpad|@widgets|@boost|@receive|@settings|@security' }
112112

113113
name: e2e-tests - ${{ matrix.shard.name }}
114114

Bitkit/Components/NumberPadTextField.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ struct NumberPadTextField: View {
77

88
var showConversion: Bool = true
99
var isFocused: Bool = true
10+
var testIdentifier: String?
1011

1112
private let springAnimation = Animation.spring(response: 0.3, dampingFraction: 0.8)
1213

@@ -86,6 +87,7 @@ struct NumberPadTextField: View {
8687
+ Text(viewModel.getPlaceholder(currency: currency))
8788
.foregroundColor(isFocused ? .textSecondary : .textPrimary))
8889
.font(.custom(Fonts.black, size: 44))
90+
.accessibilityIdentifierIfPresent(testIdentifier)
8991
}
9092
}
9193
}

Bitkit/Components/TextField.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ struct TextField: View {
66
let font: Font
77
let axis: Axis
88
let testIdentifier: String?
9+
let submitLabel: SubmitLabel
910
@Binding var text: String
1011

1112
init(
@@ -14,13 +15,15 @@ struct TextField: View {
1415
backgroundColor: Color = .white10,
1516
font: Font = .custom(Fonts.semiBold, size: 15),
1617
axis: Axis = .horizontal,
17-
testIdentifier: String? = nil
18+
testIdentifier: String? = nil,
19+
submitLabel: SubmitLabel = .return
1820
) {
1921
self.placeholder = placeholder
2022
self.backgroundColor = backgroundColor
2123
self.font = font
2224
self.axis = axis
2325
self.testIdentifier = testIdentifier
26+
self.submitLabel = submitLabel
2427
_text = text
2528
}
2629

@@ -35,6 +38,7 @@ struct TextField: View {
3538
SwiftUI.TextField("", text: $text, axis: axis)
3639
.accentColor(.brandAccent)
3740
.font(font)
41+
.submitLabel(submitLabel)
3842
.accessibilityIdentifierIfPresent(testIdentifier)
3943
}
4044
.padding()

Bitkit/Constants/Env.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ enum Env {
1515
static let isE2E = ProcessInfo.processInfo.environment["E2E"] == "true"
1616
#endif
1717
static let dustLimit = 547
18+
static let msatsPerSat: UInt64 = 1000
1819

1920
#if CHECK_GEOBLOCK
2021
static let isGeoblockingEnabled = true

Bitkit/MainNavView.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ struct MainNavView: View {
8383
.sheet(
8484
item: $sheets.lnurlWithdrawSheetItem,
8585
onDismiss: {
86-
sheets.hideSheet()
86+
sheets.hideSheetIfActive(.lnurlWithdraw, reason: "LNURL withdraw sheet dismissed")
8787
}
8888
) {
8989
config in LnurlWithdrawSheet(config: config)
@@ -116,7 +116,7 @@ struct MainNavView: View {
116116
.sheet(
117117
item: $sheets.scannerSheetItem,
118118
onDismiss: {
119-
sheets.hideSheet()
119+
sheets.hideSheetIfActive(.scanner, reason: "Scanner sheet dismissed")
120120
}
121121
) {
122122
config in ScannerSheet(config: config)
@@ -141,7 +141,7 @@ struct MainNavView: View {
141141
.sheet(
142142
item: $sheets.sendSheetItem,
143143
onDismiss: {
144-
sheets.hideSheet()
144+
sheets.hideSheetIfActive(.send, reason: "Send sheet dismissed")
145145
}
146146
) {
147147
config in SendSheet(config: config)

Bitkit/Utilities/Lnurl.swift

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -175,13 +175,18 @@ struct LnurlHelper {
175175
params: LnurlChannelData,
176176
nodeId: String
177177
) async throws {
178-
let queryItems = [
179-
URLQueryItem(name: "k1", value: params.k1),
180-
URLQueryItem(name: "remoteid", value: nodeId),
181-
URLQueryItem(name: "private", value: "1"), // Private channel
182-
]
178+
let callbackUrlString = try createChannelRequestUrl(
179+
k1: params.k1,
180+
callback: params.callback,
181+
localNodeId: nodeId,
182+
isPrivate: true,
183+
cancel: false
184+
)
185+
186+
guard let callbackURL = URL(string: callbackUrlString) else {
187+
throw NSError(domain: "LNURL", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid callback URL"])
188+
}
183189

184-
let callbackURL = try buildUrl(baseUrl: params.callback, queryItems: queryItems)
185190
let responseString = try await makeHttpGetRequest(url: callbackURL)
186191
let channelResponse = try parseJsonResponse(responseString, as: LnurlChannelResponse.self)
187192

Bitkit/Utilities/PaymentNavigationHelper.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,14 @@ struct PaymentNavigationHelper {
103103
currency: CurrencyViewModel,
104104
settings: SettingsViewModel
105105
) -> SendRoute {
106+
if let lnurlWithdrawData = app.lnurlWithdrawData {
107+
if lnurlWithdrawData.minWithdrawable == lnurlWithdrawData.maxWithdrawable {
108+
return .lnurlWithdrawConfirm
109+
} else {
110+
return .lnurlWithdrawAmount
111+
}
112+
}
113+
106114
let shouldUseQuickpay = shouldUseQuickpay(app: app, settings: settings, currency: currency)
107115

108116
// Handle Lightning address / LNURL pay

Bitkit/ViewModels/AppViewModel.swift

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,13 @@ extension AppViewModel {
252252
return
253253
}
254254

255+
var normalizedData = data
256+
normalizedData.minSendable = max(1, normalizedData.minSendable / Env.msatsPerSat)
257+
normalizedData.maxSendable = max(normalizedData.minSendable, normalizedData.maxSendable / Env.msatsPerSat)
258+
255259
// Check if user has enough lightning balance to pay the minimum amount
256260
let lightningBalance = lightningService.balances?.totalLightningBalanceSats ?? 0
257-
if lightningBalance < data.minSendable {
261+
if lightningBalance < normalizedData.minSendable {
258262
toast(
259263
type: .warning,
260264
title: t("other__lnurl_pay_error"),
@@ -264,7 +268,7 @@ extension AppViewModel {
264268
}
265269

266270
selectedWalletToPayFrom = .lightning
267-
lnurlPayData = data
271+
lnurlPayData = normalizedData
268272
}
269273

270274
private func handleLnurlWithdraw(_ data: LnurlWithdrawData) {
@@ -274,8 +278,11 @@ extension AppViewModel {
274278
return
275279
}
276280

281+
let minMsats = data.minWithdrawable ?? Env.msatsPerSat
282+
let maxMsats = data.maxWithdrawable
283+
277284
// Check if minWithdrawable > maxWithdrawable
278-
if (data.minWithdrawable ?? 1000) > data.maxWithdrawable {
285+
if minMsats > maxMsats {
279286
toast(
280287
type: .warning,
281288
title: t("other__lnurl_withdr_error"),
@@ -284,9 +291,15 @@ extension AppViewModel {
284291
return
285292
}
286293

294+
var normalizedData = data
295+
let minSats = max(1, minMsats / Env.msatsPerSat)
296+
let maxSats = max(minSats, maxMsats / Env.msatsPerSat)
297+
normalizedData.minWithdrawable = minSats
298+
normalizedData.maxWithdrawable = maxSats
299+
287300
// Check if we have enough receiving capacity
288301
let lightningBalance = lightningService.balances?.totalLightningBalanceSats ?? 0
289-
if lightningBalance < (data.minWithdrawable ?? 1000) / 1000 {
302+
if lightningBalance < minSats {
290303
toast(
291304
type: .warning,
292305
title: t("other__lnurl_withdr_error"),
@@ -295,7 +308,7 @@ extension AppViewModel {
295308
return
296309
}
297310

298-
lnurlWithdrawData = data
311+
lnurlWithdrawData = normalizedData
299312
}
300313

301314
private func handleLnurlChannel(_ data: LnurlChannelData) {
@@ -415,7 +428,8 @@ extension AppViewModel {
415428
type: .lightning,
416429
title: t("lightning__channel_opened_title"),
417430
description: t("lightning__channel_opened_msg"),
418-
visibilityTime: 5.0
431+
visibilityTime: 5.0,
432+
accessibilityIdentifier: "SpendingBalanceReadyToast"
419433
)
420434
}
421435
}
@@ -424,7 +438,8 @@ extension AppViewModel {
424438
type: .lightning,
425439
title: t("lightning__channel_opened_title"),
426440
description: t("lightning__channel_opened_msg"),
427-
visibilityTime: 5.0
441+
visibilityTime: 5.0,
442+
accessibilityIdentifier: "SpendingBalanceReadyToast"
428443
)
429444
}
430445
case .channelClosed(channelId: _, userChannelId: _, counterpartyNodeId: _, reason: _):

Bitkit/ViewModels/SheetViewModel.swift

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class SheetViewModel: ObservableObject {
3838

3939
DispatchQueue.main.asyncAfter(deadline: .now() + 0.7) { [weak self] in
4040
guard let self else { return }
41+
Logger.debug("Showing sheet \(id.rawValue) after delay", context: "SheetViewModel")
4142
activeSheetConfiguration = SheetConfiguration(id: id, data: data)
4243
playHaptics(for: id)
4344

@@ -48,6 +49,7 @@ class SheetViewModel: ObservableObject {
4849
}
4950
} else {
5051
// If no sheet is open, show the new sheet immediately
52+
Logger.debug("Showing sheet \(id.rawValue)", context: "SheetViewModel")
5153
activeSheetConfiguration = SheetConfiguration(id: id, data: data)
5254
playHaptics(for: id)
5355

@@ -58,7 +60,16 @@ class SheetViewModel: ObservableObject {
5860
}
5961
}
6062

61-
func hideSheet() {
63+
func hideSheet(reason: String? = nil, file: String = #file, function: String = #function, line: Int = #line) {
64+
if let config = activeSheetConfiguration {
65+
let fallback = "\(URL(fileURLWithPath: file).lastPathComponent):\(line) \(function)"
66+
let reasonText = " reason: \(reason ?? fallback)"
67+
Logger.debug("Hiding sheet \(config.id.rawValue)\(reasonText)", context: "SheetViewModel")
68+
} else {
69+
let fallback = "\(URL(fileURLWithPath: file).lastPathComponent):\(line) \(function)"
70+
let reasonText = " reason: \(reason ?? fallback)"
71+
Logger.debug("hideSheet called with no active sheet\(reasonText)", context: "SheetViewModel")
72+
}
6273
activeSheetConfiguration = nil
6374

6475
// Notify timed sheet manager
@@ -67,6 +78,17 @@ class SheetViewModel: ObservableObject {
6778
}
6879
}
6980

81+
func hideSheetIfActive(_ id: SheetID, reason: String? = nil, file: String = #file, function: String = #function, line: Int = #line) {
82+
guard activeSheetConfiguration?.id == id else {
83+
let fallback = "\(URL(fileURLWithPath: file).lastPathComponent):\(line) \(function)"
84+
let reasonText = " reason: \(reason ?? fallback)"
85+
let activeId = activeSheetConfiguration?.id.rawValue ?? "none"
86+
Logger.debug("hideSheetIfActive skipped for \(id.rawValue) (active: \(activeId))\(reasonText)", context: "SheetViewModel")
87+
return
88+
}
89+
hideSheet(reason: reason, file: file, function: function, line: line)
90+
}
91+
7092
var isAnySheetOpen: Bool {
7193
return activeSheetConfiguration != nil
7294
}

Bitkit/Views/Sheets/LnurlAuth/LnurlAuthSheet.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,16 +85,19 @@ struct LnurlAuthSheet: View {
8585
) {
8686
onCancel()
8787
}
88+
.accessibilityIdentifier("LnurlAuthCancel")
8889

8990
CustomButton(title: actionText) {
9091
Task {
9192
await onContinue()
9293
}
9394
}
95+
.accessibilityIdentifier("LnurlAuthContinue")
9496
}
9597
.padding(.top, 32)
9698
}
9799
.padding(.horizontal, 16)
100+
.accessibilityElement(children: .contain)
98101
.accessibilityIdentifier("LnurlAuth")
99102
}
100103
}

0 commit comments

Comments
 (0)