Skip to content

Commit

Permalink
Add binding tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Qata committed Feb 16, 2021
1 parent f19821b commit 7f8ea98
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 10 deletions.
2 changes: 1 addition & 1 deletion Sources/RecombinePackage/Middleware.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public struct Middleware<State, Input, Output> {
public typealias Transform<Result> = (StatePublisher, Output) -> Result
internal let transform: Function

/// Create a blank slate Middleware.
/// Create a passthrough Middleware.
public init() where Input == Output {
self.transform = { Just($1).eraseToAnyPublisher() }
}
Expand Down
16 changes: 8 additions & 8 deletions Sources/RecombinePackage/Store/StoreProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,17 @@ public extension StoreProtocol {
}

public extension StoreProtocol {
/// Create a SwiftUI Binding from a `KeyPath` and a `SubRefinedAction`.
/// Create a SwiftUI Binding from a lensing function and a `SubRefinedAction`.
/// - Parameters:
/// - keyPath: A keypath to the state property.
/// - lens: A lens to the state property.
/// - action: The refined action which will be called when the value is changed.
/// - Returns: A `Binding` whose getter is the property and whose setter dispatches the refined action.
func binding<Value>(
state keyPath: KeyPath<SubState, Value>,
state lens: @escaping (SubState) -> Value,
actions transform: @escaping (Value) -> SubRefinedAction
) -> Binding<Value> {
.init(
get: { self.state[keyPath: keyPath] },
get: { lens(self.state) },
set: { self.dispatch(refined: transform($0)) }
)
}
Expand All @@ -107,15 +107,15 @@ public extension StoreProtocol {
)
}

/// Create a SwiftUI Binding from a `KeyPath` when the value of that path is equivalent to `SubRefinedAction`.
/// Create a SwiftUI Binding from a lensing function when the value of that function is equivalent to `SubRefinedAction`.
/// - Parameters:
/// - keyPath: A keypath to the state property.
/// - lens: A lens to the state property.
/// - Returns: A `Binding` whose getter is the property and whose setter dispatches the store's refined action.
func binding<Value>(
state keyPath: KeyPath<SubState, Value>
state lens: @escaping (SubState) -> Value
) -> Binding<Value> where SubRefinedAction == Value {
.init(
get: { self.state[keyPath: keyPath] },
get: { lens(self.state) },
set: { self.dispatch(refined: $0) }
)
}
Expand Down
42 changes: 41 additions & 1 deletion Tests/RecombineTests/StoreTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ class StoreTests: XCTestCase {
middleware: .init(),
publishOn: ImmediateScheduler.shared
)
let subStore = store.lensing(state: \.subState.value, actions: TestFakes.NestedTest.Action.sub)
let subStore = store.lensing(
state: \.subState.value,
actions: TestFakes.NestedTest.Action.sub
)
let stateRecorder = subStore.$state.dropFirst().record()
let actionsRecorder = subStore.actions.record()

Expand All @@ -43,6 +46,43 @@ class StoreTests: XCTestCase {
let actions = try wait(for: actionsRecorder.prefix(1), timeout: 1)
XCTAssertEqual(actions, [.set(string)])
}

func testBinding() throws {
let store = BaseStore(
state: TestFakes.NestedTest.State(),
reducer: TestFakes.NestedTest.reducer,
middleware: .init(),
publishOn: ImmediateScheduler.shared
)
let binding1 = store.binding(
state: \.subState.value,
actions: { .sub(.set("\($0)1")) }
)
let binding2 = store.lensing(
state: \.subState.value
).binding(
actions: { .sub(.set("\($0)2")) }
)
let binding3 = store.lensing(
state: \.subState,
actions: { .sub(.set("\($0)3")) }
).binding(
state: \.value
)
let stateRecorder = store.$state.dropFirst().record()

let string = "Oh Yeah!"

binding1.wrappedValue = string
binding2.wrappedValue = string
binding3.wrappedValue = string

let state = try wait(for: stateRecorder.prefix(3), timeout: 1)
XCTAssertEqual(
state.map(\.subState.value),
zip(repeatElement(string, count: 3), 1...).map { "\($0)\($1)" }
)
}
}

// Used for deinitialization test
Expand Down

0 comments on commit 7f8ea98

Please sign in to comment.