Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
117 commits
Select commit Hold shift + click to select a range
f098d77
Initial commit
voisine Oct 5, 2016
343210e
refactor: squash history to single commit
Mar 10, 2025
6826904
Updated gitignore with new filenames
kcw-grunt Mar 13, 2025
56baa6c
Still not finding BRCore
kcw-grunt Mar 13, 2025
da6aa0a
update config
kcw-grunt Mar 23, 2025
eb245c2
removed nettle
kcw-grunt Mar 23, 2025
20755b5
removed the unbound and cleaned
kcw-grunt Mar 23, 2025
5624f83
moved files to br-swift
kcw-grunt Mar 23, 2025
18b688b
WIP import BRCore
kcw-grunt Mar 23, 2025
5fb58d0
update gitignore
kcw-grunt Mar 23, 2025
0393aca
removed the TE xcscheme
kcw-grunt Mar 25, 2025
5112b94
Updated to Xcode 16
kcw-grunt Mar 25, 2025
bbf0d24
readdded launch resources
kcw-grunt Mar 25, 2025
4fafd47
remove wrong ver of core
kcw-grunt Mar 26, 2025
12d9a1b
remove wrong ver of data
kcw-grunt Mar 26, 2025
491cb72
STASHING WIP
kcw-grunt Mar 27, 2025
e49326f
Removed the data submodules
kcw-grunt Apr 11, 2025
3f3497a
WIP...BRCore found but extensions not found
kcw-grunt Apr 11, 2025
25f9fcf
DID IT DID!!!!!
kcw-grunt Apr 11, 2025
3fe2673
Merge remote-tracking branch 'origin/techdebt/kcw-debugging' into dev…
kcw-grunt Apr 11, 2025
cdc09b2
debugged the tests
kcw-grunt Apr 11, 2025
f63ca8e
updated the .gitignore
kcw-grunt Apr 11, 2025
c3555d2
version bump
kcw-grunt Apr 11, 2025
aea1369
Removed Today Extension
kcw-grunt Apr 11, 2025
482d2fd
Added localized strings
kcw-grunt Apr 11, 2025
c7ba4e1
Polished the welcome start view to match Android
kcw-grunt Apr 16, 2025
a9484b1
Set user theme mode globally
kcw-grunt Apr 17, 2025
973d586
update brand images
kcw-grunt Apr 17, 2025
b751cbf
Implement dark light mode in Start classes
kcw-grunt Apr 17, 2025
69a5210
Fixed tests
kcw-grunt Apr 17, 2025
054baae
Merge pull request #1 from gruntsoftware/feat/update-welcome-view-iss…
kcw-grunt Apr 20, 2025
7259a85
Replaced UIColor and Color with Brainwallet Color theme (#2)
kcw-grunt Apr 20, 2025
2447697
Epic/gtm color ops fixes (#4)
kcw-grunt May 5, 2025
a5e504d
chore: ios: Fix smells comply with App Store (#5)
kcw-grunt May 8, 2025
cfbd12c
πŸŽ₯ Epic/gtm refactor core library (#6)
kcw-grunt May 10, 2025
241bd6a
🧰 Fix/confirm seed words submit (#9)
kcw-grunt May 11, 2025
4f1d978
πŸ“½οΈ Epic/ Add storekit private lib (#7)
kcw-grunt May 11, 2025
939832f
πŸŽ₯ Epic/add more swift UI views prior to Localizations (#8)
kcw-grunt May 13, 2025
9caead3
🧰 Fix/add localizations (#10)
kcw-grunt May 14, 2025
5f21728
Removed the wipe wallet button (#14)
kcw-grunt May 23, 2025
0ad5c0e
🧰 Fix: Made Scanning work again (#15)
kcw-grunt May 27, 2025
5e8d578
Add a animated shape for Send (#17)
kcw-grunt May 28, 2025
10653fe
✨ Worked in the Full SwiftUI with LockScreen (#16)
kcw-grunt May 29, 2025
720bd41
per @hassanashraf92 notes (#19)
kcw-grunt May 30, 2025
3f1aa24
Refactored to remove strong parent = child references to avoid πŸ§Ÿβ€β™‚οΈ (…
kcw-grunt May 30, 2025
38847bc
❇️ chore/fetch moonpay countries+ signed buy url (#20)
kcw-grunt Jun 2, 2025
0402d16
change file location
kcw-grunt Jun 2, 2025
35f390c
chore: Polish UI (#22)
kcw-grunt Jun 4, 2025
9196e20
build bump
kcw-grunt Jun 4, 2025
f2ca5d4
fix: ios: Add wipe button UI polishes (#25)
kcw-grunt Jun 6, 2025
fe149b5
Added more defensive steps in Wallet Coordinator (#26)
kcw-grunt Jun 7, 2025
b83d7db
Fix/localization polishes (#27)
kcw-grunt Jun 7, 2025
bd6bfb0
Added agent string encryp (#29)
kcw-grunt Jun 8, 2025
2ae754e
🧰 ✨ Chore/currency set defaults polish (#30)
kcw-grunt Jun 9, 2025
05b06b8
build bump
kcw-grunt Jun 9, 2025
3b09255
✨ Feat/add buy receive inlockscreen (#32)
kcw-grunt Jun 12, 2025
36ff5a5
build bump
kcw-grunt Jun 12, 2025
f576034
Fix/UI feedback send receive (#35)
kcw-grunt Jun 14, 2025
7b88e96
small polish (#34)
kcw-grunt Jun 14, 2025
e1dbe80
admin push
kcw-grunt Jun 17, 2025
3d2d9f1
🧰 Fix Debug price recv (#37)
kcw-grunt Jun 19, 2025
0a8a1a6
🧰 Fix/theme preferred settings (#40)
kcw-grunt Jun 20, 2025
ce7d12a
build a bump
kcw-grunt Jun 22, 2025
f3bf964
❇️ Chore/polish localizations (#42)
kcw-grunt Jun 23, 2025
2976158
chore: ios: add unique ID to externalid (#44)
kcw-grunt Jun 23, 2025
5df7acb
build bump
kcw-grunt Jun 23, 2025
e6ae80a
Chore/activate test coverage (#49)
kcw-grunt Jun 30, 2025
9e24731
Chore/refactor firebase analytics (#48)
kcw-grunt Jun 30, 2025
2982094
Epic/settings migration (#50)
kcw-grunt Jul 2, 2025
9ffa5a8
🧰 fix: Removed the thread blocking seen in the lock screen trx. loa…
kcw-grunt Jul 7, 2025
5b70262
Updated localizations (#54)
kcw-grunt Jul 7, 2025
5806acf
Fix/login view crash (#55)
kcw-grunt Jul 15, 2025
c00eda2
🦾 Chore/migrate ready onboarding (#58)
kcw-grunt Jul 18, 2025
1970de7
refactor crash in WalletManager+Auth
kcw-grunt Jul 18, 2025
0bf0ecd
Merge branch 'main' into release/v3.6.0
kcw-grunt Jul 18, 2025
167eeec
config working (#60)
kcw-grunt Jul 25, 2025
b2eaad4
deleted empty dirs
kcw-grunt Jul 27, 2025
0b17a5a
πŸ“Έ Reorganized test structure Added Screenshots (#61)
kcw-grunt Jul 29, 2025
7e37f3d
Techdebt/add private submodule 175 (#62)
kcw-grunt Aug 15, 2025
197472b
Create PULL_REQUEST_TEMPLATE.md
kcw-grunt Aug 19, 2025
ece8adb
Techdebt/add private submodule 175 (#63)
kcw-grunt Aug 19, 2025
c6d24d5
Fix/refactor welcome ready restore 216 (#64)
kcw-grunt Aug 27, 2025
25d2f82
Remove erroneous yml
kcw-grunt Aug 27, 2025
dc5150d
Feat/add fcm with topics 233 (#67)
kcw-grunt Aug 29, 2025
58433f5
Techdebt/connect games (#69)
kcw-grunt Sep 29, 2025
825c106
Add nightly bento build
kcw-grunt Oct 1, 2025
e87ff00
Merge Release/v3.8.2 into Develop (#73)
kcw-grunt Oct 29, 2025
5c45ea2
MAJOR Bento MERGE (#77)
kcw-grunt Jan 24, 2026
1bcbf63
Feat/tutorials send receive walkthrough (#80)
kcw-grunt Jan 26, 2026
e24ef2f
Readded an empty class
kcw-grunt Jan 26, 2026
7ac1008
Merge branch 'main' into develop
kcw-grunt Jan 26, 2026
931ec6c
refactored Export Classes
kcw-grunt Jan 26, 2026
3a690a8
Update format
kcw-grunt Jan 26, 2026
10056a6
Udpated config.yml
kcw-grunt Jan 27, 2026
8a5f405
Techdebt/polish tutorials (#82)
kcw-grunt Jan 31, 2026
4fb05c7
Techdebt/polish game hub (#83)
kcw-grunt Feb 2, 2026
ca0dddd
Merge Release/v3.9.0 into develop (#86)
kcw-grunt Feb 10, 2026
302b46d
Techdebt/fixes various (#87)
kcw-grunt Feb 10, 2026
272a813
bump project version
kcw-grunt Feb 10, 2026
5755076
Techdebt/add tests (#88)
kcw-grunt Feb 12, 2026
c409055
Removed old legacy code that was unused
kcw-grunt Feb 12, 2026
c5b443b
modified the fastlane
kcw-grunt Feb 12, 2026
24baa40
removed old unused files
kcw-grunt Feb 12, 2026
60345bb
Remove old assets
kcw-grunt Feb 12, 2026
fe2578e
fixed or refactored warnings
kcw-grunt Feb 12, 2026
ca5eb98
Removed unused code
kcw-grunt Feb 12, 2026
f981436
version bump
kcw-grunt Feb 12, 2026
972b174
Merge branch 'main' into release/v3.9.1
kcw-grunt Feb 12, 2026
5b24eb6
Added a progress bar in send
kcw-grunt Feb 14, 2026
a3a52e9
Polishing the layout in send
kcw-grunt Feb 14, 2026
0ad162b
Debugged send view
kcw-grunt Feb 14, 2026
4f6e4d0
Added explorer urls
kcw-grunt Feb 14, 2026
c8ae2c8
Polished the script
kcw-grunt Feb 14, 2026
553775f
Update PULL_REQUEST_TEMPLATE.md
kcw-grunt Feb 16, 2026
95fbff4
Tested for xcloud xcode
kcw-grunt Feb 16, 2026
445881f
polished the xcode test script
kcw-grunt Feb 16, 2026
e0a45c7
Removed unused code
kcw-grunt Feb 16, 2026
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
7 changes: 2 additions & 5 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
HOMEBREW_NO_AUTO_UPDATE: 1
FASTLANE_SKIP_UPDATE_CHECK: 1
FL_OUTPUT_DIR: output
FASTLANE_LANE: run_all_tests_iPhone16ProMax
FASTLANE_LANE: run_unit_tests_iPhone16ProMax
XCODE_SCHEME: brainwalletUnitTests
XCODE_PROJECT: brainwallet.xcodeproj
FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT: 120
Expand Down Expand Up @@ -198,11 +198,8 @@ jobs:
find ~/Library/Developer/CoreSimulator/Devices/*/data/Library/Logs/CrashReporter/ -name "*Brainwallet*" -type f -exec echo "Found simulator crash log: {}" \; -exec cat {} \; || echo "No simulator crash logs found"
log show --predicate 'process == "Brainwallet"' --last 10m || echo "No system logs found for Brainwallet"
when: on_fail

- store_artifacts:
path: output
- store_test_results:
path: output/scan
path: test_output #.This works path: output/scan
- store_artifacts:
path: ~/Library/Logs/DiagnosticReports
destination: crash-logs
Expand Down
12 changes: 3 additions & 9 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@
## Platform
- [ ] Android
- [ ] iOS
- [ ] Games-Unity
- [ ] DevOps (AWS)
- [ ] C/Golang
- [ ] Games-Unity

## 🎯 Type of Change
<!-- Mark the relevant option with an [x] -->
- [ ] πŸš€ Release
- [ ] πŸ› Bug fix
- [ ] ✨ New feature
- [ ] πŸ”§ Refactoring (code change that neither fixes a bug nor adds a feature)
Expand All @@ -18,12 +17,7 @@
- [ ] ⚑ Performance improvement
- [ ] πŸ§ͺ Test addition or improvement

## πŸ“‹ Changes
<!-- List the key changes made in this PR -->
-
-

### πŸ”— Related Issues
## πŸ“‹ Changes / Issues
<!-- Link any related issues using "Fixes #issue_number" or "Closes #issue_number" -->
- Fixes #
- Related to #
Expand Down
46 changes: 0 additions & 46 deletions BrainwalletUITests/BrainwalletUITests.swift

This file was deleted.

67 changes: 67 additions & 0 deletions BrainwalletUITests/LockScreenViewUITests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// LockScreenViewUITests.swift
// BrainwalletUITests
//
// Created by Kerry Washington on 08/02/2026.
// Copyright Β© 2026 Grunt Software, LTD. All rights reserved.
//

import XCTest

final class LockScreenViewUITests: XCTestCase {

var app: XCUIApplication!

override func setUpWithError() throws {
try super.setUpWithError()
continueAfterFailure = false

app = XCUIApplication()
Task {
await setupSnapshot(app)
}
app.launch()

let isLockScreenViewShowing = app.descendants(matching: .any)["Lock Screen Footer View"].waitForExistence(timeout: 2)
try XCTSkipUnless(isLockScreenViewShowing, "Lock Screen Footer View not showing, skipping these tests")
}

override func tearDownWithError() throws {
app.terminate()
}

@MainActor
func testLockScreenView() throws {

XCTAssertTrue(app.descendants(matching: .any)["Lock Screen Footer View"].exists)

app.activate()
app/*@START_MENU_TOKEN@*/.buttons["moon.stars"]/*[[".otherElements",".buttons[\"Clear Night\"]",".buttons[\"moon.stars\"]"],[[[-1,2],[-1,1],[-1,0,1]],[[-1,2],[-1,1]]],[0]]@END_MENU_TOKEN@*/.firstMatch.tap()
app/*@START_MENU_TOKEN@*/.buttons["sun.max"]/*[[".otherElements",".buttons[\"Brightness Higher\"]",".buttons[\"sun.max\"]"],[[[-1,2],[-1,1],[-1,0,1]],[[-1,2],[-1,1]]],[0]]@END_MENU_TOKEN@*/.firstMatch.tap()
app/*@START_MENU_TOKEN@*/.buttons["qrcode"]/*[[".otherElements",".buttons[\"Qr Code\"]",".buttons[\"qrcode\"]"],[[[-1,2],[-1,1],[-1,0,1]],[[-1,2],[-1,1]]],[0]]@END_MENU_TOKEN@*/.firstMatch.tap()

let element = app/*@START_MENU_TOKEN@*/.buttons["8"]/*[[".otherElements.buttons[\"8\"]",".buttons[\"8\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch
element.swipeDown()
app/*@START_MENU_TOKEN@*/.buttons["trash"]/*[[".otherElements",".buttons[\"Trash\"]",".buttons[\"trash\"]"],[[[-1,2],[-1,1],[-1,0,1]],[[-1,2],[-1,1]]],[0]]@END_MENU_TOKEN@*/.firstMatch.tap()
app/*@START_MENU_TOKEN@*/.buttons["Cancel"]/*[[".otherElements.buttons[\"Cancel\"]",".buttons[\"Cancel\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch.tap()
app/*@START_MENU_TOKEN@*/.buttons["1"]/*[[".otherElements.buttons[\"1\"]",".buttons[\"1\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch.tap()
app/*@START_MENU_TOKEN@*/.buttons["2"]/*[[".otherElements.buttons[\"2\"]",".buttons[\"2\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch.tap()
app/*@START_MENU_TOKEN@*/.buttons["3"]/*[[".otherElements.buttons[\"3\"]",".buttons[\"3\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch.tap()

let element2 = app/*@START_MENU_TOKEN@*/.buttons["4"]/*[[".otherElements.buttons[\"4\"]",".buttons[\"4\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch
element2.tap()

let element3 = app/*@START_MENU_TOKEN@*/.buttons["arrow.backward"]/*[[".otherElements.buttons[\"arrow.backward\"]",".buttons[\"arrow.backward\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch
element3.doubleTap()
element3.tap()
element2.tap()
app/*@START_MENU_TOKEN@*/.buttons["5"]/*[[".otherElements.buttons[\"5\"]",".buttons[\"5\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch.tap()
app/*@START_MENU_TOKEN@*/.buttons["6"]/*[[".otherElements.buttons[\"6\"]",".buttons[\"6\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch.tap()
app/*@START_MENU_TOKEN@*/.buttons["7"]/*[[".otherElements.buttons[\"7\"]",".buttons[\"7\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch.tap()
element.tap()
app/*@START_MENU_TOKEN@*/.buttons["9"]/*[[".otherElements.buttons[\"9\"]",".buttons[\"9\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch.tap()
app/*@START_MENU_TOKEN@*/.buttons["0"]/*[[".otherElements.buttons[\"0\"]",".buttons[\"0\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch.tap()
element3.tap()
element3.doubleTap()
}
}
123 changes: 123 additions & 0 deletions BrainwalletUITests/StartViewUITests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
//
// StartViewUITests.swift
//
// Created by Kerry Washington on 08/02/2026.
// Copyright Β© 2026 Grunt Software, LTD. All rights reserved.
//

import XCTest

final class StartViewUITests: XCTestCase {
var app: XCUIApplication!

override func setUpWithError() throws {
try super.setUpWithError()
continueAfterFailure = false

app = XCUIApplication()
Task {
await setupSnapshot(app)
}
app.launch()


let isStartViewShowing = app.otherElements["Welcome Moji Demo View"].waitForExistence(timeout: 2)
try XCTSkipUnless(isStartViewShowing, "StartView not showing, skipping these tests")
}

override func tearDownWithError() throws {
app.terminate()
}

@MainActor
func testStartToReadyPath() throws {
app = XCUIApplication()
app.activate()
app/*@START_MENU_TOKEN@*/.buttons["darkModePreference"]/*[[".otherElements",".buttons[\"Brightness Higher\"]",".buttons[\"darkModePreference\"]"],[[[-1,2],[-1,1],[-1,0,1]],[[-1,2],[-1,1]]],[0]]@END_MENU_TOKEN@*/.firstMatch.tap()
app/*@START_MENU_TOKEN@*/.buttons["darkModePreference"]/*[[".otherElements",".buttons[\"Clear Night\"]",".buttons[\"darkModePreference\"]"],[[[-1,2],[-1,1],[-1,0,1]],[[-1,2],[-1,1]]],[0]]@END_MENU_TOKEN@*/.firstMatch.tap()
app/*@START_MENU_TOKEN@*/.buttons["readyCreateNewBrainwalletButton"]/*[[".otherElements",".buttons[\"Create New Wallet\"]",".buttons[\"readyCreateNewBrainwalletButton\"]"],[[[-1,2],[-1,1],[-1,0,1]],[[-1,2],[-1,1]]],[0]]@END_MENU_TOKEN@*/.firstMatch.tap()
app/*@START_MENU_TOKEN@*/.buttons["Setup app passcode"]/*[[".otherElements.buttons[\"Setup app passcode\"]",".buttons[\"Setup app passcode\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch.tap()

let element = app/*@START_MENU_TOKEN@*/.buttons["1"]/*[[".otherElements.buttons[\"1\"]",".buttons[\"1\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch
element.tap()

let element2 = app/*@START_MENU_TOKEN@*/.buttons["2"]/*[[".otherElements.buttons[\"2\"]",".buttons[\"2\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch
element2.tap()

let element3 = app/*@START_MENU_TOKEN@*/.buttons["3"]/*[[".otherElements.buttons[\"3\"]",".buttons[\"3\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch
element3.tap()

let arrowBackwardElementsQuery = app.buttons.matching(identifier: "arrow.backward")
let element4 = arrowBackwardElementsQuery.element(boundBy: 1)
element4.doubleTap()
element4.tap()
element3.tap()

let element5 = app/*@START_MENU_TOKEN@*/.buttons["4"]/*[[".otherElements.buttons[\"4\"]",".buttons[\"4\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch
element5.tap()

let element6 = app/*@START_MENU_TOKEN@*/.buttons["5"]/*[[".otherElements.buttons[\"5\"]",".buttons[\"5\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch
element6.tap()

let element7 = app/*@START_MENU_TOKEN@*/.buttons["6"]/*[[".otherElements.buttons[\"6\"]",".buttons[\"6\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch
element7.tap()

let element8 = arrowBackwardElementsQuery.element(boundBy: 0)
element8.tap()

let element9 = app/*@START_MENU_TOKEN@*/.buttons["7"]/*[[".otherElements.buttons[\"7\"]",".buttons[\"7\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch
element9.tap()

let element10 = app/*@START_MENU_TOKEN@*/.buttons["8"]/*[[".otherElements.buttons[\"8\"]",".buttons[\"8\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch
element10.tap()

let element11 = app/*@START_MENU_TOKEN@*/.buttons["9"]/*[[".otherElements.buttons[\"9\"]",".buttons[\"9\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch
element11.tap()

let element12 = app/*@START_MENU_TOKEN@*/.buttons["0"]/*[[".otherElements.buttons[\"0\"]",".buttons[\"0\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch
element12.tap()
element8.tap()
element.doubleTap()
element.doubleTap()
element.tap()
element.tap()
element2.tap()
element6.tap()
element3.tap()
element5.tap()
element6.tap()
element7.tap()
element9.tap()
element10.tap()
element11.tap()
element12.tap()
element.tap()
element.tap()
element.doubleTap()
}

@MainActor
func testStartToRestorePath() throws {
app = XCUIApplication()
app.activate()
app/*@START_MENU_TOKEN@*/.buttons["restoreYourBrainwalletButton"]/*[[".otherElements",".buttons[\"Restore with Seed Phrase\"]",".buttons[\"restoreYourBrainwalletButton\"]"],[[[-1,2],[-1,1],[-1,0,1]],[[-1,2],[-1,1]]],[0]]@END_MENU_TOKEN@*/.firstMatch.tap()
app/*@START_MENU_TOKEN@*/.buttons["Restore your Brainwallet"]/*[[".otherElements.buttons[\"Restore your Brainwallet\"]",".buttons[\"Restore your Brainwallet\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch.tap()

let element = app/*@START_MENU_TOKEN@*/.buttons["1"]/*[[".otherElements.buttons[\"1\"]",".buttons[\"1\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch
element.tap()

let element2 = app/*@START_MENU_TOKEN@*/.buttons["2"]/*[[".otherElements.buttons[\"2\"]",".buttons[\"2\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch
element2.tap()

let element3 = app/*@START_MENU_TOKEN@*/.buttons["3"]/*[[".otherElements.buttons[\"3\"]",".buttons[\"3\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch
element3.tap()

let element4 = app/*@START_MENU_TOKEN@*/.buttons["4"]/*[[".otherElements.buttons[\"4\"]",".buttons[\"4\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.firstMatch
element4.tap()
element.tap()
element2.tap()
element3.tap()
element4.tap()
}
}

1 change: 1 addition & 0 deletions BrainwalletUnitTests/APITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ class APITests: XCTestCase {
}
}
}

36 changes: 36 additions & 0 deletions BrainwalletUnitTests/Audio Tests/AudioTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// AudioTests.swift
// BrainwalletUnitTests
//
// Created by Kerry Washington on 12/02/2026.
// Copyright Β© 2026 Grunt Software, LTD. All rights reserved.
//

import Testing
import SwiftUI
import AudioToolbox

@testable import brainwallet


class MockAudioServices: AudioServicesProtocol {

var createCalled = false
var addCompletionCalled = false
var playCalled = false

func createSystemSoundID(url: CFURL, id: inout SystemSoundID) {
createCalled = true
id = 123
}

func addCompletion(id: SystemSoundID) {
addCompletionCalled = true
}

func play(id: SystemSoundID) {
playCalled = true
}

func dispose(id: SystemSoundID) {}
}
54 changes: 54 additions & 0 deletions BrainwalletUnitTests/Audio Tests/SoundsHelperTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//
// SoundsHelperTests.swift
// BrainwalletUnitTests
//
// Created by Kerry Washington on 12/02/2026.
// Copyright Β© 2026 Grunt Software, LTD. All rights reserved.
//
import XCTest
import Testing
import SwiftUI
import AudioToolbox

@testable import brainwallet

class SoundsHelperTests: XCTestCase {

var mockAudio: MockAudioServices!
var sut: SoundsHelper!

override func setUp() {
super.setUp()
mockAudio = MockAudioServices()
sut = SoundsHelper(audioService: mockAudio,
bundle: Bundle(for: Self.self))
}

func test_play_whenFileExists_callsAudioServices() {
// Given
let bundle = Bundle(for: Self.self)
sut = SoundsHelper(audioService: mockAudio, bundle: bundle)

// When
sut.play(filename: "errorsound", type: "mp3")

// Then
XCTAssertTrue(mockAudio.createCalled)
XCTAssertTrue(mockAudio.addCompletionCalled)
XCTAssertTrue(mockAudio.playCalled)
}

func test_play_whenFileDoesNotExist_doesNotCallAudioServices() {
// Given
let emptyBundle = Bundle()
sut = SoundsHelper(audioService: mockAudio, bundle: emptyBundle)

// When
sut.play(filename: "non_existing_file")

// Then
XCTAssertFalse(mockAudio.createCalled)
XCTAssertFalse(mockAudio.addCompletionCalled)
XCTAssertFalse(mockAudio.playCalled)
}
}
Binary file added BrainwalletUnitTests/Audio Tests/errorsound.mp3
Binary file not shown.
Loading