The below code works because of the do
operator on line 24. Is there a more functional way to get the test to pass, or would you consider this an appropriate use of do
?
import RxSwift
struct Token: Equatable {
let rawValue: String
static func ==(lhs: Token, rhs: Token) -> Bool {
return lhs.rawValue == rhs.rawValue
}
}
protocol Login {
func getCredentials() -> Observable<(email: String, password: String)>
func presentAuthFailure(_ error: Observable<Error>)
}
protocol Network {
func getAuthToken(credentials: (email: String, password: String)) -> Observable<Token>
}
// MARK: - function Under Test
func checkCredentials(login: Login, network: Network) -> Observable<Token> {
let credentials = login.getCredentials()
let token = credentials.flatMap { network.getAuthToken(credentials: $0) }
.do(onError: { login.presentAuthFailure(Observable.just($0)) }) // can this be done in some other way?
return token.retry()
}
// MARK: - Test harness
class MockLogin: Login {
func getCredentials() -> Observable<(email: String, password: String)> {
assert(_credentials == nil)
_credentials = PublishSubject()
return _credentials!
}
func presentAuthFailure(_ error: Observable<Error>) {
_ = error.subscribe(onNext: { [unowned self] error in
assert(self._error == nil)
self._error = error
})
}
var _credentials: PublishSubject<(email: String, password: String)>?
var _error: Error?
}
class MockNetwork: Network {
func getAuthToken(credentials: (email: String, password: String)) -> Observable<Token> {
assert(_token == nil)
_token = PublishSubject()
return _token!
}
var _token: PublishSubject<Token>?
}
func testTwoBadAttempts(login: MockLogin, network: MockNetwork) {
checkCredentials(login: login, network: network).subscribe()
assert(login._credentials != nil)
let credentials = (email: "foo", password: "bar")
login._credentials?.onNext(credentials)
assert(network._token != nil)
let error = NSError(domain: "testing", code: -1, userInfo: nil)
network._token?.onError(error)
assert(login._error != nil)
network._token = nil
login._error = nil
login._credentials?.onNext(credentials)
network._token?.onError(error)
assert(login._error != nil)
}
let login = MockLogin()
let network = MockNetwork()
testTwoBadAttempts(login: login, network: network)