import AppCore import ComposableArchitecture import CustomDump import HomeFeature import RestoreFeature import WelcomeFeature import XCTest import XXClient @testable import AppFeature final class AppFeatureTests: XCTestCase { func testStartWithoutMessengerCreated() { var actions: [Action] = [] let store = TestStore( initialState: AppState(), reducer: appReducer, environment: .unimplemented ) store.environment.mainQueue = .immediate store.environment.bgQueue = .immediate store.environment.dbManager.hasDB.run = { false } store.environment.messenger.isLoaded.run = { false } store.environment.messenger.isCreated.run = { false } store.environment.dbManager.makeDB.run = { actions.append(.didMakeDB) } store.environment.authHandler.run = { _ in actions.append(.didStartAuthHandler) return Cancellable {} } store.environment.messageListener.run = { _ in actions.append(.didStartMessageListener) return Cancellable {} } store.send(.start) store.receive(.set(\.$screen, .welcome(WelcomeState()))) { $0.screen = .welcome(WelcomeState()) } XCTAssertNoDifference(actions, [ .didMakeDB, .didStartAuthHandler, .didStartMessageListener, ]) store.send(.stop) } func testStartWithMessengerCreated() { var actions: [Action] = [] let store = TestStore( initialState: AppState(), reducer: appReducer, environment: .unimplemented ) store.environment.mainQueue = .immediate store.environment.bgQueue = .immediate store.environment.dbManager.hasDB.run = { false } store.environment.messenger.isLoaded.run = { false } store.environment.messenger.isCreated.run = { true } store.environment.dbManager.makeDB.run = { actions.append(.didMakeDB) } store.environment.messenger.load.run = { actions.append(.didLoadMessenger) } store.environment.authHandler.run = { _ in actions.append(.didStartAuthHandler) return Cancellable {} } store.environment.messageListener.run = { _ in actions.append(.didStartMessageListener) return Cancellable {} } store.send(.start) store.receive(.set(\.$screen, .home(HomeState()))) { $0.screen = .home(HomeState()) } XCTAssertNoDifference(actions, [ .didMakeDB, .didStartAuthHandler, .didStartMessageListener, .didLoadMessenger, ]) store.send(.stop) } func testWelcomeFinished() { var actions: [Action] = [] let store = TestStore( initialState: AppState( screen: .welcome(WelcomeState()) ), reducer: appReducer, environment: .unimplemented ) store.environment.mainQueue = .immediate store.environment.bgQueue = .immediate store.environment.dbManager.hasDB.run = { true } store.environment.messenger.isLoaded.run = { false } store.environment.messenger.isCreated.run = { true } store.environment.messenger.load.run = { actions.append(.didLoadMessenger) } store.environment.authHandler.run = { _ in actions.append(.didStartAuthHandler) return Cancellable {} } store.environment.messageListener.run = { _ in actions.append(.didStartMessageListener) return Cancellable {} } store.send(.welcome(.finished)) { $0.screen = .loading } store.receive(.set(\.$screen, .home(HomeState()))) { $0.screen = .home(HomeState()) } XCTAssertNoDifference(actions, [ .didStartAuthHandler, .didStartMessageListener, .didLoadMessenger, ]) store.send(.stop) } func testRestoreFinished() { var actions: [Action] = [] let store = TestStore( initialState: AppState( screen: .restore(RestoreState()) ), reducer: appReducer, environment: .unimplemented ) store.environment.mainQueue = .immediate store.environment.bgQueue = .immediate store.environment.dbManager.hasDB.run = { true } store.environment.messenger.isLoaded.run = { false } store.environment.messenger.isCreated.run = { true } store.environment.messenger.load.run = { actions.append(.didLoadMessenger) } store.environment.authHandler.run = { _ in actions.append(.didStartAuthHandler) return Cancellable {} } store.environment.messageListener.run = { _ in actions.append(.didStartMessageListener) return Cancellable {} } store.send(.restore(.finished)) { $0.screen = .loading } store.receive(.set(\.$screen, .home(HomeState()))) { $0.screen = .home(HomeState()) } XCTAssertNoDifference(actions, [ .didStartAuthHandler, .didStartMessageListener, .didLoadMessenger, ]) store.send(.stop) } func testHomeDidDeleteAccount() { var actions: [Action] = [] let store = TestStore( initialState: AppState( screen: .home(HomeState()) ), reducer: appReducer, environment: .unimplemented ) store.environment.mainQueue = .immediate store.environment.bgQueue = .immediate store.environment.dbManager.hasDB.run = { true } store.environment.messenger.isLoaded.run = { false } store.environment.messenger.isCreated.run = { false } store.environment.authHandler.run = { _ in actions.append(.didStartAuthHandler) return Cancellable {} } store.environment.messageListener.run = { _ in actions.append(.didStartMessageListener) return Cancellable {} } store.send(.home(.deleteAccount(.success))) { $0.screen = .loading } store.receive(.set(\.$screen, .welcome(WelcomeState()))) { $0.screen = .welcome(WelcomeState()) } XCTAssertNoDifference(actions, [ .didStartAuthHandler, .didStartMessageListener, ]) store.send(.stop) } func testWelcomeRestoreTapped() { let store = TestStore( initialState: AppState( screen: .welcome(WelcomeState()) ), reducer: appReducer, environment: .unimplemented ) store.send(.welcome(.restoreTapped)) { $0.screen = .restore(RestoreState()) } } func testWelcomeFailed() { let failure = "Something went wrong" let store = TestStore( initialState: AppState( screen: .welcome(WelcomeState()) ), reducer: appReducer, environment: .unimplemented ) store.send(.welcome(.failed(failure))) { $0.screen = .failure(failure) } } func testStartDatabaseMakeFailure() { struct Failure: Error {} let error = Failure() let store = TestStore( initialState: AppState(), reducer: appReducer, environment: .unimplemented ) store.environment.mainQueue = .immediate store.environment.bgQueue = .immediate store.environment.dbManager.hasDB.run = { false } store.environment.dbManager.makeDB.run = { throw error } store.send(.start) store.receive(.set(\.$screen, .failure(error.localizedDescription))) { $0.screen = .failure(error.localizedDescription) } store.send(.stop) } func testStartMessengerLoadFailure() { struct Failure: Error {} let error = Failure() var actions: [Action] = [] let store = TestStore( initialState: AppState(), reducer: appReducer, environment: .unimplemented ) store.environment.mainQueue = .immediate store.environment.bgQueue = .immediate store.environment.dbManager.hasDB.run = { true } store.environment.messenger.isLoaded.run = { false } store.environment.messenger.isCreated.run = { true } store.environment.messenger.load.run = { throw error } store.environment.authHandler.run = { _ in actions.append(.didStartAuthHandler) return Cancellable {} } store.environment.messageListener.run = { _ in actions.append(.didStartMessageListener) return Cancellable {} } store.send(.start) store.receive(.set(\.$screen, .failure(error.localizedDescription))) { $0.screen = .failure(error.localizedDescription) } XCTAssertNoDifference(actions, [ .didStartAuthHandler, .didStartMessageListener, ]) store.send(.stop) } func testStartHandlersAndListeners() { var actions: [Action] = [] var authHandlerOnError: [AuthCallbackHandler.OnError] = [] var messageListenerOnError: [MessageListenerHandler.OnError] = [] let store = TestStore( initialState: AppState(), reducer: appReducer, environment: .unimplemented ) store.environment.mainQueue = .immediate store.environment.bgQueue = .immediate store.environment.dbManager.hasDB.run = { true } store.environment.messenger.isLoaded.run = { true } store.environment.messenger.isCreated.run = { true } store.environment.authHandler.run = { onError in authHandlerOnError.append(onError) actions.append(.didStartAuthHandler) return Cancellable { actions.append(.didCancelAuthHandler) } } store.environment.messageListener.run = { onError in messageListenerOnError.append(onError) actions.append(.didStartMessageListener) return Cancellable { actions.append(.didCancelMessageListener) } } store.send(.start) store.receive(.set(\.$screen, .home(HomeState()))) { $0.screen = .home(HomeState()) } XCTAssertNoDifference(actions, [ .didStartAuthHandler, .didStartMessageListener, ]) actions = [] store.send(.start) { $0.screen = .loading } store.receive(.set(\.$screen, .home(HomeState()))) { $0.screen = .home(HomeState()) } XCTAssertNoDifference(actions, [ .didCancelAuthHandler, .didCancelMessageListener, .didStartAuthHandler, .didStartMessageListener, ]) actions = [] struct AuthError: Error {} authHandlerOnError.first?(AuthError()) XCTAssertNoDifference(actions, []) actions = [] struct MessageError: Error {} messageListenerOnError.first?(MessageError()) XCTAssertNoDifference(actions, []) actions = [] store.send(.stop) XCTAssertNoDifference(actions, [ .didCancelAuthHandler, .didCancelMessageListener, ]) } } private enum Action: Equatable { case didMakeDB case didStartAuthHandler case didStartMessageListener case didLoadMessenger case didCancelAuthHandler case didCancelMessageListener }