Add ChatViewModel testability and unit tests

- Add testable ChatViewModel initializer accepting Transport dependency
- Create MockTransport implementing full Transport protocol for testing
- Add 21 unit tests covering:
  - Initialization (delegate, services, nickname)
  - Message sending (basic, empty, mentions, commands)
  - Message receiving (delegate calls, public messages)
  - Peer connections (connect, disconnect, isPeerConnected)
  - Deduplication service integration
  - Private chat routing
  - Bluetooth state handling
  - Panic clear functionality
- Guard NotificationService methods against test environment crashes
- Make deduplicationService internal for test access

All 303 tests pass.
This commit is contained in:
jack
2025-11-25 09:20:38 -10:00
parent ec3c16176e
commit 3e680f40bf
4 changed files with 591 additions and 7 deletions
+22 -5
View File
@@ -188,7 +188,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate, CommandContextProv
private let privateChatManager: PrivateChatManager
private let unifiedPeerService: UnifiedPeerService
private let autocompleteService: AutocompleteService
private let deduplicationService: MessageDeduplicationService
let deduplicationService: MessageDeduplicationService // internal for test access
// Computed properties for compatibility
@MainActor
@@ -417,17 +417,34 @@ final class ChatViewModel: ObservableObject, BitchatDelegate, CommandContextProv
private var nostrKeyMapping: [PeerID: String] = [:] // senderPeerID -> nostrPubkey
// MARK: - Initialization
@MainActor
init(
convenience init(
keychain: KeychainManagerProtocol,
idBridge: NostrIdentityBridge,
identityManager: SecureIdentityStateManagerProtocol
) {
self.init(
keychain: keychain,
idBridge: idBridge,
identityManager: identityManager,
transport: BLEService(keychain: keychain, idBridge: idBridge, identityManager: identityManager)
)
}
/// Testable initializer that accepts a Transport dependency.
/// Use this initializer for unit testing with MockTransport.
@MainActor
init(
keychain: KeychainManagerProtocol,
idBridge: NostrIdentityBridge,
identityManager: SecureIdentityStateManagerProtocol,
transport: Transport
) {
self.keychain = keychain
self.idBridge = idBridge
self.identityManager = identityManager
self.meshService = BLEService(keychain: keychain, idBridge: idBridge, identityManager: identityManager)
self.meshService = transport
self.publicMessagePipeline = PublicMessagePipeline()
// Load persisted read receipts
@@ -616,7 +633,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate, CommandContextProv
}
.store(in: &cancellables)
// Request notification permission
// Request notification permission (guards test environment internally)
NotificationService.shared.requestAuthorization()