Removing Delivered Notifications (#1305)

* completed

* changelog

* tests

* more tests

* better naming

* fix

* a bit more waiting time

* generated mocks

* xcodegen
This commit is contained in:
Mauro
2023-07-11 10:44:06 +02:00
committed by GitHub
parent 98dabe8500
commit 28fa1140b7
15 changed files with 245 additions and 8 deletions
+8
View File
@@ -10,6 +10,7 @@
0033481EE363E4914295F188 /* LocalizationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C070FD43DC6BF4E50217965A /* LocalizationTests.swift */; };
020F7E70167FB2833266F2F0 /* AnalyticsSettingsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = D39D7F513A36C9C1951DB44C /* AnalyticsSettingsScreen.swift */; };
02D8DF8EB7537EB4E9019DDB /* EventBasedTimelineItemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 218AB05B4E3889731959C5F1 /* EventBasedTimelineItemProtocol.swift */; };
02F4FAE40AF63A1941FD3BBA /* NotificationCenterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10B7F8EE25775DE2A305CBB5 /* NotificationCenterProtocol.swift */; };
037006FB6DF1374F94E4058D /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDCAC6CAAD65A2C24EA9C4B /* Dictionary.swift */; };
03D684A3AE85A23B3DA3B43F /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26747B3154A5DBC3A7E24A5 /* Image.swift */; };
0437765FF480249486893CC7 /* ScreenTrackerViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 196004E7695FBA292A7944AF /* ScreenTrackerViewModifier.swift */; };
@@ -566,6 +567,7 @@
C413D36D44F89DE63D3ADFA4 /* ReportContentScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = A433BE28B40D418237BE37B5 /* ReportContentScreen.swift */; };
C4180F418235DAD9DD173951 /* TemplateScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9873076F224E4CE09D8BD47D /* TemplateScreenUITests.swift */; };
C49FCC766673006B6D299F1C /* RoomDetailsEditScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DF8F7A3AD83D04C08D75E01 /* RoomDetailsEditScreenViewModelProtocol.swift */; };
C4C84901ABAC9B17564AB7EB /* NotificationName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4151163F666ED94FD959475A /* NotificationName.swift */; };
C4D2BCAA54E2C62B94B24AF4 /* InviteUsersScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E9B841EE4878283ECDB554 /* InviteUsersScreen.swift */; };
C4E0D03DF88242697545A9B7 /* UserIndicatorController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD1275D9CE0FFBA6E8E85426 /* UserIndicatorController.swift */; };
C4F69156C31A447FEFF2A47C /* DTHTMLElement+AttributedStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E508AB0EDEE017FF4F6F8D1 /* DTHTMLElement+AttributedStringBuilder.swift */; };
@@ -835,6 +837,7 @@
0FB782CE6176A5D2C082EC5D /* WelcomeScreenScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeScreenScreenModels.swift; sourceTree = "<group>"; };
1059E2AE7878CF7820592637 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
105B2A8426404EF66F00CFDB /* RoomTimelineItemFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemFactory.swift; sourceTree = "<group>"; };
10B7F8EE25775DE2A305CBB5 /* NotificationCenterProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationCenterProtocol.swift; sourceTree = "<group>"; };
10CC626F97AD70FF0420C115 /* RoomSummaryProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryProviderProtocol.swift; sourceTree = "<group>"; };
10F32E0B4B83D2A11EE8D011 /* InviteUsersScreenSelectedItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreenSelectedItem.swift; sourceTree = "<group>"; };
11151E78D6BB2B04A8FBD389 /* EmojiPickerScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreenViewModelProtocol.swift; sourceTree = "<group>"; };
@@ -964,6 +967,7 @@
3FFDA99C98BE05F43A92343B /* test_pdf.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = test_pdf.pdf; sourceTree = "<group>"; };
40B21E611DADDEF00307E7AC /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = "<group>"; };
4132F882A984ED971338EE9D /* ReportContentScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportContentScreenUITests.swift; sourceTree = "<group>"; };
4151163F666ED94FD959475A /* NotificationName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationName.swift; sourceTree = "<group>"; };
4176C3E20C772DE8D182863C /* LegalInformationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegalInformationScreen.swift; sourceTree = "<group>"; };
421E716C521F96D24ECE69B3 /* NoticeRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeRoomTimelineItem.swift; sourceTree = "<group>"; };
421FA93BCC2840E66E4F306F /* NotificationSettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsScreenViewModelProtocol.swift; sourceTree = "<group>"; };
@@ -2052,6 +2056,7 @@
C14D83B2B7CD5501A0089EFC /* LayoutDirection.swift */,
2AFEF3AC64B1358083F76B8B /* List.swift */,
23AA3F4B285570805CB0CCDD /* MapTiler.swift */,
4151163F666ED94FD959475A /* NotificationName.swift */,
F72EFC8C634469F9262659C7 /* NSItemProvider.swift */,
95BAC0F6C9644336E9567EE6 /* NSRegularExpresion.swift */,
7310D8DFE01AF45F0689C3AA /* Publisher.swift */,
@@ -3194,6 +3199,7 @@
6A580295A56B55A856CC4084 /* InfoPlistReader.swift */,
6AD1A853D605C2146B0DC028 /* MatrixEntityRegex.swift */,
C789E7BFC066CF39B8AE0974 /* NetworkMonitor.swift */,
10B7F8EE25775DE2A305CBB5 /* NotificationCenterProtocol.swift */,
F754E66A8970963B15B2A41E /* PermalinkBuilder.swift */,
53482ECA4B6633961EC224F5 /* ScrollViewAdapter.swift */,
DBA8DC95C079805B0B56E8A9 /* SharedUserDefaultsKeys.swift */,
@@ -4386,10 +4392,12 @@
0C58A846F61949B1D545D661 /* NoticeRoomTimelineItem.swift in Sources */,
9408CE8B8865C0C8DD4C9869 /* NoticeRoomTimelineItemContent.swift in Sources */,
368C8758FCD079E6AAA18C2C /* NoticeRoomTimelineView.swift in Sources */,
02F4FAE40AF63A1941FD3BBA /* NotificationCenterProtocol.swift in Sources */,
3F70E237CE4C3FAB02FC227F /* NotificationConstants.swift in Sources */,
CE9530A4CA661E090635C2F2 /* NotificationItemProxy.swift in Sources */,
652ACCF104A8CEF30788963C /* NotificationManager.swift in Sources */,
06D3942496E9E0E655F14D21 /* NotificationManagerProtocol.swift in Sources */,
C4C84901ABAC9B17564AB7EB /* NotificationName.swift in Sources */,
6786C4B0936AC84D993B20BF /* NotificationSettingsScreen.swift in Sources */,
F6DFA23885980118AD7359C5 /* NotificationSettingsScreenCoordinator.swift in Sources */,
D12F440F7973F1489F61389D /* NotificationSettingsScreenModels.swift in Sources */,
@@ -197,6 +197,25 @@ class BugReportServiceMock: BugReportServiceProtocol {
}
}
}
class NotificationCenterMock: NotificationCenterProtocol {
//MARK: - post
var postNameObjectCallsCount = 0
var postNameObjectCalled: Bool {
return postNameObjectCallsCount > 0
}
var postNameObjectReceivedArguments: (aName: NSNotification.Name, anObject: Any?)?
var postNameObjectReceivedInvocations: [(aName: NSNotification.Name, anObject: Any?)] = []
var postNameObjectClosure: ((NSNotification.Name, Any?) -> Void)?
func post(name aName: NSNotification.Name, object anObject: Any?) {
postNameObjectCallsCount += 1
postNameObjectReceivedArguments = (aName: aName, anObject: anObject)
postNameObjectReceivedInvocations.append((aName: aName, anObject: anObject))
postNameObjectClosure?(aName, anObject)
}
}
class NotificationManagerMock: NotificationManagerProtocol {
var delegate: NotificationManagerDelegate?
@@ -1365,6 +1384,39 @@ class UserNotificationCenterMock: UserNotificationCenterProtocol {
return requestAuthorizationOptionsReturnValue
}
}
//MARK: - deliveredNotifications
var deliveredNotificationsCallsCount = 0
var deliveredNotificationsCalled: Bool {
return deliveredNotificationsCallsCount > 0
}
var deliveredNotificationsReturnValue: [UNNotification]!
var deliveredNotificationsClosure: (() async -> [UNNotification])?
func deliveredNotifications() async -> [UNNotification] {
deliveredNotificationsCallsCount += 1
if let deliveredNotificationsClosure = deliveredNotificationsClosure {
return await deliveredNotificationsClosure()
} else {
return deliveredNotificationsReturnValue
}
}
//MARK: - removeDeliveredNotifications
var removeDeliveredNotificationsWithIdentifiersCallsCount = 0
var removeDeliveredNotificationsWithIdentifiersCalled: Bool {
return removeDeliveredNotificationsWithIdentifiersCallsCount > 0
}
var removeDeliveredNotificationsWithIdentifiersReceivedIdentifiers: [String]?
var removeDeliveredNotificationsWithIdentifiersReceivedInvocations: [[String]] = []
var removeDeliveredNotificationsWithIdentifiersClosure: (([String]) -> Void)?
func removeDeliveredNotifications(withIdentifiers identifiers: [String]) {
removeDeliveredNotificationsWithIdentifiersCallsCount += 1
removeDeliveredNotificationsWithIdentifiersReceivedIdentifiers = identifiers
removeDeliveredNotificationsWithIdentifiersReceivedInvocations.append(identifiers)
removeDeliveredNotificationsWithIdentifiersClosure?(identifiers)
}
//MARK: - setNotificationCategories
var setNotificationCategoriesCallsCount = 0
@@ -0,0 +1,22 @@
//
// Copyright 2023 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
extension Notification.Name {
static let roomMarkedAsRead = Notification.Name("roomMarkedAsRead")
static let invitesScreenAppeared = Notification.Name("invitesScreenAppeared")
}
@@ -0,0 +1,24 @@
//
// Copyright 2023 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
// sourcery: AutoMockable
protocol NotificationCenterProtocol: AnyObject {
func post(name aName: NSNotification.Name, object anObject: Any?)
}
extension NotificationCenter: NotificationCenterProtocol { }
@@ -48,4 +48,5 @@ struct InvitesScreenRoomDetails: Identifiable {
enum InvitesScreenViewAction {
case accept(InvitesScreenRoomDetails)
case decline(InvitesScreenRoomDetails)
case appeared
}
@@ -24,6 +24,7 @@ class InvitesScreenViewModel: InvitesScreenViewModelType, InvitesScreenViewModel
private let appSettings: AppSettings
private let analytics: AnalyticsService
private let userIndicatorController: UserIndicatorControllerProtocol
private let notificationCenterProtocol: NotificationCenterProtocol
private let previouslySeenInvites: Set<String>
private let actionsSubject: PassthroughSubject<InvitesScreenViewModelAction, Never> = .init()
@@ -36,11 +37,13 @@ class InvitesScreenViewModel: InvitesScreenViewModelType, InvitesScreenViewModel
init(userSession: UserSessionProtocol,
appSettings: AppSettings,
analytics: AnalyticsService,
userIndicatorController: UserIndicatorControllerProtocol) {
userIndicatorController: UserIndicatorControllerProtocol,
notificationCenterProtocol: NotificationCenterProtocol = NotificationCenter.default) {
self.userSession = userSession
self.appSettings = appSettings
self.analytics = analytics
self.userIndicatorController = userIndicatorController
self.notificationCenterProtocol = notificationCenterProtocol
previouslySeenInvites = appSettings.seenInvites
super.init(initialViewState: InvitesScreenViewState(), imageProvider: userSession.mediaProvider)
@@ -55,6 +58,8 @@ class InvitesScreenViewModel: InvitesScreenViewModelType, InvitesScreenViewModel
accept(invite: invite)
case .decline(let invite):
startDeclineFlow(invite: invite)
case .appeared:
notificationCenterProtocol.post(name: .invitesScreenAppeared, object: nil)
}
}
@@ -51,8 +51,11 @@ struct InvitesScreen: View {
noInvitesContent
}
}
.onAppear {
context.send(viewAction: .appeared)
}
}
private var noInvitesContent: some View {
Text(L10n.screenInvitesEmptyList)
.font(.compound.bodyLG)
@@ -33,18 +33,21 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
private let appSettings: AppSettings
private let analytics: AnalyticsService
private unowned let userIndicatorController: UserIndicatorControllerProtocol
private let notificationCenterProtocol: NotificationCenterProtocol
init(timelineController: RoomTimelineControllerProtocol,
mediaProvider: MediaProviderProtocol,
roomProxy: RoomProxyProtocol,
appSettings: AppSettings,
analytics: AnalyticsService,
userIndicatorController: UserIndicatorControllerProtocol) {
userIndicatorController: UserIndicatorControllerProtocol,
notificationCenterProtocol: NotificationCenterProtocol = NotificationCenter.default) {
self.roomProxy = roomProxy
self.timelineController = timelineController
self.appSettings = appSettings
self.analytics = analytics
self.userIndicatorController = userIndicatorController
self.notificationCenterProtocol = notificationCenterProtocol
super.init(initialViewState: RoomScreenViewState(roomId: timelineController.roomID,
roomTitle: roomProxy.roomTitle,
@@ -214,6 +217,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
}
private func markRoomAsRead() async {
notificationCenterProtocol.post(name: .roomMarkedAsRead, object: roomProxy.id)
_ = await timelineController.markRoomAsRead()
}
@@ -19,7 +19,7 @@ import Foundation
import UIKit
import UserNotifications
class NotificationManager: NSObject, NotificationManagerProtocol {
final class NotificationManager: NSObject, NotificationManagerProtocol {
private let notificationCenter: UserNotificationCenterProtocol
private let appSettings: AppSettings
@@ -31,6 +31,8 @@ class NotificationManager: NSObject, NotificationManagerProtocol {
appSettings: AppSettings) {
self.notificationCenter = notificationCenter
self.appSettings = appSettings
super.init()
addObservers()
}
// MARK: NotificationManagerProtocol
@@ -169,6 +171,47 @@ class NotificationManager: NSObject, NotificationManagerProtocol {
delegate?.unregisterForRemoteNotifications()
}
}
private func addObservers() {
NotificationCenter
.default
.publisher(for: .roomMarkedAsRead)
.sink { [weak self] notification in
guard let roomID = notification.object as? String else {
return
}
self?.removeMessageNotifications(for: roomID)
}
.store(in: &cancellables)
NotificationCenter
.default
.publisher(for: .invitesScreenAppeared)
.sink { [weak self] _ in
self?.removeInviteNotifications()
}
.store(in: &cancellables)
}
private func removeMessageNotifications(for roomID: String) {
Task {
let notificationsIdentifiers = await notificationCenter
.deliveredNotifications()
.filter { $0.request.content.roomID == roomID }
.map(\.request.identifier)
notificationCenter.removeDeliveredNotifications(withIdentifiers: notificationsIdentifiers)
}
}
private func removeInviteNotifications() {
Task {
let notificationsIdentifiers = await notificationCenter
.deliveredNotifications()
.filter { $0.request.content.categoryIdentifier == NotificationConstants.Category.invite }
.map(\.request.identifier)
notificationCenter.removeDeliveredNotifications(withIdentifiers: notificationsIdentifiers)
}
}
}
// MARK: - UNUserNotificationCenterDelegate
@@ -17,10 +17,14 @@
import Foundation
import UserNotifications
// Sadly we can't mock this because the delegate needs to be weak
// Use UserNotificationCenterSpy
protocol UserNotificationCenterProtocol: AnyObject {
var delegate: UNUserNotificationCenterDelegate? { get set }
func add(_ request: UNNotificationRequest) async throws
func requestAuthorization(options: UNAuthorizationOptions) async throws -> Bool
func deliveredNotifications() async -> [UNNotification]
func removeDeliveredNotifications(withIdentifiers identifiers: [String])
func setNotificationCategories(_ categories: Set<UNNotificationCategory>)
func authorizationStatus() async -> UNAuthorizationStatus
}
@@ -22,6 +22,7 @@ class InvitesScreenViewModelTests: XCTestCase {
var viewModel: InvitesScreenViewModelProtocol!
var clientProxy: MockClientProxy!
var userSession: MockUserSession!
var mockNotificationCenter: NotificationCenterMock!
var context: InvitesScreenViewModelType.Context {
viewModel.context
@@ -30,6 +31,7 @@ class InvitesScreenViewModelTests: XCTestCase {
override func setUpWithError() throws {
clientProxy = MockClientProxy(userID: "@a:b.com")
userSession = MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider())
mockNotificationCenter = NotificationCenterMock()
}
func testEmptyState() async throws {
@@ -72,6 +74,14 @@ class InvitesScreenViewModelTests: XCTestCase {
context.send(viewAction: .decline(.init(roomDetails: details, isUnread: false)))
XCTAssertNotNil(context.alertInfo)
}
func testHasAppeared() async {
setupViewModel()
context.send(viewAction: .appeared)
await Task.yield()
XCTAssertEqual(mockNotificationCenter.postNameObjectReceivedArguments?.aName, .invitesScreenAppeared)
}
// MARK: - Private
@@ -85,6 +95,7 @@ class InvitesScreenViewModelTests: XCTestCase {
viewModel = InvitesScreenViewModel(userSession: userSession,
appSettings: ServiceLocator.shared.settings,
analytics: ServiceLocator.shared.analytics,
userIndicatorController: ServiceLocator.shared.userIndicatorController)
userIndicatorController: ServiceLocator.shared.userIndicatorController,
notificationCenterProtocol: mockNotificationCenter)
}
}
@@ -14,9 +14,10 @@
// limitations under the License.
//
import Combine
import NotificationCenter
import XCTest
import Combine
@testable import ElementX
final class NotificationManagerTests: XCTestCase {
@@ -176,6 +177,32 @@ final class NotificationManagerTests: XCTestCase {
await notificationManager.userNotificationCenter(UNUserNotificationCenter.current(), didReceive: response)
XCTAssertTrue(notificationTappedDelegateCalled)
}
func test_MessageNotificationsRemoval() async throws {
// No interaction if the object is nil or of the wrong type
NotificationCenter.default.post(name: .roomMarkedAsRead, object: nil)
try await Task.sleep(for: .microseconds(200))
XCTAssertEqual(notificationCenter.deliveredNotificationsCallsCount, 0)
XCTAssertEqual(notificationCenter.removeDeliveredNotificationsCallsCount, 0)
NotificationCenter.default.post(name: .roomMarkedAsRead, object: 1)
try await Task.sleep(for: .microseconds(200))
XCTAssertEqual(notificationCenter.deliveredNotificationsCallsCount, 0)
XCTAssertEqual(notificationCenter.removeDeliveredNotificationsCallsCount, 0)
// The center calls the delivered and the removal functions when an id is passed
NotificationCenter.default.post(name: .roomMarkedAsRead, object: "RoomID")
try await Task.sleep(for: .microseconds(200))
XCTAssertEqual(notificationCenter.deliveredNotificationsCallsCount, 1)
XCTAssertEqual(notificationCenter.removeDeliveredNotificationsCallsCount, 1)
}
func test_InvitesNotificationsRemoval() async throws {
NotificationCenter.default.post(name: .invitesScreenAppeared, object: nil)
try await Task.sleep(for: .microseconds(200))
XCTAssertEqual(notificationCenter.deliveredNotificationsCallsCount, 1)
XCTAssertEqual(notificationCenter.removeDeliveredNotificationsCallsCount, 1)
}
}
extension NotificationManagerTests: NotificationManagerDelegate {
@@ -17,9 +17,20 @@
import Foundation
import UserNotifications
class UserNotificationCenterSpy: UserNotificationCenterProtocol {
final class UserNotificationCenterSpy: UserNotificationCenterProtocol {
weak var delegate: UNUserNotificationCenterDelegate?
var deliveredNotificationsCallsCount = 0
func deliveredNotifications() async -> [UNNotification] {
deliveredNotificationsCallsCount += 1
return []
}
var removeDeliveredNotificationsCallsCount = 0
func removeDeliveredNotifications(withIdentifiers identifiers: [String]) {
removeDeliveredNotificationsCallsCount += 1
}
var addRequest: UNNotificationRequest?
func add(_ request: UNNotificationRequest) async throws {
addRequest = request
@@ -349,6 +349,27 @@ class RoomScreenViewModelTests: XCTestCase {
await Task.yield()
XCTAssert(roomProxyMock.cancelSendTransactionIDCallsCount == 0)
}
func testMarkAsRead() async {
// Setup
let notificationCenterMock = NotificationCenterMock()
let timelineController = MockRoomTimelineController()
let roomProxyMock = RoomProxyMock(with: .init(displayName: ""))
let viewModel = RoomScreenViewModel(timelineController: timelineController,
mediaProvider: MockMediaProvider(),
roomProxy: roomProxyMock,
appSettings: ServiceLocator.shared.settings,
analytics: ServiceLocator.shared.analytics,
userIndicatorController: userIndicatorControllerMock,
notificationCenterProtocol: notificationCenterMock)
viewModel.context.send(viewAction: .markRoomAsRead)
await Task.yield()
XCTAssertEqual(notificationCenterMock.postNameObjectReceivedArguments?.aName, .roomMarkedAsRead)
let roomID = notificationCenterMock.postNameObjectReceivedArguments?.anObject as? String
XCTAssertEqual(roomID, roomProxyMock.id)
}
}
private extension TextRoomTimelineItem {
+1
View File
@@ -0,0 +1 @@
Push notifications for a room are cleared from the notification centre when opening its timeline. Same for invitations when opening the invite screen.