Skip to content

Commit f15eebb

Browse files
committed
Fix error handling in execute()
1 parent a934591 commit f15eebb

File tree

2 files changed

+67
-11
lines changed

2 files changed

+67
-11
lines changed

Sources/Action/Action.swift

+17-11
Original file line numberDiff line numberDiff line change
@@ -120,20 +120,26 @@ public final class Action<Input, Element> {
120120

121121
@discardableResult
122122
public func execute(_ value: Input) -> Observable<Element> {
123-
let subject = ReplaySubject<Element>.createUnbounded()
124-
125-
executionObservables
123+
defer {
124+
inputs.onNext(value)
125+
}
126+
127+
let execution = executionObservables
126128
.take(1)
127-
.flatMap { $0.catchError { _ in Observable.never() } }
128-
.bindTo(subject)
129-
.addDisposableTo(disposeBag)
129+
.flatMap { $0 }
130+
.catchError { throw ActionError.underlyingError($0) }
130131

131-
errors
132-
.map { throw $0 }
133-
.bindTo(subject)
134-
.addDisposableTo(disposeBag)
132+
let notEnabledError = inputs
133+
.takeUntil(executionObservables)
134+
.withLatestFrom(enabled)
135+
.flatMap { $0 ? Observable<Element>.empty() : Observable.error(ActionError.notEnabled) }
135136

136-
inputs.onNext(value)
137+
let subject = ReplaySubject<Element>.createUnbounded()
138+
Observable
139+
.of(execution, notEnabledError)
140+
.merge()
141+
.subscribe(subject)
142+
.addDisposableTo(disposeBag)
137143

138144
return subject.asObservable()
139145
}

Tests/ActionTests/ActionTests.swift

+50
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,56 @@ class ActionTests: QuickSpec {
473473
expect(executionObservables.events).to(beEmpty())
474474
}
475475
}
476+
477+
context("execute while executing") {
478+
var secondElement: TestableObserver<String>!
479+
var trigger: PublishSubject<Void>!
480+
481+
beforeEach {
482+
secondElement = scheduler.createObserver(String.self)
483+
trigger = PublishSubject<Void>()
484+
action = Action { Observable.just($0).sample(trigger) }
485+
486+
action.executionObservables
487+
.bindTo(executionObservables)
488+
.addDisposableTo(disposeBag)
489+
490+
scheduler.scheduleAt(10) {
491+
action.execute("a")
492+
.bindTo(element)
493+
.addDisposableTo(disposeBag)
494+
}
495+
496+
scheduler.scheduleAt(20) {
497+
action.execute("b")
498+
.bindTo(secondElement)
499+
.addDisposableTo(disposeBag)
500+
}
501+
502+
scheduler.scheduleAt(30) {
503+
trigger.onNext()
504+
}
505+
506+
scheduler.start()
507+
}
508+
509+
it("first element receives single value") {
510+
XCTAssertEqual(element.events, [
511+
next(30, "a"),
512+
completed(30),
513+
])
514+
}
515+
516+
it("second element fails with notEnabled error") {
517+
XCTAssertEqual(secondElement.events, [
518+
error(20, ActionError.notEnabled)
519+
])
520+
}
521+
522+
it("executes once") {
523+
expect(executionObservables.events.count) == 1
524+
}
525+
}
476526
}
477527
}
478528
}

0 commit comments

Comments
 (0)