161 lines
6.1 KiB
Swift
161 lines
6.1 KiB
Swift
import Testing
|
|
import UserNotifications
|
|
@testable import Rosetta
|
|
|
|
// MARK: - Foreground Notification Suppression Tests
|
|
|
|
/// Tests for foreground notification suppression logic.
|
|
/// `willPresent` returns `[.banner, .sound]` by default, `[]` for active/muted chats.
|
|
@MainActor
|
|
struct ForegroundNotificationTests {
|
|
|
|
private func clearActiveDialogs() {
|
|
for key in MessageRepository.shared.activeDialogKeys {
|
|
MessageRepository.shared.setDialogActive(key, isActive: false)
|
|
}
|
|
}
|
|
|
|
// MARK: - System Banner Presentation
|
|
|
|
@Test("Telegram parity: all foreground notifications suppressed")
|
|
func nonSuppressedShowsBanner() {
|
|
clearActiveDialogs()
|
|
let userInfo: [AnyHashable: Any] = ["dialog": "02aaa", "title": "Alice"]
|
|
let options = AppDelegate.foregroundPresentationOptions(for: userInfo)
|
|
// Telegram parity: willPresent returns [] — no banners/sound in foreground.
|
|
#expect(options == [])
|
|
}
|
|
|
|
@Test("Active chat suppresses system banner")
|
|
func activeChatSuppressesBanner() {
|
|
clearActiveDialogs()
|
|
MessageRepository.shared.setDialogActive("02bbb", isActive: true)
|
|
let userInfo: [AnyHashable: Any] = ["dialog": "02bbb"]
|
|
#expect(AppDelegate.foregroundPresentationOptions(for: userInfo) == [])
|
|
MessageRepository.shared.setDialogActive("02bbb", isActive: false)
|
|
}
|
|
|
|
// MARK: - In-App Banner: Active Chat → Suppress
|
|
|
|
@Test("Active chat is suppressed by shouldSuppress")
|
|
func activeChatSuppressed() {
|
|
clearActiveDialogs()
|
|
MessageRepository.shared.setDialogActive("02aaa", isActive: true)
|
|
|
|
#expect(InAppNotificationManager.shouldSuppress(senderKey: "02aaa") == true)
|
|
|
|
MessageRepository.shared.setDialogActive("02aaa", isActive: false)
|
|
}
|
|
|
|
@Test("Inactive chat is NOT suppressed")
|
|
func inactiveChatNotSuppressed() {
|
|
clearActiveDialogs()
|
|
#expect(InAppNotificationManager.shouldSuppress(senderKey: "02bbb") == false)
|
|
}
|
|
|
|
@Test("Only active chat suppressed, other chats shown")
|
|
func onlyActiveSuppressed() {
|
|
clearActiveDialogs()
|
|
MessageRepository.shared.setDialogActive("02aaa", isActive: true)
|
|
|
|
#expect(InAppNotificationManager.shouldSuppress(senderKey: "02aaa") == true)
|
|
#expect(InAppNotificationManager.shouldSuppress(senderKey: "02bbb") == false)
|
|
|
|
MessageRepository.shared.setDialogActive("02aaa", isActive: false)
|
|
}
|
|
|
|
// MARK: - Dialog Deactivation
|
|
|
|
@Test("After closing chat, notifications from it are no longer suppressed")
|
|
func deactivatedChatNotSuppressed() {
|
|
clearActiveDialogs()
|
|
MessageRepository.shared.setDialogActive("02aaa", isActive: true)
|
|
#expect(InAppNotificationManager.shouldSuppress(senderKey: "02aaa") == true)
|
|
|
|
MessageRepository.shared.setDialogActive("02aaa", isActive: false)
|
|
#expect(InAppNotificationManager.shouldSuppress(senderKey: "02aaa") == false)
|
|
}
|
|
|
|
// MARK: - Empty / Missing Sender Key
|
|
|
|
@Test("Empty sender key is suppressed (can't navigate to empty chat)")
|
|
func emptySenderKeySuppressed() {
|
|
clearActiveDialogs()
|
|
#expect(InAppNotificationManager.shouldSuppress(senderKey: "") == true)
|
|
}
|
|
|
|
// MARK: - Multiple Active Dialogs
|
|
|
|
@Test("Multiple active dialogs — each independently suppressed")
|
|
func multipleActiveDialogs() {
|
|
clearActiveDialogs()
|
|
MessageRepository.shared.setDialogActive("02aaa", isActive: true)
|
|
MessageRepository.shared.setDialogActive("02bbb", isActive: true)
|
|
|
|
#expect(InAppNotificationManager.shouldSuppress(senderKey: "02aaa") == true)
|
|
#expect(InAppNotificationManager.shouldSuppress(senderKey: "02bbb") == true)
|
|
#expect(InAppNotificationManager.shouldSuppress(senderKey: "02ccc") == false)
|
|
|
|
MessageRepository.shared.setDialogActive("02aaa", isActive: false)
|
|
MessageRepository.shared.setDialogActive("02bbb", isActive: false)
|
|
}
|
|
|
|
// MARK: - Muted Chat Suppression
|
|
|
|
@Test("Muted chat is suppressed")
|
|
func mutedChatSuppressed() {
|
|
clearActiveDialogs()
|
|
// Set up muted chat in App Group
|
|
let shared = UserDefaults(suiteName: "group.com.rosetta.dev")
|
|
let originalMuted = shared?.stringArray(forKey: "muted_chats_keys")
|
|
shared?.set(["02muted"], forKey: "muted_chats_keys")
|
|
|
|
#expect(InAppNotificationManager.shouldSuppress(senderKey: "02muted") == true)
|
|
|
|
// Restore
|
|
shared?.set(originalMuted, forKey: "muted_chats_keys")
|
|
}
|
|
|
|
@Test("Non-muted chat is NOT suppressed")
|
|
func nonMutedChatNotSuppressed() {
|
|
clearActiveDialogs()
|
|
let shared = UserDefaults(suiteName: "group.com.rosetta.dev")
|
|
let originalMuted = shared?.stringArray(forKey: "muted_chats_keys")
|
|
shared?.set(["02other"], forKey: "muted_chats_keys")
|
|
|
|
#expect(InAppNotificationManager.shouldSuppress(senderKey: "02notmuted") == false)
|
|
|
|
shared?.set(originalMuted, forKey: "muted_chats_keys")
|
|
}
|
|
|
|
// MARK: - Sender Key Extraction (AppDelegate)
|
|
|
|
@Test("extractSenderKey reads 'dialog' field first")
|
|
func extractSenderKeyDialog() {
|
|
let userInfo: [AnyHashable: Any] = ["dialog": "02aaa", "sender_public_key": "02bbb"]
|
|
let key = AppDelegate.extractSenderKey(from: userInfo)
|
|
#expect(key == "02aaa")
|
|
}
|
|
|
|
@Test("extractSenderKey falls back to 'sender_public_key'")
|
|
func extractSenderKeyFallback() {
|
|
let userInfo: [AnyHashable: Any] = ["sender_public_key": "02ccc"]
|
|
let key = AppDelegate.extractSenderKey(from: userInfo)
|
|
#expect(key == "02ccc")
|
|
}
|
|
|
|
@Test("extractSenderKey falls back to 'fromPublicKey'")
|
|
func extractSenderKeyFromPublicKey() {
|
|
let userInfo: [AnyHashable: Any] = ["fromPublicKey": "02ddd"]
|
|
let key = AppDelegate.extractSenderKey(from: userInfo)
|
|
#expect(key == "02ddd")
|
|
}
|
|
|
|
@Test("extractSenderKey returns empty for missing keys")
|
|
func extractSenderKeyEmpty() {
|
|
let userInfo: [AnyHashable: Any] = ["type": "personal_message"]
|
|
let key = AppDelegate.extractSenderKey(from: userInfo)
|
|
#expect(key == "")
|
|
}
|
|
}
|