diff --git a/Workflow/Sources/AnyWorkflow.swift b/Workflow/Sources/AnyWorkflow.swift index a142b534b..4dacd7f97 100644 --- a/Workflow/Sources/AnyWorkflow.swift +++ b/Workflow/Sources/AnyWorkflow.swift @@ -91,7 +91,7 @@ extension AnyWorkflow { /// That type information *is* present in our storage object, however, so we /// pass the context down to that storage object which will ultimately call /// through to `context.render(workflow:key:reducer:)`. - internal func render(context: RenderContext, key: String, outputMap: @escaping (Output) -> Action) -> Rendering where Action: WorkflowAction, Action.WorkflowType == Parent { + internal func render(context: RenderContext, key: String, outputMap: @escaping (Output) -> Action) -> Rendering where Action: WorkflowActionCore, Action.WorkflowType == Parent { return storage.render(context: context, key: key, outputMap: outputMap) } } @@ -103,7 +103,7 @@ extension AnyWorkflow { fileprivate class AnyStorage { var base: Any { fatalError() } - func render(context: RenderContext, key: String, outputMap: @escaping (Output) -> Action) -> Rendering where Action: WorkflowAction, Action.WorkflowType == Parent { + func render(context: RenderContext, key: String, outputMap: @escaping (Output) -> Action) -> Rendering where Action: WorkflowActionCore, Action.WorkflowType == Parent { fatalError() } @@ -140,7 +140,7 @@ extension AnyWorkflow { return T.self } - override func render(context: RenderContext, key: String, outputMap: @escaping (Output) -> Action) -> Rendering where Action: WorkflowAction, Action.WorkflowType == Parent { + override func render(context: RenderContext, key: String, outputMap: @escaping (Output) -> Action) -> Rendering where Action: WorkflowActionCore, Action.WorkflowType == Parent { let outputMap: (T.Output) -> Action = { [outputTransform] output in outputMap(outputTransform(output)) } diff --git a/Workflow/Sources/AnyWorkflowConvertible.swift b/Workflow/Sources/AnyWorkflowConvertible.swift index 6a78eed44..92c82423f 100644 --- a/Workflow/Sources/AnyWorkflowConvertible.swift +++ b/Workflow/Sources/AnyWorkflowConvertible.swift @@ -37,11 +37,11 @@ extension AnyWorkflowConvertible { /// - Parameter key: A string that uniquely identifies this workflow. /// /// - Returns: The `Rendering` generated by the workflow. - public func rendered(in context: RenderContext, key: String = "") -> Rendering where Output: WorkflowAction, Output.WorkflowType == Parent { + public func rendered(in context: RenderContext, key: String = "") -> Rendering where Output: WorkflowActionCore, Output.WorkflowType == Parent { return asAnyWorkflow().render(context: context, key: key, outputMap: { $0 }) } - public func rendered(in context: RenderContext, key: String = "", outputMap: @escaping (Output) -> Action) -> Rendering where Action: WorkflowAction, Action.WorkflowType == Parent { + public func rendered(in context: RenderContext, key: String = "", outputMap: @escaping (Output) -> Action) -> Rendering where Action: WorkflowActionCore, Action.WorkflowType == Parent { return asAnyWorkflow().render(context: context, key: key, outputMap: { outputMap($0) }) } @@ -73,12 +73,12 @@ extension AnyWorkflowConvertible where Output == Never { } extension AnyWorkflowConvertible where Rendering == Void { - public func running(in context: RenderContext, key: String = "", outputMap: @escaping (Output) -> Action) where Action: WorkflowAction, Action.WorkflowType == Parent { + public func running(in context: RenderContext, key: String = "", outputMap: @escaping (Output) -> Action) where Action: WorkflowActionCore, Action.WorkflowType == Parent { rendered(in: context, key: key, outputMap: outputMap) } } -extension AnyWorkflowConvertible where Rendering == Void, Output: WorkflowAction { +extension AnyWorkflowConvertible where Rendering == Void, Output: WorkflowActionCore { public func running(in context: RenderContext, key: String = "") where Output.WorkflowType == Parent { rendered(in: context, key: key) } diff --git a/Workflow/Sources/RenderContext.swift b/Workflow/Sources/RenderContext.swift index 9c6b1fda7..e3f7e5457 100644 --- a/Workflow/Sources/RenderContext.swift +++ b/Workflow/Sources/RenderContext.swift @@ -63,7 +63,7 @@ public class RenderContext: RenderContextType { /// - Parameter key: A string that uniquely identifies this child. /// /// - Returns: The `Rendering` result of the child's `render` method. - func render(workflow: Child, key: String, outputMap: @escaping (Child.Output) -> Action) -> Child.Rendering where Child: Workflow, Action: WorkflowAction, WorkflowType == Action.WorkflowType { + func render(workflow: Child, key: String, outputMap: @escaping (Child.Output) -> Action) -> Child.Rendering where Child: Workflow, Action: WorkflowActionCore, WorkflowType == Action.WorkflowType { fatalError() } @@ -77,7 +77,7 @@ public class RenderContext: RenderContextType { /// /// - Parameter actionType: The type of Action this Sink may process /// - Returns: A Sink capable of relaying `Action` instances to the Workflow runtime - public func makeSink(of actionType: Action.Type) -> Sink where Action: WorkflowAction, Action.WorkflowType == WorkflowType { + public func makeSink(of actionType: Action.Type) -> Sink where Action: WorkflowActionCore, Action.WorkflowType == WorkflowType { fatalError() } @@ -118,12 +118,12 @@ public class RenderContext: RenderContextType { super.init() } - override func render(workflow: Child, key: String, outputMap: @escaping (Child.Output) -> Action) -> Child.Rendering where WorkflowType == Action.WorkflowType, Child: Workflow, Action: WorkflowAction { + override func render(workflow: Child, key: String, outputMap: @escaping (Child.Output) -> Action) -> Child.Rendering where WorkflowType == Action.WorkflowType, Child: Workflow, Action: WorkflowActionCore { assertStillValid() return implementation.render(workflow: workflow, key: key, outputMap: outputMap) } - override func makeSink(of actionType: Action.Type) -> Sink where WorkflowType == Action.WorkflowType, Action: WorkflowAction { + override func makeSink(of actionType: Action.Type) -> Sink where WorkflowType == Action.WorkflowType, Action: WorkflowActionCore { assertStillValid() return implementation.makeSink(of: actionType) } @@ -142,9 +142,9 @@ public class RenderContext: RenderContextType { internal protocol RenderContextType: AnyObject { associatedtype WorkflowType: Workflow - func render(workflow: Child, key: String, outputMap: @escaping (Child.Output) -> Action) -> Child.Rendering where Child: Workflow, Action: WorkflowAction, Action.WorkflowType == WorkflowType + func render(workflow: Child, key: String, outputMap: @escaping (Child.Output) -> Action) -> Child.Rendering where Child: Workflow, Action: WorkflowActionCore, Action.WorkflowType == WorkflowType - func makeSink(of actionType: Action.Type) -> Sink where Action: WorkflowAction, Action.WorkflowType == WorkflowType + func makeSink(of actionType: Action.Type) -> Sink where Action: WorkflowActionCore, Action.WorkflowType == WorkflowType func runSideEffect(key: AnyHashable, action: (_ lifetime: Lifetime) -> Void) } diff --git a/Workflow/Sources/Sink.swift b/Workflow/Sources/Sink.swift index 573478345..c4dcabfcd 100644 --- a/Workflow/Sources/Sink.swift +++ b/Workflow/Sources/Sink.swift @@ -14,7 +14,7 @@ * limitations under the License. */ -/// Sink is a type that receives incoming values (commonly events or `WorkflowAction`) +/// Sink is a type that receives incoming values (commonly events or `WorkflowActionCore`) /// /// Use `RenderContext.makeSink` to create instances. public struct Sink { diff --git a/Workflow/Sources/SubtreeManager.swift b/Workflow/Sources/SubtreeManager.swift index ca469a95f..12f1b0d36 100644 --- a/Workflow/Sources/SubtreeManager.swift +++ b/Workflow/Sources/SubtreeManager.swift @@ -128,7 +128,7 @@ extension WorkflowNode { extension WorkflowNode.SubtreeManager { enum Output { - case update(any WorkflowAction, source: WorkflowUpdateDebugInfo.Source) + case update(any WorkflowActionCore, source: WorkflowUpdateDebugInfo.Source) case childDidUpdate(WorkflowUpdateDebugInfo) } } @@ -178,7 +178,7 @@ extension WorkflowNode.SubtreeManager { outputMap: @escaping (Child.Output) -> Action ) -> Child.Rendering where Child: Workflow, - Action: WorkflowAction, + Action: WorkflowActionCore, WorkflowType == Action.WorkflowType { /// A unique key used to identify this child workflow let childKey = ChildKey(childType: Child.self, key: key) @@ -227,7 +227,7 @@ extension WorkflowNode.SubtreeManager { return child.render() } - func makeSink(of actionType: Action.Type) -> Sink where Action: WorkflowAction, WorkflowType == Action.WorkflowType { + func makeSink(of actionType: Action.Type) -> Sink where Action: WorkflowActionCore, WorkflowType == Action.WorkflowType { let reusableSink = sinkStore.findOrCreate(actionType: Action.self) let sink = Sink { [weak reusableSink] action in @@ -270,7 +270,7 @@ extension WorkflowNode.SubtreeManager { self.usedSinks = [:] } - mutating func findOrCreate(actionType: Action.Type) -> ReusableSink { + mutating func findOrCreate(actionType: Action.Type) -> ReusableSink { let key = ObjectIdentifier(actionType) let reusableSink: ReusableSink @@ -302,7 +302,7 @@ extension WorkflowNode.SubtreeManager { } } - fileprivate final class ReusableSink: AnyReusableSink where Action.WorkflowType == WorkflowType { + fileprivate final class ReusableSink: AnyReusableSink where Action.WorkflowType == WorkflowType { func handle(action: Action) { let output = Output.update(action, source: .external) @@ -445,11 +445,11 @@ extension WorkflowNode.SubtreeManager { fileprivate final class ChildWorkflow: AnyChildWorkflow { private let node: WorkflowNode - private var outputMap: (W.Output) -> any WorkflowAction + private var outputMap: (W.Output) -> any WorkflowActionCore init( workflow: W, - outputMap: @escaping (W.Output) -> any WorkflowAction, + outputMap: @escaping (W.Output) -> any WorkflowActionCore, eventPipe: EventPipe, key: String, parentSession: WorkflowSession?, @@ -480,7 +480,7 @@ extension WorkflowNode.SubtreeManager { func update( workflow: W, - outputMap: @escaping (W.Output) -> any WorkflowAction, + outputMap: @escaping (W.Output) -> any WorkflowActionCore, eventPipe: EventPipe ) { self.outputMap = outputMap diff --git a/Workflow/Sources/WorkflowAction.swift b/Workflow/Sources/WorkflowAction.swift index 260eb2f92..a2514ce3c 100644 --- a/Workflow/Sources/WorkflowAction.swift +++ b/Workflow/Sources/WorkflowAction.swift @@ -14,12 +14,18 @@ * limitations under the License. */ -/// Conforming types represent an action that advances a workflow. When applied, an action emits the next -/// state and / or output for the workflow. -public protocol WorkflowAction { +// TODO: document this +public protocol WorkflowActionCore { /// The type of workflow that this action can be applied to. associatedtype WorkflowType: Workflow + // TODO: document this + func apply(toState state: inout WorkflowType.State, workflow: WorkflowType) -> WorkflowType.Output? +} + +/// Conforming types represent an action that advances a workflow. When applied, an action emits the next +/// state and / or output for the workflow. +public protocol WorkflowAction: WorkflowActionCore { /// Applies this action to a given state of the workflow, optionally returning an output event. /// /// - Parameter state: The current state of the workflow. The state is passed as an `inout` param, allowing actions @@ -30,11 +36,17 @@ public protocol WorkflowAction { func apply(toState state: inout WorkflowType.State) -> WorkflowType.Output? } +public extension WorkflowActionCore where Self: WorkflowAction { + func apply(toState state: inout WorkflowType.State, workflow: WorkflowType) -> WorkflowType.Output? { + apply(toState: &state) + } +} + /// A type-erased workflow action. /// /// The `AnyWorkflowAction` type forwards `apply` to an underlying workflow action, hiding its specific underlying type. -public struct AnyWorkflowAction: WorkflowAction { - private let _apply: (inout WorkflowType.State) -> WorkflowType.Output? +public struct AnyWorkflowAction: WorkflowActionCore { + private let _apply: (inout WorkflowType.State, WorkflowType) -> WorkflowType.Output? /// The underlying type-erased `WorkflowAction` public let base: Any @@ -45,12 +57,12 @@ public struct AnyWorkflowAction: WorkflowAction { /// Creates a type-erased workflow action that wraps the given instance. /// /// - Parameter base: A workflow action to wrap. - public init(_ base: E) where E: WorkflowAction, E.WorkflowType == WorkflowType { + public init(_ base: E) where E: WorkflowActionCore, E.WorkflowType == WorkflowType { if let anyEvent = base as? AnyWorkflowAction { self = anyEvent return } - self._apply = { return base.apply(toState: &$0) } + self._apply = base.apply self.base = base self.isClosureBased = false } @@ -62,6 +74,21 @@ public struct AnyWorkflowAction: WorkflowAction { _ apply: @escaping (inout WorkflowType.State) -> WorkflowType.Output?, fileID: StaticString = #fileID, line: UInt = #line + ) { + self.init( + { state, _ in apply(&state) }, + fileID: fileID, + line: line + ) + } + + /// Creates a type-erased workflow action with the given `apply` implementation. + /// + /// - Parameter apply: the apply function for the resulting action. + public init( + _ apply: @escaping (inout WorkflowType.State, WorkflowType) -> WorkflowType.Output?, + fileID: StaticString = #fileID, + line: UInt = #line ) { let closureAction = ClosureAction( _apply: apply, @@ -74,13 +101,13 @@ public struct AnyWorkflowAction: WorkflowAction { /// Private initializer forwarded to via `init(_ apply:...)` /// - Parameter closureAction: The `ClosureAction` wrapping the underlying `apply` closure. fileprivate init(closureAction: ClosureAction) { - self._apply = closureAction.apply(toState:) + self._apply = closureAction.apply(toState:workflow:) self.base = closureAction self.isClosureBased = true } - public func apply(toState state: inout WorkflowType.State) -> WorkflowType.Output? { - return _apply(&state) + public func apply(toState state: inout WorkflowType.State, workflow: WorkflowType) -> WorkflowType.Output? { + return _apply(&state, workflow) } } @@ -108,13 +135,13 @@ extension AnyWorkflowAction { /// A `WorkflowAction` that wraps an `apply(...)` implementation defined by a closure. /// Mainly used to provide more useful debugging/telemetry information for `AnyWorkflow` instances /// defined via a closure. -struct ClosureAction: WorkflowAction { - private let _apply: (inout WorkflowType.State) -> WorkflowType.Output? +struct ClosureAction: WorkflowActionCore { + private let _apply: (inout WorkflowType.State, WorkflowType) -> WorkflowType.Output? let fileID: StaticString let line: UInt init( - _apply: @escaping (inout WorkflowType.State) -> WorkflowType.Output?, + _apply: @escaping (inout WorkflowType.State, WorkflowType) -> WorkflowType.Output?, fileID: StaticString, line: UInt ) { @@ -123,8 +150,8 @@ struct ClosureAction: WorkflowAction { self.line = line } - func apply(toState state: inout WorkflowType.State) -> WorkflowType.Output? { - _apply(&state) + func apply(toState state: inout WorkflowType.State, workflow: WorkflowType) -> WorkflowType.Output? { + _apply(&state, workflow) } } diff --git a/Workflow/Sources/WorkflowLogger.swift b/Workflow/Sources/WorkflowLogger.swift index d68a5eb17..13c49c52e 100644 --- a/Workflow/Sources/WorkflowLogger.swift +++ b/Workflow/Sources/WorkflowLogger.swift @@ -113,7 +113,7 @@ final class WorkflowLogger { os_signpost(.end, log: .active, name: "Alive", signpostID: signpostID) } - static func logSinkEvent(ref: AnyObject, action: Action) { + static func logSinkEvent(ref: AnyObject, action: Action) { guard WorkflowLogging.config.logActions else { return } let signpostID = OSSignpostID(log: .active, object: ref) diff --git a/Workflow/Sources/WorkflowNode.swift b/Workflow/Sources/WorkflowNode.swift index 36d47f551..94cda76dd 100644 --- a/Workflow/Sources/WorkflowNode.swift +++ b/Workflow/Sources/WorkflowNode.swift @@ -80,7 +80,7 @@ final class WorkflowNode { switch subtreeOutput { case .update(let action, let source): - /// 'Opens' the existential `any WorkflowAction` value + /// 'Opens' the existential `any WorkflowActionCore` value /// allowing the underlying conformance to be applied to the Workflow's State let outputEvent = openAndApply( action, @@ -178,12 +178,12 @@ extension WorkflowNode { } private extension WorkflowNode { - /// Applies an appropriate `WorkflowAction` to advance the underlying Workflow `State` + /// Applies an appropriate `WorkflowActionCore` to advance the underlying Workflow `State` /// - Parameters: - /// - action: The `WorkflowAction` to apply + /// - action: The `WorkflowActionCore` to apply /// - isExternal: Whether the handled action came from the 'outside world' vs being bubbled up from a child node /// - Returns: An optional `Output` produced by the action application - func openAndApply( + func openAndApply( _ action: A, isExternal: Bool ) -> WorkflowType.Output? where A.WorkflowType == WorkflowType { @@ -208,7 +208,7 @@ private extension WorkflowNode { defer { observerCompletion?(state, output) } /// Apply the action to the current state - output = action.apply(toState: &state) + output = action.apply(toState: &state, workflow: workflow) return output } diff --git a/Workflow/Sources/WorkflowObserver.swift b/Workflow/Sources/WorkflowObserver.swift index 2cf7f0385..a2c75d5c1 100644 --- a/Workflow/Sources/WorkflowObserver.swift +++ b/Workflow/Sources/WorkflowObserver.swift @@ -69,24 +69,24 @@ public protocol WorkflowObserver { session: WorkflowSession ) - /// Called after a `WorkflowAction` is received, but **before** it has been handled and propagated up the tree. + /// Called after a `WorkflowActionCore` is received, but **before** it has been handled and propagated up the tree. /// - Parameters: /// - action: The action that was received. /// - session: The `WorkflowSession` corresponding to the backing `WorkflowNode`. - func workflowDidReceiveAction( + func workflowDidReceiveAction( _ action: Action, workflow: Action.WorkflowType, session: WorkflowSession ) - /// Called when a `WorkflowAction` will be applied to its corresponding Workflow's State + /// Called when a `WorkflowActionCore` will be applied to its corresponding Workflow's State /// - Parameters: /// - action: The action that will be applied. /// - workflow: The action's corresponding `Workflow`. /// - state: The state to which the action will be applied. /// - session: The `WorkflowSession` corresponding to the backing `WorkflowNode`. /// - Returns: An optional closure to be called immediately after the action is applied to the `State`, and an optional `Output` has been produced. The closure takes the updated state and optional output as its arguments. - func workflowWillApplyAction( + func workflowWillApplyAction( _ action: Action, workflow: Action.WorkflowType, state: Action.WorkflowType.State, @@ -193,13 +193,13 @@ public extension WorkflowObserver { session: WorkflowSession ) {} - func workflowDidReceiveAction( + func workflowDidReceiveAction( _ action: Action, workflow: Action.WorkflowType, session: WorkflowSession ) {} - func workflowWillApplyAction( + func workflowWillApplyAction( _ action: Action, workflow: Action.WorkflowType, state: Action.WorkflowType.State, @@ -280,7 +280,7 @@ final class ChainedWorkflowObserver: WorkflowObserver { _ action: Action, workflow: Action.WorkflowType, session: WorkflowSession - ) where Action: WorkflowAction { + ) where Action: WorkflowActionCore { for observer in observers { observer.workflowDidReceiveAction( action, @@ -295,7 +295,7 @@ final class ChainedWorkflowObserver: WorkflowObserver { workflow: Action.WorkflowType, state: Action.WorkflowType.State, session: WorkflowSession - ) -> ((Action.WorkflowType.State, Action.WorkflowType.Output?) -> Void)? where Action: WorkflowAction { + ) -> ((Action.WorkflowType.State, Action.WorkflowType.Output?) -> Void)? where Action: WorkflowActionCore { let callbacks = observers.compactMap { $0.workflowWillApplyAction( action, diff --git a/Workflow/Tests/AnyWorkflowActionTests.swift b/Workflow/Tests/AnyWorkflowActionTests.swift index 5e3ab968c..e1d0d604e 100644 --- a/Workflow/Tests/AnyWorkflowActionTests.swift +++ b/Workflow/Tests/AnyWorkflowActionTests.swift @@ -83,7 +83,7 @@ final class AnyWorkflowActionTests: XCTestCase { XCTAssertEqual(log, []) var state: Void = () - _ = erased.apply(toState: &state) + _ = erased.apply(toState: &state, workflow: ExampleWorkflow()) XCTAssertEqual(log, ["action invoked"]) } diff --git a/Workflow/Tests/WorkflowObserverTests.swift b/Workflow/Tests/WorkflowObserverTests.swift index 3bd620e84..d9fd43ccc 100644 --- a/Workflow/Tests/WorkflowObserverTests.swift +++ b/Workflow/Tests/WorkflowObserverTests.swift @@ -647,11 +647,11 @@ private final class TestObserver: WorkflowObserver { onDidChange?(oldWorkflow, newWorkflow, state, session) } - func workflowDidReceiveAction(_ action: Action, workflow: Action.WorkflowType, session: WorkflowSession) where Action: WorkflowAction { + func workflowDidReceiveAction(_ action: Action, workflow: Action.WorkflowType, session: WorkflowSession) where Action: WorkflowActionCore { onDidReceiveAction?(action, workflow, session) } - func workflowWillApplyAction(_ action: Action, workflow: Action.WorkflowType, state: Action.WorkflowType.State, session: WorkflowSession) -> ((Action.WorkflowType.State, Action.WorkflowType.Output?) -> Void)? where Action: WorkflowAction { + func workflowWillApplyAction(_ action: Action, workflow: Action.WorkflowType, state: Action.WorkflowType.State, session: WorkflowSession) -> ((Action.WorkflowType.State, Action.WorkflowType.Output?) -> Void)? where Action: WorkflowActionCore { onApplyAction?(action, workflow, state, session) } } diff --git a/WorkflowTesting/Sources/Internal/AppliedAction.swift b/WorkflowTesting/Sources/Internal/AppliedAction.swift index 950464cbd..1cf9a1793 100644 --- a/WorkflowTesting/Sources/Internal/AppliedAction.swift +++ b/WorkflowTesting/Sources/Internal/AppliedAction.swift @@ -20,7 +20,7 @@ import XCTest struct AppliedAction { let erasedAction: Any - init(_ action: ActionType) where ActionType.WorkflowType == WorkflowType { + init(_ action: ActionType) where ActionType.WorkflowType == WorkflowType { self.erasedAction = action } diff --git a/WorkflowTesting/Sources/Internal/RenderTester+TestContext.swift b/WorkflowTesting/Sources/Internal/RenderTester+TestContext.swift index 0e86f6e8f..d14afa828 100644 --- a/WorkflowTesting/Sources/Internal/RenderTester+TestContext.swift +++ b/WorkflowTesting/Sources/Internal/RenderTester+TestContext.swift @@ -29,15 +29,18 @@ extension RenderTester { let file: StaticString let line: UInt + private let workflow: WorkflowType private var usedWorkflowKeys: Set = [] internal init( + workflow: WorkflowType, state: WorkflowType.State, expectedWorkflows: [AnyExpectedWorkflow], expectedSideEffects: [AnyHashable: ExpectedSideEffect], file: StaticString, line: UInt ) { + self.workflow = workflow self.state = state self.expectedWorkflows = expectedWorkflows self.expectedSideEffects = expectedSideEffects @@ -45,7 +48,7 @@ extension RenderTester { self.line = line } - func render(workflow: Child, key: String, outputMap: @escaping (Child.Output) -> Action) -> Child.Rendering where Child: Workflow, Action: WorkflowAction, Action.WorkflowType == WorkflowType { + func render(workflow: Child, key: String, outputMap: @escaping (Child.Output) -> Action) -> Child.Rendering where Child: Workflow, Action: WorkflowActionCore, Action.WorkflowType == WorkflowType { let matchingTypes = expectedWorkflows.compactMap { $0 as? ExpectedWorkflow } guard let expectedWorkflow = matchingTypes.first(where: { $0.key == key }) else { let sameTypeDifferentKeys = matchingTypes.map { $0.key } @@ -90,7 +93,7 @@ extension RenderTester { return expectedWorkflow.rendering } - func makeSink(of actionType: ActionType.Type) -> Sink where ActionType: WorkflowAction, ActionType.WorkflowType == WorkflowType { + func makeSink(of actionType: ActionType.Type) -> Sink where ActionType: WorkflowActionCore, ActionType.WorkflowType == WorkflowType { return Sink { action in self.apply(action: action) } @@ -116,10 +119,10 @@ extension RenderTester { } } - private func apply(action: ActionType) where ActionType: WorkflowAction, ActionType.WorkflowType == WorkflowType { + private func apply(action: ActionType) where ActionType: WorkflowActionCore, ActionType.WorkflowType == WorkflowType { XCTAssertNil(appliedAction, "Received multiple actions in a single render test", file: file, line: line) appliedAction = AppliedAction(action) - let output = action.apply(toState: &state) + let output = action.apply(toState: &state, workflow: workflow) if let output = output { XCTAssertNil(producedOutput, "Received multiple outputs in a single render test", file: file, line: line) diff --git a/WorkflowTesting/Sources/WorkflowRenderTester.swift b/WorkflowTesting/Sources/WorkflowRenderTester.swift index d4a418df0..9156e921d 100644 --- a/WorkflowTesting/Sources/WorkflowRenderTester.swift +++ b/WorkflowTesting/Sources/WorkflowRenderTester.swift @@ -261,6 +261,7 @@ public struct RenderTester { assertions: (WorkflowType.Rendering) throws -> Void ) rethrows -> RenderTesterResult { let contextImplementation = TestContext( + workflow: workflow, state: state, expectedWorkflows: expectedWorkflows, expectedSideEffects: expectedSideEffects,