Skip to content

Commit

Permalink
Fix setBy when CompositeAction used
Browse files Browse the repository at this point in the history
Now if used Composite action in state.setBy will be displayed actual action, not CompositeAction
  • Loading branch information
reloni committed Mar 12, 2017
1 parent b404747 commit 1cf56fe
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 11 deletions.
23 changes: 12 additions & 11 deletions RxDataFlow/RxDataFlowController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,31 +89,32 @@ public final class RxDataFlowController<State: RxStateType> : RxDataFlowControll
actionsQueue.currentItemSubject.observeOn(scheduler)
.flatMap { [weak self] action -> Observable<Void> in
guard let object = self else { return Observable.empty() }

return object.observe(action: action)
return object.observe(action: action)
}.subscribe().addDisposableTo(bag)
}
private func observe(action: RxActionType) -> Observable<Void> {
let object = self
let handle: Observable<RxStateType> = {
let handle: Observable<(setBy: RxActionType, state: RxStateType)> = {
guard let compositeAction = action as? RxCompositeAction else {
return Observable.from([action], scheduler: action.scheduler ?? object.scheduler)
.flatMap { a -> Observable<RxStateType> in object.reducer.handle(action, flowController: object).subscribeOn(action.scheduler ?? object.scheduler) }
return Observable<RxActionType>.from([action], scheduler: action.scheduler ?? object.scheduler)
.flatMap { act in object.reducer.handle(act, flowController: object).subscribeOn(act.scheduler ?? object.scheduler) }
.flatMap { result -> Observable<(setBy: RxActionType, state: RxStateType)> in return .just((setBy: action, state: result)) }
}
return object.observe(compositeAction: compositeAction)
}()

return handle
.do(onNext: { object.currentStateSubject.onNext((setBy: action, state: $0 as! State)) },
.do(onNext: { object.currentStateSubject.onNext((setBy: $0.setBy, state: $0.state as! State)) },
onError: { object.errorsSubject.onNext((state: object.currentState.state, action: action, error: $0)) },
onDispose: { _ in _ = object.actionsQueue.dequeue() })
.flatMap { result -> Observable<RxStateType?> in .just(result) }
.flatMap { result -> Observable<RxStateType?> in .just(result.state) }
.catchErrorJustReturn(nil)
.flatMap { _ in return Observable<Void>.just() }
}

func observe(compositeAction action: RxCompositeAction) -> Observable<RxStateType> {
func observe(compositeAction action: RxCompositeAction) -> Observable<(setBy: RxActionType, state: RxStateType)> {
return Observable.create { [weak self] observer in
guard let object = self else { return Disposables.create() }

Expand All @@ -122,8 +123,8 @@ public final class RxDataFlowController<State: RxStateType> : RxDataFlowControll
let disposable = compositeQueue.currentItemSubject.observeOn(object.scheduler).flatMap { action -> Observable<RxStateType> in
return Observable.create { _ in
let subscribsion = Observable.from([action], scheduler: action.scheduler ?? object.scheduler)
.flatMap { a -> Observable<RxStateType> in object.reducer.handle(action, flowController: object).subscribeOn(action.scheduler ?? object.scheduler) }
.do(onNext: { observer.onNext($0) },
.flatMap { act -> Observable<RxStateType> in object.reducer.handle(act, flowController: object).subscribeOn(act.scheduler ?? object.scheduler) }
.do(onNext: { observer.onNext((setBy: action, state: $0)) },
onError: { observer.onError($0) },
onCompleted: { _ = compositeQueue.dequeue() },
onDispose: { if compositeQueue.count == 0 { observer.onCompleted() } })
Expand Down
35 changes: 35 additions & 0 deletions RxDataFlowTests/CompositeActionsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,41 @@ class CompositeActions: XCTestCase {
XCTAssertEqual(expectedStateHistoryTextValues, store.stateStack.array.flatMap { $0 }.map { $0.state.text })
}

func testCorrectSetByAction() {
let store = RxDataFlowController(reducer: TestStoreReducer(),
initialState: TestState(text: "Initial value"))

let completeExpectation = expectation(description: "Should perform all non-error actions")
_ = store.state.filter { $0.setBy is CompletionAction }.subscribe(onNext: { next in
completeExpectation.fulfill()
})

let changeTextValueActionExpectation = expectation(description: "Should perform ChangeTextValueAction with correct setBy")
let customDescriptorActionExpectation = expectation(description: "Should perform CustomDescriptorAction with correct setBy")
_ = store.state.subscribe(onNext: { next in
if next.setBy is ChangeTextValueAction {
changeTextValueActionExpectation.fulfill()
} else if next.setBy is CustomDescriptorAction {
customDescriptorActionExpectation.fulfill()
}
})

let action = RxCompositeAction(actions: [ChangeTextValueAction(newText: "Action 1 executed"),
CustomDescriptorAction(scheduler: nil, descriptor: .just((TestState(text: "Action 2 executed"))))])
store.dispatch(action)
store.dispatch(CompletionAction())

waitForExpectations(timeout: 1, handler: nil)

let expectedStateHistoryTextValues = ["Initial value",
"Action 1 executed",
"Action 2 executed",
"Completed"]

XCTAssertEqual(expectedStateHistoryTextValues, store.stateStack.array.flatMap { $0 }.map { $0.state.text })
XCTAssertTrue(store.currentState.setBy is CompletionAction)
}

func testCompositeActionStopIfErrorOccurred() {
let store = RxDataFlowController(reducer: TestStoreReducer(),
initialState: TestState(text: "Initial value"))
Expand Down

0 comments on commit 1cf56fe

Please sign in to comment.