@testable import WMF @testable import Wikipedia import XCTest class NotificationsCenterViewModelTests: XCTestCase { enum TestError: Error { case failureSettingUpModelController case failurePullingFixtures case failureConvertingDataToNotificationsResult case failurePullingNetworkNotificationModels case failureSavingNetworkNotificationModelsToDatabase case failurePullingManagedObjectFromDatabase case failureConvertingManagedObjectToViewModel } var dataFileName: String { XCTFail("Must override dataFileName.") return "" } private var data: Data! private var networkModels: [RemoteNotificationsAPIController.NotificationsResult.Notification]! let dataStore = MWKDataStore.temporary() lazy var languageLinkController = { dataStore.languageLinkController }() lazy var configuration = { dataStore.configuration }() private let modelController: RemoteNotificationsModelController! = try? RemoteNotificationsModelController.temporaryModelController() override func setUp(completion: @escaping (Error?) -> Void) { if let gmtTimeZone = TimeZone(abbreviation: "GMT") { NSTimeZone.default = gmtTimeZone } guard modelController != nil else { completion(TestError.failureSettingUpModelController) return } if let data = wmf_bundle().wmf_data(fromContentsOfFile: dataFileName, ofType: "json") { self.data = data } else { completion(TestError.failurePullingFixtures) return } let decoder = JSONDecoder() let networkResult: RemoteNotificationsAPIController.NotificationsResult do { networkResult = try decoder.decode(RemoteNotificationsAPIController.NotificationsResult.self, from: data) } catch { completion(TestError.failureConvertingDataToNotificationsResult) return } guard let networkModels = networkResult.query?.notifications?.list, networkModels.count > 0 else { completion(TestError.failurePullingNetworkNotificationModels) return } self.networkModels = networkModels saveNetworkModels(networkModels: networkModels) { result in switch result { case .success: completion(nil) case .failure: completion(TestError.failureSavingNetworkNotificationModelsToDatabase) } } } override func tearDown(completion: @escaping (Error?) -> Void) { NSTimeZone.resetSystemTimeZone() completion(nil) } func fetchManagedObject(identifier: String) throws -> RemoteNotification { let predicate = NSPredicate(format: "id == %@", identifier) guard let managedObject = try? self.modelController.fetchNotifications(predicate: predicate).first else { throw TestError.failurePullingManagedObjectFromDatabase } return managedObject } func detailViewModelFromIdentifier(identifier: String) throws -> NotificationsCenterDetailViewModel { let notification = try fetchManagedObject(identifier: identifier) guard let apiIdentifier = notification.wiki, let project = WikimediaProject(notificationsApiIdentifier: apiIdentifier, languageLinkController: languageLinkController) else { throw TestError.failureConvertingManagedObjectToViewModel } let commonViewModel = NotificationsCenterCommonViewModel(configuration: configuration, notification: notification, project: project) return NotificationsCenterDetailViewModel(commonViewModel: commonViewModel) } private func saveNetworkModels(networkModels: [RemoteNotificationsAPIController.NotificationsResult.Notification], completion: @escaping (Result) -> Void) { let backgroundContext = modelController!.newBackgroundContext() modelController!.createNewNotifications(moc: backgroundContext, notificationsFetchedFromTheServer: Set(networkModels)) { result in DispatchQueue.main.async { switch result { case .success: completion(.success(())) case .failure(let error): completion(.failure(error)) } } } } func testActions(expectedText: String, expectedURL: URL?, expectedIcon: NotificationsCenterIconType?, expectedDestinationText: String?, actionToTest: NotificationsCenterAction, isMarkAsRead: Bool = false, isNotificationSettings: Bool = false, actionType: NotificationsCenterActionData.LoggingLabel?) throws { let expectedActionData = NotificationsCenterActionData(text: expectedText, url: expectedURL, iconType: expectedIcon, destinationText: expectedDestinationText, actionType: actionType) let expectedAction: NotificationsCenterAction if isMarkAsRead { expectedAction = NotificationsCenterAction.markAsReadOrUnread(expectedActionData) } else if isNotificationSettings { expectedAction = NotificationsCenterAction.notificationSubscriptionSettings(expectedActionData) } else { expectedAction = NotificationsCenterAction.custom(expectedActionData) } XCTAssertEqual(expectedAction, actionToTest, "Invalid action") XCTAssertEqual(expectedActionData.actionType?.stringValue, actionToTest.actionData?.actionType?.stringValue) } }