Files
element-x-ios/UnitTests/Sources/NotificationContentBuilderTests.swift
T
Doug 64aae09c6d Add an AccountProvider type and use it within the authentication flow. (#6103)
* Add an AccountProvider type and use it within AppSettings.

* Use the AccountProvider type within the Authentication flow too.

* Fix unit test compilation with Swift 6.4

* Make sure defaultAccountProvider takes allowOtherAccountProviders into account.

* Document a caveat on using AuthenticationService.homeserver.value.accountProvider.
2026-09-14 15:25:33 +01:00

301 lines
19 KiB
Swift

//
// Copyright 2025 Element Creations Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
// Please see LICENSE files in the repository root for full details.
//
import Dynamic
@testable import ElementX
import MatrixRustSDK
import MatrixRustSDKMocks
import Testing
import UserNotifications
nonisolated struct NotificationContentBuilderTests {
var notificationContentBuilder: NotificationContentBuilder
var mediaProvider: MediaProviderMock
var notificationContent: UNMutableNotificationContent
init() async {
notificationContent = .init()
let stringBuilder = RoomMessageEventStringBuilder(attributedStringBuilder: AttributedStringBuilder(mentionBuilder: PlainMentionBuilder()),
style: .plain)
mediaProvider = MediaProviderMock(.init())
notificationContentBuilder = await NotificationContentBuilder(messageEventStringBuilder: stringBuilder,
notificationSoundName: UNNotificationSoundName("message.caf"),
userSession: NSEUserSessionMock(.init()))
}
@Test
mutating func dmMessageNotification() async {
let notificationItem = NotificationItemProxyMock(.init(roomID: "!test:matrix.org",
receiverID: "@bob:matrix.org",
senderDisplayName: "Alice",
roomDisplayName: "Alice",
roomJoinedMembers: 2,
isRoomDirect: true,
isRoomPrivate: true,
isNoisy: true))
await notificationContentBuilder.process(notificationContent: &notificationContent,
notificationItem: notificationItem,
mediaProvider: mediaProvider)
let communicationContext = Dynamic(notificationContent, memberName: "communicationContext")
// Checking if nil without using asObject always fails
#expect(communicationContext.displayName.asObject == nil)
#expect(communicationContext.sender.displayName == "Alice")
#expect(notificationContent.body == "Hello world!")
#expect(notificationContent.categoryIdentifier == NotificationConstants.Category.message)
#expect(notificationContent.threadRootEventID == nil)
#expect(notificationContent.sound != nil)
// Remember we remove the @ due to an iOS bug
#expect(notificationContent.threadIdentifier == "bob:matrix.org!test:matrix.org")
#expect(notificationContent.attachments == [])
}
@Test
mutating func dmMessageNotificationWithMention() async {
let notificationItem = NotificationItemProxyMock(.init(roomID: "!test:matrix.org",
receiverID: "@bob:matrix.org",
senderDisplayName: "Alice",
roomDisplayName: "Alice",
roomJoinedMembers: 2,
isRoomDirect: true,
isRoomPrivate: true,
isNoisy: true,
hasMention: true))
await notificationContentBuilder.process(notificationContent: &notificationContent,
notificationItem: notificationItem,
mediaProvider: mediaProvider)
let communicationContext = Dynamic(notificationContent, memberName: "communicationContext")
// Checking if nil without using asObject always fails
#expect(communicationContext.displayName.asObject == nil)
#expect(communicationContext.sender.displayName == L10n.notificationSenderMentionReply("Alice"))
#expect(notificationContent.body == "Hello world!")
#expect(notificationContent.categoryIdentifier == NotificationConstants.Category.message)
#expect(notificationContent.threadRootEventID == nil)
#expect(notificationContent.sound != nil)
// Remember we remove the @ due to an iOS bug
#expect(notificationContent.threadIdentifier == "bob:matrix.org!test:matrix.org")
#expect(notificationContent.attachments == [])
}
@Test
mutating func dmMessageNotificationWithThread() async {
let notificationItem = NotificationItemProxyMock(.init(roomID: "!test:matrix.org",
receiverID: "@bob:matrix.org",
senderDisplayName: "Alice",
roomDisplayName: "Alice",
roomJoinedMembers: 2,
isRoomDirect: true,
isRoomPrivate: true,
isNoisy: true,
hasMention: false,
threadRootEventID: "thread"))
await notificationContentBuilder.process(notificationContent: &notificationContent,
notificationItem: notificationItem,
mediaProvider: mediaProvider)
let communicationContext = Dynamic(notificationContent, memberName: "communicationContext")
#expect(communicationContext.displayName == L10n.commonThread)
#expect(communicationContext.sender.displayName == "Alice")
#expect(notificationContent.body == "Hello world!")
#expect(notificationContent.categoryIdentifier == NotificationConstants.Category.message)
#expect(notificationContent.threadRootEventID != nil)
#expect(notificationContent.sound != nil)
// Remember we remove the @ due to an iOS bug
#expect(notificationContent.threadIdentifier == "bob:matrix.org!test:matrix.orgthread")
#expect(notificationContent.attachments == [])
}
@Test
mutating func dmMessageNotificationWithThreadAndMention() async {
let notificationItem = NotificationItemProxyMock(.init(roomID: "!test:matrix.org",
receiverID: "@bob:matrix.org",
senderDisplayName: "Alice",
roomDisplayName: "Alice",
roomJoinedMembers: 2,
isRoomDirect: true,
isRoomPrivate: true,
isNoisy: true,
hasMention: true,
threadRootEventID: "thread"))
await notificationContentBuilder.process(notificationContent: &notificationContent,
notificationItem: notificationItem,
mediaProvider: mediaProvider)
let communicationContext = Dynamic(notificationContent, memberName: "communicationContext")
#expect(communicationContext.displayName == L10n.commonThread)
#expect(communicationContext.sender.displayName == L10n.notificationSenderMentionReply("Alice"))
#expect(notificationContent.body == "Hello world!")
#expect(notificationContent.categoryIdentifier == NotificationConstants.Category.message)
#expect(notificationContent.threadRootEventID != nil)
#expect(notificationContent.sound != nil)
// Remember we remove the @ due to an iOS bug
#expect(notificationContent.threadIdentifier == "bob:matrix.org!test:matrix.orgthread")
#expect(notificationContent.attachments == [])
}
@Test
mutating func roomMessageNotification() async {
let notificationItem = NotificationItemProxyMock(.init(roomID: "!testroom:matrix.org",
receiverID: "@bob:matrix.org",
senderDisplayName: "Alice",
roomDisplayName: "General",
roomJoinedMembers: 5,
isRoomDirect: false,
isRoomPrivate: false,
isNoisy: false))
await notificationContentBuilder.process(notificationContent: &notificationContent,
notificationItem: notificationItem,
mediaProvider: mediaProvider)
let communicationContext = Dynamic(notificationContent, memberName: "communicationContext")
#expect(communicationContext.displayName == "General")
#expect(communicationContext.sender.displayName == "Alice")
#expect(notificationContent.body == "Hello world!")
#expect(notificationContent.categoryIdentifier == NotificationConstants.Category.message)
#expect(notificationContent.threadRootEventID == nil)
#expect(notificationContent.sound == nil)
// Remember we remove the @ due to an iOS bug
#expect(notificationContent.threadIdentifier == "bob:matrix.org!testroom:matrix.org")
#expect(notificationContent.attachments == [])
}
@Test
mutating func roomMessageNotificationWithMention() async {
let notificationItem = NotificationItemProxyMock(.init(roomID: "!testroom:matrix.org",
receiverID: "@bob:matrix.org",
senderDisplayName: "Alice",
roomDisplayName: "General",
roomJoinedMembers: 5,
isRoomDirect: false,
isRoomPrivate: false,
isNoisy: true,
hasMention: true))
await notificationContentBuilder.process(notificationContent: &notificationContent,
notificationItem: notificationItem,
mediaProvider: mediaProvider)
let communicationContext = Dynamic(notificationContent, memberName: "communicationContext")
#expect(communicationContext.displayName == "General")
#expect(communicationContext.sender.displayName == L10n.notificationSenderMentionReply("Alice"))
#expect(notificationContent.body == "Hello world!")
#expect(notificationContent.categoryIdentifier == NotificationConstants.Category.message)
#expect(notificationContent.threadRootEventID == nil)
#expect(notificationContent.sound != nil)
#expect(notificationContent.threadIdentifier == "bob:matrix.org!testroom:matrix.org")
#expect(notificationContent.attachments == [])
}
@Test
mutating func roomMessageNotificationWithThread() async {
let notificationItem = NotificationItemProxyMock(.init(roomID: "!testroom:matrix.org",
receiverID: "@bob:matrix.org",
senderDisplayName: "Alice",
roomDisplayName: "General",
roomJoinedMembers: 5,
isRoomDirect: false,
isRoomPrivate: false,
isNoisy: false,
threadRootEventID: "thread123"))
await notificationContentBuilder.process(notificationContent: &notificationContent,
notificationItem: notificationItem,
mediaProvider: mediaProvider)
let communicationContext = Dynamic(notificationContent, memberName: "communicationContext")
#expect(communicationContext.displayName == L10n.notificationThreadInRoom("General"))
#expect(communicationContext.sender.displayName == "Alice")
#expect(notificationContent.body == "Hello world!")
#expect(notificationContent.categoryIdentifier == NotificationConstants.Category.message)
#expect(notificationContent.threadRootEventID != nil)
#expect(notificationContent.sound == nil)
#expect(notificationContent.threadIdentifier == "bob:matrix.org!testroom:matrix.orgthread123")
#expect(notificationContent.attachments == [])
}
@Test
mutating func liveLocationStartNotification() async {
let event = TimelineEventSDKMock()
event.eventIdReturnValue = UUID().uuidString
event.contentReturnValue = .state(content: .beaconInfo)
let notificationItem = NotificationItemProxyMock(.init(event: .timeline(event: event),
roomID: "!test:matrix.org",
receiverID: "@bob:matrix.org",
senderDisplayName: "Alice",
roomDisplayName: "Alice",
roomJoinedMembers: 2,
isRoomDirect: true,
isRoomPrivate: true,
isNoisy: true))
await notificationContentBuilder.process(notificationContent: &notificationContent,
notificationItem: notificationItem,
mediaProvider: mediaProvider)
let communicationContext = Dynamic(notificationContent, memberName: "communicationContext")
#expect(communicationContext.sender.displayName == "Alice")
#expect(notificationContent.body == L10n.notificationLiveLocationStartedBody)
#expect(notificationContent.categoryIdentifier == NotificationConstants.Category.message)
#expect(notificationContent.sound != nil)
}
@Test
mutating func otherStateEventNotification() async {
let event = TimelineEventSDKMock()
event.eventIdReturnValue = UUID().uuidString
event.contentReturnValue = .state(content: .roomName)
let notificationItem = NotificationItemProxyMock(.init(event: .timeline(event: event),
roomID: "!test:matrix.org",
receiverID: "@bob:matrix.org",
senderDisplayName: "Alice",
roomDisplayName: "Alice",
roomJoinedMembers: 2,
isRoomDirect: true,
isRoomPrivate: true,
isNoisy: true))
await notificationContentBuilder.process(notificationContent: &notificationContent,
notificationItem: notificationItem,
mediaProvider: mediaProvider)
#expect(notificationContent.body == L10n.notification)
}
@Test
mutating func roomMessageNotificationWithThreadAndMention() async {
let notificationItem = NotificationItemProxyMock(.init(roomID: "!testroom:matrix.org",
receiverID: "@bob:matrix.org",
senderDisplayName: "Alice",
roomDisplayName: "General",
roomJoinedMembers: 5,
isRoomDirect: false,
isRoomPrivate: false,
isNoisy: true,
hasMention: true,
threadRootEventID: "thread123"))
await notificationContentBuilder.process(notificationContent: &notificationContent,
notificationItem: notificationItem,
mediaProvider: mediaProvider)
let communicationContext = Dynamic(notificationContent, memberName: "communicationContext")
#expect(communicationContext.displayName == L10n.notificationThreadInRoom("General"))
#expect(communicationContext.sender.displayName == L10n.notificationSenderMentionReply("Alice"))
#expect(notificationContent.body == "Hello world!")
#expect(notificationContent.categoryIdentifier == NotificationConstants.Category.message)
#expect(notificationContent.threadRootEventID != nil)
#expect(notificationContent.sound != nil)
#expect(notificationContent.threadIdentifier == "bob:matrix.org!testroom:matrix.orgthread123")
#expect(notificationContent.attachments == [])
}
}