RIBsTests/Interactor/InteractorTests.swift (109 lines of code) (raw):

// // InteractorTests.swift // RIBs // // Created by Alex Bush on 6/22/25. // @testable import RIBs import XCTest import RxSwift final class InteractorTests: XCTestCase { private var interactor: InteractorMock! override func setUp() { super.setUp() interactor = InteractorMock() // NOTE: we're using InteractorMock here to test the underlying parent class, Interactor, behavior so this is appropriate here. } func test_interactorIsInactiveByDefault() { XCTAssertFalse(interactor.isActive) let _ = interactor.isActiveStream.subscribe { isActive in XCTAssertFalse(isActive) } } func test_isActive_whenStarted_isTrue() { // give // when interactor.activate() // then XCTAssertTrue(interactor.isActive) let _ = interactor.isActiveStream.subscribe { isActive in XCTAssertTrue(isActive) } } func test_isActive_whenDeactivated_isFalse() { // given interactor.activate() // when interactor.deactivate() // then XCTAssertFalse(interactor.isActive) let _ = interactor.isActiveStream.subscribe { isActive in XCTAssertFalse(isActive) } } func test_didBecomeActive_isCalledWhenStarted() { // given // when interactor.activate() // then XCTAssertEqual(interactor.didBecomeActiveCallCount, 1) } func test_didBecomeActive_isNotCalledWhenAlreadyActive() { // given interactor.activate() XCTAssertEqual(interactor.didBecomeActiveCallCount, 1) // when interactor.activate() // then XCTAssertEqual(interactor.didBecomeActiveCallCount, 1) } func test_willResignActive_isCalledWhenDeactivated() { // given interactor.activate() // when interactor.deactivate() // then XCTAssertEqual(interactor.willResignActiveCallCount, 1) } func test_willResignActive_isNotCalledWhenAlreadyInactive() { // given interactor.activate() interactor.deactivate() XCTAssertEqual(interactor.willResignActiveCallCount, 1) // when interactor.deactivate() // then XCTAssertEqual(interactor.willResignActiveCallCount, 1) } func test_isActiveStream_completedOnInteractorDeinit() { // given var isActiveStreamCompleted = false interactor.activate() let _ = interactor.isActiveStream.subscribe { _ in } onCompleted: { isActiveStreamCompleted = true } // when interactor = nil // then XCTAssertTrue(isActiveStreamCompleted) } // MARK: - BEGIN Observables Attached/Detached to/from Interactor func test_observableAttachedToInactiveInteactorIsDisposedImmediately() { // given var onDisposeCalled = false let subjectEmiitingValues: PublishSubject<Int> = .init() let observable = subjectEmiitingValues.asObservable().do { _ in } onDispose: { onDisposeCalled = true } // when observable.subscribe().disposeOnDeactivate(interactor: interactor) // then XCTAssertTrue(onDisposeCalled) } func test_observableIsDisposedOnInteractorDeactivation() { // given var onDisposeCalled = false let subjectEmiitingValues: PublishSubject<Int> = .init() let observable = subjectEmiitingValues.asObservable().do { _ in } onDispose: { onDisposeCalled = true } interactor.activate() observable.subscribe().disposeOnDeactivate(interactor: interactor) // when interactor.deactivate() // then XCTAssertTrue(onDisposeCalled) } func test_observableIsDisposedOnInteractorDeinit() { // given var onDisposeCalled = false let subjectEmiitingValues: PublishSubject<Int> = .init() let observable = subjectEmiitingValues.asObservable().do { _ in } onDispose: { onDisposeCalled = true } interactor.activate() observable.subscribe().disposeOnDeactivate(interactor: interactor) XCTAssertFalse(onDisposeCalled) // when interactor = nil // then XCTAssertTrue(onDisposeCalled) } // MARK: Observables Attached/Detached to/from Interactor END - // MARK: - BEGIN Observables Confined to Interactor func test_observableConfinedToInteractorOnlyEmitsValueWhenInteractorIsActive() { // given var emittedValue: Int? let subjectEmiitingValues: PublishSubject<Int> = .init() let confinedObservable = subjectEmiitingValues.asObservable().confineTo(interactor) let _ = confinedObservable.confineTo(interactor) let _ = confinedObservable.subscribe { newValue in emittedValue = newValue } subjectEmiitingValues.onNext(1) XCTAssertNil(emittedValue) // when interactor.activate() subjectEmiitingValues.onNext(2) // then XCTAssertNotNil(emittedValue) XCTAssertEqual(emittedValue, 2) } // MARK: Observables Confined to Interactor - }